content: /*
   * Copyright (C) 2006 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.os;
  
  import android.annotation.NonNull;
  import android.annotation.Nullable;
  import android.annotation.UnsupportedAppUsage;
  import android.util.Log;
  import android.util.Printer;
  
  import java.lang.reflect.Modifier;
  
  /**
   * A Handler allows you to send and process {@link Message} and Runnable
   * objects associated with a thread's {@link MessageQueue}.  Each Handler
   * instance is associated with a single thread and that thread's message
   * queue.  When you create a new Handler, it is bound to the thread /
   * message queue of the thread that is creating it -- from that point on,
   * it will deliver messages and runnables to that message queue and execute
   * them as they come out of the message queue.
   * 
   * <p>There are two main uses for a Handler: (1) to schedule messages and
   * runnables to be executed at some point in the future; and (2) to enqueue
   * an action to be performed on a different thread than your own.
   * 
   * <p>Scheduling messages is accomplished with the
   * {@link #post}, {@link #postAtTime(Runnable, long)},
   * {@link #postDelayed}, {@link #sendEmptyMessage},
   * {@link #sendMessage}, {@link #sendMessageAtTime}, and
   * {@link #sendMessageDelayed} methods.  The <em>post</em> versions allow
   * you to enqueue Runnable objects to be called by the message queue when
   * they are received; the <em>sendMessage</em> versions allow you to enqueue
   * a {@link Message} object containing a bundle of data that will be
   * processed by the Handler's {@link #handleMessage} method (requiring that
   * you implement a subclass of Handler).
   * 
   * <p>When posting or sending to a Handler, you can either
   * allow the item to be processed as soon as the message queue is ready
   * to do so, or specify a delay before it gets processed or absolute time for
   * it to be processed.  The latter two allow you to implement timeouts,
   * ticks, and other timing-based behavior.
   * 
   * <p>When a
   * process is created for your application, its main thread is dedicated to
   * running a message queue that takes care of managing the top-level
   * application objects (activities, broadcast receivers, etc) and any windows
   * they create.  You can create your own threads, and communicate back with
   * the main application thread through a Handler.  This is done by calling
   * the same <em>post</em> or <em>sendMessage</em> methods as before, but from
   * your new thread.  The given Runnable or Message will then be scheduled
   * in the Handler's message queue and processed when appropriate.
   */
  public class Handler {
      /*
       * Set this flag to true to detect anonymous, local or member classes
       * that extend this Handler class and that are not static. These kind
       * of classes can potentially create leaks.
       */
      private static final boolean FIND_POTENTIAL_LEAKS = false;
      private static final String TAG = "Handler";
      private static Handler MAIN_THREAD_HANDLER = null;
  
      /**
       * Callback interface you can use when instantiating a Handler to avoid
       * having to implement your own subclass of Handler.
       */
      public interface Callback {
          /**
           * @param msg A {@link android.os.Message Message} object
           * @return True if no further handling is desired
           */
          boolean handleMessage(@NonNull Message msg);
      }
      
      /**
       * Subclasses must implement this to receive messages.
       */
      public void handleMessage(@NonNull Message msg) {
      }
      
      /**
       * Handle system messages here.
       */
      public void dispatchMessage(@NonNull Message msg) {
          if (msg.callback != null) {
              handleCallback(msg);
          } else {
              if (mCallback != null) {
                  if (mCallback.handleMessage(msg)) {
                      return;
                  }
              }
              handleMessage(msg);
          }
      }
  
      /**
       * Default constructor associates this handler with the {@link Looper} for the
       * current thread.
       *
       * If this thread does not have a looper, this handler won't be able to receive messages
       * so an exception is thrown.
       */
      public Handler() {
          this(null, false);
      }
  
      /**
       * Constructor associates this handler with the {@link Looper} for the
       * current thread and takes a callback interface in which you can handle
       * messages.
       *
       * If this thread does not have a looper, this handler won't be able to receive messages
       * so an exception is thrown.
       *
       * @param callback The callback interface in which to handle messages, or null.
       */
      public Handler(@Nullable Callback callback) {
          this(callback, false);
      }
  
      /**
       * Use the provided {@link Looper} instead of the default one.
       *
       * @param looper The looper, must not be null.
       */
      public Handler(@NonNull Looper looper) {
          this(looper, null, false);
      }
  
      /**
       * Use the provided {@link Looper} instead of the default one and take a callback
       * interface in which to handle messages.
       *
       * @param looper The looper, must not be null.
       * @param callback The callback interface in which to handle messages, or null.
       */
      public Handler(@NonNull Looper looper, @Nullable Callback callback) {
          this(looper, callback, false);
      }
  
      /**
       * Use the {@link Looper} for the current thread
       * and set whether the handler should be asynchronous.
       *
       * Handlers are synchronous by default unless this constructor is used to make
       * one that is strictly asynchronous.
       *
       * Asynchronous messages represent interrupts or events that do not require global ordering
       * with respect to synchronous messages.  Asynchronous messages are not subject to
       * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
       *
       * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
       * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
       *
       * @hide
       */
      @UnsupportedAppUsage
      public Handler(boolean async) {
          this(null, async);
      }
  
      /**
       * Use the {@link Looper} for the current thread with the specified callback interface
       * and set whether the handler should be asynchronous.
       *
       * Handlers are synchronous by default unless this constructor is used to make
       * one that is strictly asynchronous.
       *
       * Asynchronous messages represent interrupts or events that do not require global ordering
       * with respect to synchronous messages.  Asynchronous messages are not subject to
       * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
       *
       * @param callback The callback interface in which to handle messages, or null.
       * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
       * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
       *
       * @hide
       */
      public Handler(@Nullable Callback callback, boolean async) {
          if (FIND_POTENTIAL_LEAKS) {
              final Class<? extends Handler> klass = getClass();
              if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                      (klass.getModifiers() & Modifier.STATIC) == 0) {
                  Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                      klass.getCanonicalName());
              }
          }
  
          mLooper = Looper.myLooper();
          if (mLooper == null) {
              throw new RuntimeException(
                  "Can't create handler inside thread " + Thread.currentThread()
                          + " that has not called Looper.prepare()");
          }
          mQueue = mLooper.mQueue;
          mCallback = callback;
          mAsynchronous = async;
      }
  
      /**
       * Use the provided {@link Looper} instead of the default one and take a callback
       * interface in which to handle messages.  Also set whether the handler
       * should be asynchronous.
       *
       * Handlers are synchronous by default unless this constructor is used to make
       * one that is strictly asynchronous.
       *
       * Asynchronous messages represent interrupts or events that do not require global ordering
       * with respect to synchronous messages.  Asynchronous messages are not subject to
       * the synchronization barriers introduced by conditions such as display vsync.
       *
       * @param looper The looper, must not be null.
       * @param callback The callback interface in which to handle messages, or null.
       * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
       * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
       *
       * @hide
       */
      @UnsupportedAppUsage
      public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
          mLooper = looper;
          mQueue = looper.mQueue;
          mCallback = callback;
          mAsynchronous = async;
      }
  
      /**
       * Create a new Handler whose posted messages and runnables are not subject to
       * synchronization barriers such as display vsync.
       *
       * <p>Messages sent to an async handler are guaranteed to be ordered with respect to one another,
       * but not necessarily with respect to messages from other Handlers.</p>
       *
       * @see #createAsync(Looper, Callback) to create an async Handler with custom message handling.
       *
       * @param looper the Looper that the new Handler should be bound to
       * @return a new async Handler instance
       */
      @NonNull
      public static Handler createAsync(@NonNull Looper looper) {
          if (looper == null) throw new NullPointerException("looper must not be null");
          return new Handler(looper, null, true);
      }
  
      /**
       * Create a new Handler whose posted messages and runnables are not subject to
       * synchronization barriers such as display vsync.
       *
       * <p>Messages sent to an async handler are guaranteed to be ordered with respect to one another,
       * but not necessarily with respect to messages from other Handlers.</p>
       *
       * @see #createAsync(Looper) to create an async Handler without custom message handling.
       *
       * @param looper the Looper that the new Handler should be bound to
       * @return a new async Handler instance
       */
      @NonNull
      public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
          if (looper == null) throw new NullPointerException("looper must not be null");
          if (callback == null) throw new NullPointerException("callback must not be null");
          return new Handler(looper, callback, true);
      }
  
      /** @hide */
      @UnsupportedAppUsage
      @NonNull
      public static Handler getMain() {
          if (MAIN_THREAD_HANDLER == null) {
              MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
          }
          return MAIN_THREAD_HANDLER;
      }
  
      /** @hide */
      @NonNull
      public static Handler mainIfNull(@Nullable Handler handler) {
          return handler == null ? getMain() : handler;
      }
  
      /** {@hide} */
      @NonNull
      public String getTraceName(@NonNull Message message) {
          final StringBuilder sb = new StringBuilder();
          sb.append(getClass().getName()).append(": ");
          if (message.callback != null) {
              sb.append(message.callback.getClass().getName());
          } else {
              sb.append("#").append(message.what);
          }
          return sb.toString();
      }
  
      /**
       * Returns a string representing the name of the specified message.
       * The default implementation will either return the class name of the
       * message callback if any, or the hexadecimal representation of the
       * message "what" field.
       *  
       * @param message The message whose name is being queried 
       */
      @NonNull
      public String getMessageName(@NonNull Message message) {
          if (message.callback != null) {
              return message.callback.getClass().getName();
          }
          return "0x" + Integer.toHexString(message.what);
      }
  
      /**
       * Returns a new {@link android.os.Message Message} from the global message pool. More efficient than
       * creating and allocating new instances. The retrieved message has its handler set to this instance (Message.target == this).
       *  If you don't want that facility, just call Message.obtain() instead.
       */
      @NonNull
      public final Message obtainMessage()
      {
          return Message.obtain(this);
      }
  
      /**
       * Same as {@link #obtainMessage()}, except that it also sets the what member of the returned Message.
       * 
       * @param what Value to assign to the returned Message.what field.
       * @return A Message from the global message pool.
       */
      @NonNull
      public final Message obtainMessage(int what)
      {
          return Message.obtain(this, what);
      }
      
      /**
       * 
       * Same as {@link #obtainMessage()}, except that it also sets the what and obj members 
       * of the returned Message.
       * 
       * @param what Value to assign to the returned Message.what field.
       * @param obj Value to assign to the returned Message.obj field.
       * @return A Message from the global message pool.
       */
      @NonNull
      public final Message obtainMessage(int what, @Nullable Object obj) {
          return Message.obtain(this, what, obj);
      }
  
      /**
       * 
       * Same as {@link #obtainMessage()}, except that it also sets the what, arg1 and arg2 members of the returned
       * Message.
       * @param what Value to assign to the returned Message.what field.
       * @param arg1 Value to assign to the returned Message.arg1 field.
       * @param arg2 Value to assign to the returned Message.arg2 field.
       * @return A Message from the global message pool.
       */
      @NonNull
      public final Message obtainMessage(int what, int arg1, int arg2)
      {
          return Message.obtain(this, what, arg1, arg2);
      }
      
      /**
       * 
       * Same as {@link #obtainMessage()}, except that it also sets the what, obj, arg1,and arg2 values on the 
       * returned Message.
       * @param what Value to assign to the returned Message.what field.
       * @param arg1 Value to assign to the returned Message.arg1 field.
       * @param arg2 Value to assign to the returned Message.arg2 field.
       * @param obj Value to assign to the returned Message.obj field.
       * @return A Message from the global message pool.
       */
      @NonNull
      public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
          return Message.obtain(this, what, arg1, arg2, obj);
      }
  
      /**
       * Causes the Runnable r to be added to the message queue.
       * The runnable will be run on the thread to which this handler is 
       * attached. 
       *  
       * @param r The Runnable that will be executed.
       * 
       * @return Returns true if the Runnable was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.
       */
      public final boolean post(@NonNull Runnable r) {
         return  sendMessageDelayed(getPostMessage(r), 0);
      }
      
      /**
       * Causes the Runnable r to be added to the message queue, to be run
       * at a specific time given by <var>uptimeMillis</var>.
       * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
       * Time spent in deep sleep will add an additional delay to execution.
       * The runnable will be run on the thread to which this handler is attached.
       *
       * @param r The Runnable that will be executed.
       * @param uptimeMillis The absolute time at which the callback should run,
       *         using the {@link android.os.SystemClock#uptimeMillis} time-base.
       *  
       * @return Returns true if the Runnable was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.  Note that a
       *         result of true does not mean the Runnable will be processed -- if
       *         the looper is quit before the delivery time of the message
       *         occurs then the message will be dropped.
       */
      public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
          return sendMessageAtTime(getPostMessage(r), uptimeMillis);
      }
      
      /**
       * Causes the Runnable r to be added to the message queue, to be run
       * at a specific time given by <var>uptimeMillis</var>.
       * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
       * Time spent in deep sleep will add an additional delay to execution.
       * The runnable will be run on the thread to which this handler is attached.
       *
       * @param r The Runnable that will be executed.
       * @param token An instance which can be used to cancel {@code r} via
       *         {@link #removeCallbacksAndMessages}.
       * @param uptimeMillis The absolute time at which the callback should run,
       *         using the {@link android.os.SystemClock#uptimeMillis} time-base.
       * 
       * @return Returns true if the Runnable was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.  Note that a
       *         result of true does not mean the Runnable will be processed -- if
       *         the looper is quit before the delivery time of the message
       *         occurs then the message will be dropped.
       *         
       * @see android.os.SystemClock#uptimeMillis
       */
      public final boolean postAtTime(
              @NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
          return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
      }
      
      /**
       * Causes the Runnable r to be added to the message queue, to be run
       * after the specified amount of time elapses.
       * The runnable will be run on the thread to which this handler
       * is attached.
       * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
       * Time spent in deep sleep will add an additional delay to execution.
       *  
       * @param r The Runnable that will be executed.
       * @param delayMillis The delay (in milliseconds) until the Runnable
       *        will be executed.
       *        
       * @return Returns true if the Runnable was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.  Note that a
       *         result of true does not mean the Runnable will be processed --
       *         if the looper is quit before the delivery time of the message
       *         occurs then the message will be dropped.
       */
      public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
          return sendMessageDelayed(getPostMessage(r), delayMillis);
      }
      
      /** @hide */
      public final boolean postDelayed(Runnable r, int what, long delayMillis) {
          return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis);
      }
  
      /**
       * Causes the Runnable r to be added to the message queue, to be run
       * after the specified amount of time elapses.
       * The runnable will be run on the thread to which this handler
       * is attached.
       * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
       * Time spent in deep sleep will add an additional delay to execution.
       *
       * @param r The Runnable that will be executed.
       * @param token An instance which can be used to cancel {@code r} via
       *         {@link #removeCallbacksAndMessages}.
       * @param delayMillis The delay (in milliseconds) until the Runnable
       *        will be executed.
       *
       * @return Returns true if the Runnable was successfully placed in to the
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.  Note that a
       *         result of true does not mean the Runnable will be processed --
       *         if the looper is quit before the delivery time of the message
       *         occurs then the message will be dropped.
       */
      public final boolean postDelayed(
              @NonNull Runnable r, @Nullable Object token, long delayMillis) {
          return sendMessageDelayed(getPostMessage(r, token), delayMillis);
      }
  
      /**
       * Posts a message to an object that implements Runnable.
       * Causes the Runnable r to executed on the next iteration through the
       * message queue. The runnable will be run on the thread to which this
       * handler is attached.
       * <b>This method is only for use in very special circumstances -- it
       * can easily starve the message queue, cause ordering problems, or have
       * other unexpected side-effects.</b>
       *  
       * @param r The Runnable that will be executed.
       * 
       * @return Returns true if the message was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.
       */
      public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
          return sendMessageAtFrontOfQueue(getPostMessage(r));
      }
  
      /**
       * Runs the specified task synchronously.
       * <p>
       * If the current thread is the same as the handler thread, then the runnable
       * runs immediately without being enqueued.  Otherwise, posts the runnable
       * to the handler and waits for it to complete before returning.
       * </p><p>
       * This method is dangerous!  Improper use can result in deadlocks.
       * Never call this method while any locks are held or use it in a
       * possibly re-entrant manner.
       * </p><p>
       * This method is occasionally useful in situations where a background thread
       * must synchronously await completion of a task that must run on the
       * handler's thread.  However, this problem is often a symptom of bad design.
       * Consider improving the design (if possible) before resorting to this method.
       * </p><p>
       * One example of where you might want to use this method is when you just
       * set up a Handler thread and need to perform some initialization steps on
       * it before continuing execution.
       * </p><p>
       * If timeout occurs then this method returns <code>false</code> but the runnable
       * will remain posted on the handler and may already be in progress or
       * complete at a later time.
       * </p><p>
       * When using this method, be sure to use {@link Looper#quitSafely} when
       * quitting the looper.  Otherwise {@link #runWithScissors} may hang indefinitely.
       * (TODO: We should fix this by making MessageQueue aware of blocking runnables.)
       * </p>
       *
       * @param r The Runnable that will be executed synchronously.
       * @param timeout The timeout in milliseconds, or 0 to wait indefinitely.
       *
       * @return Returns true if the Runnable was successfully executed.
       *         Returns false on failure, usually because the
       *         looper processing the message queue is exiting.
       *
       * @hide This method is prone to abuse and should probably not be in the API.
       * If we ever do make it part of the API, we might want to rename it to something
       * less funny like runUnsafe().
       */
      public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
          if (r == null) {
              throw new IllegalArgumentException("runnable must not be null");
          }
          if (timeout < 0) {
              throw new IllegalArgumentException("timeout must be non-negative");
          }
  
          if (Looper.myLooper() == mLooper) {
              r.run();
              return true;
          }
  
          BlockingRunnable br = new BlockingRunnable(r);
          return br.postAndWait(this, timeout);
      }
  
      /**
       * Remove any pending posts of Runnable r that are in the message queue.
       */
      public final void removeCallbacks(@NonNull Runnable r) {
          mQueue.removeMessages(this, r, null);
      }
  
      /**
       * Remove any pending posts of Runnable <var>r</var> with Object
       * <var>token</var> that are in the message queue.  If <var>token</var> is null,
       * all callbacks will be removed.
       */
      public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
          mQueue.removeMessages(this, r, token);
      }
  
      /**
       * Pushes a message onto the end of the message queue after all pending messages
       * before the current time. It will be received in {@link #handleMessage},
       * in the thread attached to this handler.
       *  
       * @return Returns true if the message was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.
       */
      public final boolean sendMessage(@NonNull Message msg) {
          return sendMessageDelayed(msg, 0);
      }
  
      /**
       * Sends a Message containing only the what value.
       *  
       * @return Returns true if the message was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.
       */
      public final boolean sendEmptyMessage(int what)
      {
          return sendEmptyMessageDelayed(what, 0);
      }
  
      /**
       * Sends a Message containing only the what value, to be delivered
       * after the specified amount of time elapses.
       * @see #sendMessageDelayed(android.os.Message, long) 
       * 
       * @return Returns true if the message was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.
       */
      public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
          Message msg = Message.obtain();
          msg.what = what;
          return sendMessageDelayed(msg, delayMillis);
      }
  
      /**
       * Sends a Message containing only the what value, to be delivered 
       * at a specific time.
       * @see #sendMessageAtTime(android.os.Message, long)
       *  
       * @return Returns true if the message was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.
       */
  
      public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
          Message msg = Message.obtain();
          msg.what = what;
          return sendMessageAtTime(msg, uptimeMillis);
      }
  
      /**
       * Enqueue a message into the message queue after all pending messages
       * before (current time + delayMillis). You will receive it in
       * {@link #handleMessage}, in the thread attached to this handler.
       *  
       * @return Returns true if the message was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.  Note that a
       *         result of true does not mean the message will be processed -- if
       *         the looper is quit before the delivery time of the message
       *         occurs then the message will be dropped.
       */
      public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
          if (delayMillis < 0) {
              delayMillis = 0;
          }
          return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
      }
  
      /**
       * Enqueue a message into the message queue after all pending messages
       * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
       * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
       * Time spent in deep sleep will add an additional delay to execution.
       * You will receive it in {@link #handleMessage}, in the thread attached
       * to this handler.
       * 
       * @param uptimeMillis The absolute time at which the message should be
       *         delivered, using the
       *         {@link android.os.SystemClock#uptimeMillis} time-base.
       *         
       * @return Returns true if the message was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.  Note that a
       *         result of true does not mean the message will be processed -- if
       *         the looper is quit before the delivery time of the message
       *         occurs then the message will be dropped.
       */
      public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
          MessageQueue queue = mQueue;
          if (queue == null) {
              RuntimeException e = new RuntimeException(
                      this + " sendMessageAtTime() called with no mQueue");
              Log.w("Looper", e.getMessage(), e);
              return false;
          }
          return enqueueMessage(queue, msg, uptimeMillis);
      }
  
      /**
       * Enqueue a message at the front of the message queue, to be processed on
       * the next iteration of the message loop.  You will receive it in
       * {@link #handleMessage}, in the thread attached to this handler.
       * <b>This method is only for use in very special circumstances -- it
       * can easily starve the message queue, cause ordering problems, or have
       * other unexpected side-effects.</b>
       *  
       * @return Returns true if the message was successfully placed in to the 
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.
       */
      public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
          MessageQueue queue = mQueue;
          if (queue == null) {
              RuntimeException e = new RuntimeException(
                  this + " sendMessageAtTime() called with no mQueue");
              Log.w("Looper", e.getMessage(), e);
              return false;
          }
          return enqueueMessage(queue, msg, 0);
      }
  
      /**
       * Executes the message synchronously if called on the same thread this handler corresponds to,
       * or {@link #sendMessage pushes it to the queue} otherwise
       *
       * @return Returns true if the message was successfully ran or placed in to the
       *         message queue.  Returns false on failure, usually because the
       *         looper processing the message queue is exiting.
       * @hide
       */
      public final boolean executeOrSendMessage(@NonNull Message msg) {
          if (mLooper == Looper.myLooper()) {
              dispatchMessage(msg);
              return true;
          }
          return sendMessage(msg);
      }
  
      private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
              long uptimeMillis) {
          msg.target = this;
          msg.workSourceUid = ThreadLocalWorkSource.getUid();
  
          if (mAsynchronous) {
              msg.setAsynchronous(true);
          }
          return queue.enqueueMessage(msg, uptimeMillis);
      }
  
      /**
       * Remove any pending posts of messages with code 'what' that are in the
       * message queue.
       */
      public final void removeMessages(int what) {
          mQueue.removeMessages(this, what, null);
      }
  
      /**
       * Remove any pending posts of messages with code 'what' and whose obj is
       * 'object' that are in the message queue.  If <var>object</var> is null,
       * all messages will be removed.
       */
      public final void removeMessages(int what, @Nullable Object object) {
          mQueue.removeMessages(this, what, object);
      }
  
      /**
       * Remove any pending posts of callbacks and sent messages whose
       * <var>obj</var> is <var>token</var>.  If <var>token</var> is null,
       * all callbacks and messages will be removed.
       */
      public final void removeCallbacksAndMessages(@Nullable Object token) {
          mQueue.removeCallbacksAndMessages(this, token);
      }
  
      /**
       * Check if there are any pending posts of messages with code 'what' in
       * the message queue.
       */
      public final boolean hasMessages(int what) {
          return mQueue.hasMessages(this, what, null);
      }
  
      /**
       * Return whether there are any messages or callbacks currently scheduled on this handler.
       * @hide
       */
      public final boolean hasMessagesOrCallbacks() {
          return mQueue.hasMessages(this);
      }
  
      /**
       * Check if there are any pending posts of messages with code 'what' and
       * whose obj is 'object' in the message queue.
       */
      public final boolean hasMessages(int what, @Nullable Object object) {
          return mQueue.hasMessages(this, what, object);
      }
  
      /**
       * Check if there are any pending posts of messages with callback r in
       * the message queue.
       */
      public final boolean hasCallbacks(@NonNull Runnable r) {
          return mQueue.hasMessages(this, r, null);
      }
  
      // if we can get rid of this method, the handler need not remember its loop
      // we could instead export a getMessageQueue() method... 
      @NonNull
      public final Looper getLooper() {
          return mLooper;
      }
  
      public final void dump(@NonNull Printer pw, @NonNull String prefix) {
          pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
          if (mLooper == null) {
              pw.println(prefix + "looper uninitialized");
          } else {
              mLooper.dump(pw, prefix + "  ");
          }
      }
  
      /**
       * @hide
       */
      public final void dumpMine(@NonNull Printer pw, @NonNull String prefix) {
          pw.println(prefix + this + " @ " + SystemClock.uptimeMillis());
          if (mLooper == null) {
              pw.println(prefix + "looper uninitialized");
          } else {
              mLooper.dump(pw, prefix + "  ", this);
          }
      }
  
      @Override
      public String toString() {
          return "Handler (" + getClass().getName() + ") {"
          + Integer.toHexString(System.identityHashCode(this))
          + "}";
      }
  
      @UnsupportedAppUsage
      final IMessenger getIMessenger() {
          synchronized (mQueue) {
              if (mMessenger != null) {
                  return mMessenger;
              }
              mMessenger = new MessengerImpl();
              return mMessenger;
          }
      }
  
      private final class MessengerImpl extends IMessenger.Stub {
          public void send(Message msg) {
              msg.sendingUid = Binder.getCallingUid();
              Handler.this.sendMessage(msg);
          }
      }
  
      private static Message getPostMessage(Runnable r) {
          Message m = Message.obtain();
          m.callback = r;
          return m;
      }
  
      @UnsupportedAppUsage
      private static Message getPostMessage(Runnable r, Object token) {
          Message m = Message.obtain();
          m.obj = token;
          m.callback = r;
          return m;
      }
  
      private static void handleCallback(Message message) {
          message.callback.run();
      }
  
      @UnsupportedAppUsage
      final Looper mLooper;
      final MessageQueue mQueue;
      @UnsupportedAppUsage
      final Callback mCallback;
      final boolean mAsynchronous;
      @UnsupportedAppUsage
      IMessenger mMessenger;
  
      private static final class BlockingRunnable implements Runnable {
          private final Runnable mTask;
          private boolean mDone;
  
          public BlockingRunnable(Runnable task) {
              mTask = task;
          }
  
          @Override
          public void run() {
              try {
                  mTask.run();
              } finally {
                  synchronized (this) {
                      mDone = true;
                      notifyAll();
                  }
              }
          }
  
          public boolean postAndWait(Handler handler, long timeout) {
              if (!handler.post(this)) {
                  return false;
              }
  
              synchronized (this) {
                  if (timeout > 0) {
                      final long expirationTime = SystemClock.uptimeMillis() + timeout;
                      while (!mDone) {
                          long delay = expirationTime - SystemClock.uptimeMillis();
                          if (delay <= 0) {
                              return false; // timeout
                          }
                          try {
                              wait(delay);
                          } catch (InterruptedException ex) {
                          }
                      }
                  } else {
                      while (!mDone) {
                          try {
                              wait();
                          } catch (InterruptedException ex) {
                          }
                      }
                  }
              }
              return true;
          }
      }
  }
  