Rename Looper::isIdling() to isPolling() to resolve confusion.

The loop isn't technically idle at this time, it's just checking
whether any file descriptors have pending events.  However it's
still a good signal as to whether the loop is alive.

Added a real isIdle() function.

Bug: 19532373
Change-Id: Idd273e8774f469ccafb00d560818cf279dfd6ba6
diff --git a/api/current.txt b/api/current.txt
index c43307e..0060c41 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22369,6 +22369,7 @@
 
   public final class MessageQueue {
     method public void addIdleHandler(android.os.MessageQueue.IdleHandler);
+    method public boolean isIdle();
     method public void removeIdleHandler(android.os.MessageQueue.IdleHandler);
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 6acea9e..c2072bc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -23964,6 +23964,7 @@
 
   public final class MessageQueue {
     method public void addIdleHandler(android.os.MessageQueue.IdleHandler);
+    method public boolean isIdle();
     method public void removeIdleHandler(android.os.MessageQueue.IdleHandler);
   }
 
diff --git a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java b/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
index 0699ffb..e19ebf2 100644
--- a/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
+++ b/core/java/android/hardware/camera2/legacy/RequestHandlerThread.java
@@ -96,15 +96,15 @@
     // Blocks until thread is idling
     public void waitUntilIdle() {
         Handler handler = waitAndGetHandler();
-        Looper looper = handler.getLooper();
-        if (looper.isIdling()) {
+        MessageQueue queue = handler.getLooper().getQueue();
+        if (queue.isIdle()) {
             return;
         }
         mIdle.close();
-        looper.getQueue().addIdleHandler(mIdleHandler);
+        queue.addIdleHandler(mIdleHandler);
         // Ensure that the idle handler gets run even if the looper already went idle
         handler.sendEmptyMessage(MSG_POKE_IDLE_HANDLER);
-        if (looper.isIdling()) {
+        if (queue.isIdle()) {
             return;
         }
         mIdle.block();
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 6d7c9cf..8b99196 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -50,6 +50,16 @@
   *  }</pre>
   */
 public final class Looper {
+    /*
+     * API Implementation Note:
+     *
+     * This class contains the code required to set up and manage an event loop
+     * based on MessageQueue.  APIs that affect the state of the queue should be
+     * defined on MessageQueue or Handler rather than on Looper itself.  For example,
+     * idle handlers and sync barriers are defined on the queue whereas preparing the
+     * thread, looping and quitting are defined on the looper.
+     */
+
     private static final String TAG = "Looper";
 
     // sThreadLocal.get() will return null unless you've called prepare().
@@ -286,16 +296,6 @@
         return mQueue;
     }
 
-    /**
-     * Return whether this looper's thread is currently idle, waiting for new work
-     * to do.  This is intrinsically racy, since its state can change before you get
-     * the result back.
-     * @hide
-     */
-    public boolean isIdling() {
-        return mQueue.isIdling();
-    }
-
     public void dump(Printer pw, String prefix) {
         pw.println(prefix + toString());
         mQueue.dump(pw, prefix + "  ");
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 01a23ce..f4d609c 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -52,54 +52,7 @@
     private native static void nativeDestroy(long ptr);
     private native static void nativePollOnce(long ptr, int timeoutMillis);
     private native static void nativeWake(long ptr);
-    private native static boolean nativeIsIdling(long ptr);
-
-    /**
-     * Callback interface for discovering when a thread is going to block
-     * waiting for more messages.
-     */
-    public static interface IdleHandler {
-        /**
-         * Called when the message queue has run out of messages and will now
-         * wait for more.  Return true to keep your idle handler active, false
-         * to have it removed.  This may be called if there are still messages
-         * pending in the queue, but they are all scheduled to be dispatched
-         * after the current time.
-         */
-        boolean queueIdle();
-    }
-
-    /**
-     * Add a new {@link IdleHandler} to this message queue.  This may be
-     * removed automatically for you by returning false from
-     * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
-     * invoked, or explicitly removing it with {@link #removeIdleHandler}.
-     * 
-     * <p>This method is safe to call from any thread.
-     * 
-     * @param handler The IdleHandler to be added.
-     */
-    public void addIdleHandler(IdleHandler handler) {
-        if (handler == null) {
-            throw new NullPointerException("Can't add a null IdleHandler");
-        }
-        synchronized (this) {
-            mIdleHandlers.add(handler);
-        }
-    }
-
-    /**
-     * Remove an {@link IdleHandler} from the queue that was previously added
-     * with {@link #addIdleHandler}.  If the given object is not currently
-     * in the idle list, nothing is done.
-     * 
-     * @param handler The IdleHandler to be removed.
-     */
-    public void removeIdleHandler(IdleHandler handler) {
-        synchronized (this) {
-            mIdleHandlers.remove(handler);
-        }
-    }
+    private native static boolean nativeIsPolling(long ptr);
 
     MessageQueue(boolean quitAllowed) {
         mQuitAllowed = quitAllowed;
@@ -124,6 +77,77 @@
         }
     }
 
+    /**
+     * Returns true if the looper has no pending messages which are due to be processed.
+     *
+     * <p>This method is safe to call from any thread.
+     *
+     * @return True if the looper is idle.
+     */
+    public boolean isIdle() {
+        synchronized (this) {
+            final long now = SystemClock.uptimeMillis();
+            return mMessages == null || now < mMessages.when;
+        }
+    }
+
+    /**
+     * Add a new {@link IdleHandler} to this message queue.  This may be
+     * removed automatically for you by returning false from
+     * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
+     * invoked, or explicitly removing it with {@link #removeIdleHandler}.
+     *
+     * <p>This method is safe to call from any thread.
+     *
+     * @param handler The IdleHandler to be added.
+     */
+    public void addIdleHandler(IdleHandler handler) {
+        if (handler == null) {
+            throw new NullPointerException("Can't add a null IdleHandler");
+        }
+        synchronized (this) {
+            mIdleHandlers.add(handler);
+        }
+    }
+
+    /**
+     * Remove an {@link IdleHandler} from the queue that was previously added
+     * with {@link #addIdleHandler}.  If the given object is not currently
+     * in the idle list, nothing is done.
+     *
+     * <p>This method is safe to call from any thread.
+     *
+     * @param handler The IdleHandler to be removed.
+     */
+    public void removeIdleHandler(IdleHandler handler) {
+        synchronized (this) {
+            mIdleHandlers.remove(handler);
+        }
+    }
+
+    /**
+     * Returns whether this looper's thread is currently polling for more work to do.
+     * This is a good signal that the loop is still alive rather than being stuck
+     * handling a callback.  Note that this method is intrinsically racy, since the
+     * state of the loop can change before you get the result back.
+     *
+     * <p>This method is safe to call from any thread.
+     *
+     * @return True if the looper is currently polling for events.
+     * @hide
+     */
+    public boolean isPolling() {
+        synchronized (this) {
+            return isPollingLocked();
+        }
+    }
+
+    private boolean isPollingLocked() {
+        // If the loop is quitting then it must not be idling.
+        // We can assume mPtr != 0 when mQuitting is false.
+        return !mQuitting && nativeIsPolling(mPtr);
+    }
+
     Message next() {
         // Return here if the message loop has already quit and been disposed.
         // This can happen if the application tries to restart a looper after quit
@@ -400,18 +424,6 @@
         }
     }
 
-    boolean isIdling() {
-        synchronized (this) {
-            return isIdlingLocked();
-        }
-    }
-
-    private boolean isIdlingLocked() {
-        // If the loop is quitting then it must not be idling.
-        // We can assume mPtr != 0 when mQuitting is false.
-        return !mQuitting && nativeIsIdling(mPtr);
-     }
-
     void removeMessages(Handler h, int what, Object object) {
         if (h == null) {
             return;
@@ -559,8 +571,23 @@
                 pw.println(prefix + "Message " + n + ": " + msg.toString(now));
                 n++;
             }
-            pw.println(prefix + "(Total messages: " + n + ", idling=" + isIdlingLocked()
+            pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
                     + ", quitting=" + mQuitting + ")");
         }
     }
+
+    /**
+     * Callback interface for discovering when a thread is going to block
+     * waiting for more messages.
+     */
+    public static interface IdleHandler {
+        /**
+         * Called when the message queue has run out of messages and will now
+         * wait for more.  Return true to keep your idle handler active, false
+         * to have it removed.  This may be called if there are still messages
+         * pending in the queue, but they are all scheduled to be dispatched
+         * after the current time.
+         */
+        boolean queueIdle();
+    }
 }
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index 5d7877b..ee64044 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -143,9 +143,9 @@
     return nativeMessageQueue->wake();
 }
 
-static jboolean android_os_MessageQueue_nativeIsIdling(JNIEnv* env, jclass clazz, jlong ptr) {
+static jboolean android_os_MessageQueue_nativeIsPolling(JNIEnv* env, jclass clazz, jlong ptr) {
     NativeMessageQueue* nativeMessageQueue = reinterpret_cast<NativeMessageQueue*>(ptr);
-    return nativeMessageQueue->getLooper()->isIdling();
+    return nativeMessageQueue->getLooper()->isPolling();
 }
 
 // ----------------------------------------------------------------------------
@@ -156,7 +156,7 @@
     { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
     { "nativePollOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce },
     { "nativeWake", "(J)V", (void*)android_os_MessageQueue_nativeWake },
-    { "nativeIsIdling", "(J)Z", (void*)android_os_MessageQueue_nativeIsIdling }
+    { "nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling }
 };
 
 int register_android_os_MessageQueue(JNIEnv* env) {
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 8e46c4d..794e1b0 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -106,8 +106,8 @@
         }
 
         public void scheduleCheckLocked() {
-            if (mMonitors.size() == 0 && mHandler.getLooper().isIdling()) {
-                // If the target looper is or just recently was idling, then
+            if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {
+                // If the target looper has recently been polling, then
                 // there is no reason to enqueue our checker on it since that
                 // is as good as it not being deadlocked.  This avoid having
                 // to do a context switch to check the thread.  Note that we