content: /*
   * Copyright (C) 2007 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.database;
  
  import android.annotation.UnsupportedAppUsage;
  import android.net.Uri;
  import android.os.Handler;
  import android.os.UserHandle;
  
  /**
   * Receives call backs for changes to content.
   * Must be implemented by objects which are added to a {@link ContentObservable}.
   */
  public abstract class ContentObserver {
      private final Object mLock = new Object();
      private Transport mTransport; // guarded by mLock
  
      Handler mHandler;
  
      /**
       * Creates a content observer.
       *
       * @param handler The handler to run {@link #onChange} on, or null if none.
       */
      public ContentObserver(Handler handler) {
          mHandler = handler;
      }
  
      /**
       * Gets access to the binder transport object. Not for public consumption.
       *
       * {@hide}
       */
      public IContentObserver getContentObserver() {
          synchronized (mLock) {
              if (mTransport == null) {
                  mTransport = new Transport(this);
              }
              return mTransport;
          }
      }
  
      /**
       * Gets access to the binder transport object, and unlinks the transport object
       * from the ContentObserver. Not for public consumption.
       *
       * {@hide}
       */
      @UnsupportedAppUsage
      public IContentObserver releaseContentObserver() {
          synchronized (mLock) {
              final Transport oldTransport = mTransport;
              if (oldTransport != null) {
                  oldTransport.releaseContentObserver();
                  mTransport = null;
              }
              return oldTransport;
          }
      }
  
      /**
       * Returns true if this observer is interested receiving self-change notifications.
       *
       * Subclasses should override this method to indicate whether the observer
       * is interested in receiving notifications for changes that it made to the
       * content itself.
       *
       * @return True if self-change notifications should be delivered to the observer.
       */
      public boolean deliverSelfNotifications() {
          return false;
      }
  
      /**
       * This method is called when a content change occurs.
       * <p>
       * Subclasses should override this method to handle content changes.
       * </p>
       *
       * @param selfChange True if this is a self-change notification.
       */
      public void onChange(boolean selfChange) {
          // Do nothing.  Subclass should override.
      }
  
      /**
       * This method is called when a content change occurs.
       * Includes the changed content Uri when available.
       * <p>
       * Subclasses should override this method to handle content changes.
       * To ensure correct operation on older versions of the framework that
       * did not provide a Uri argument, applications should also implement
       * the {@link #onChange(boolean)} overload of this method whenever they
       * implement the {@link #onChange(boolean, Uri)} overload.
       * </p><p>
       * Example implementation:
       * <pre><code>
       * // Implement the onChange(boolean) method to delegate the change notification to
       * // the onChange(boolean, Uri) method to ensure correct operation on older versions
       * // of the framework that did not have the onChange(boolean, Uri) method.
       * {@literal @Override}
       * public void onChange(boolean selfChange) {
       *     onChange(selfChange, null);
       * }
       *
       * // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
       * {@literal @Override}
       * public void onChange(boolean selfChange, Uri uri) {
       *     // Handle change.
       * }
       * </code></pre>
       * </p>
       *
       * @param selfChange True if this is a self-change notification.
       * @param uri The Uri of the changed content, or null if unknown.
       */
      public void onChange(boolean selfChange, Uri uri) {
          onChange(selfChange);
      }
  
      /**
       * Dispatches a change notification to the observer. Includes the changed
       * content Uri when available and also the user whose content changed.
       *
       * @param selfChange True if this is a self-change notification.
       * @param uri The Uri of the changed content, or null if unknown.
       * @param userId The user whose content changed. Can be either a specific
       *         user or {@link UserHandle#USER_ALL}.
       *
       * @hide
       */
      public void onChange(boolean selfChange, Uri uri, int userId) {
          onChange(selfChange, uri);
      }
  
      /**
       * Dispatches a change notification to the observer.
       * <p>
       * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
       * then a call to the {@link #onChange} method is posted to the handler's message queue.
       * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
       * </p>
       *
       * @param selfChange True if this is a self-change notification.
       *
       * @deprecated Use {@link #dispatchChange(boolean, Uri)} instead.
       */
      @Deprecated
      public final void dispatchChange(boolean selfChange) {
          dispatchChange(selfChange, null);
      }
  
      /**
       * Dispatches a change notification to the observer.
       * Includes the changed content Uri when available.
       * <p>
       * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
       * then a call to the {@link #onChange} method is posted to the handler's message queue.
       * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
       * </p>
       *
       * @param selfChange True if this is a self-change notification.
       * @param uri The Uri of the changed content, or null if unknown.
       */
      public final void dispatchChange(boolean selfChange, Uri uri) {
          dispatchChange(selfChange, uri, UserHandle.getCallingUserId());
      }
  
      /**
       * Dispatches a change notification to the observer. Includes the changed
       * content Uri when available and also the user whose content changed.
       * <p>
       * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
       * then a call to the {@link #onChange} method is posted to the handler's message queue.
       * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
       * </p>
       *
       * @param selfChange True if this is a self-change notification.
       * @param uri The Uri of the changed content, or null if unknown.
       * @param userId The user whose content changed.
       */
      private void dispatchChange(boolean selfChange, Uri uri, int userId) {
          if (mHandler == null) {
              onChange(selfChange, uri, userId);
          } else {
              mHandler.post(new NotificationRunnable(selfChange, uri, userId));
          }
      }
  
  
      private final class NotificationRunnable implements Runnable {
          private final boolean mSelfChange;
          private final Uri mUri;
          private final int mUserId;
  
          public NotificationRunnable(boolean selfChange, Uri uri, int userId) {
              mSelfChange = selfChange;
              mUri = uri;
              mUserId = userId;
          }
  
          @Override
          public void run() {
              ContentObserver.this.onChange(mSelfChange, mUri, mUserId);
          }
      }
  
      private static final class Transport extends IContentObserver.Stub {
          private ContentObserver mContentObserver;
  
          public Transport(ContentObserver contentObserver) {
              mContentObserver = contentObserver;
          }
  
          @Override
          public void onChange(boolean selfChange, Uri uri, int userId) {
              ContentObserver contentObserver = mContentObserver;
              if (contentObserver != null) {
                  contentObserver.dispatchChange(selfChange, uri, userId);
              }
          }
  
          public void releaseContentObserver() {
              mContentObserver = null;
          }
      }
  }
  