Merge "Extend process observer to be usable for media routing." into jb-dev
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index f986d15..cba488e 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -457,9 +457,11 @@
      * @param functor The native functor to insert in the execution queue.
      *
      * @see HardwareCanvas#callDrawGLFunction(int)
-     * @see #detachFunctor(int) 
+     * @see #detachFunctor(int)
+     *
+     * @return true if the functor was attached successfully
      */
-    abstract void attachFunctor(View.AttachInfo attachInfo, int functor);
+    abstract boolean attachFunctor(View.AttachInfo attachInfo, int functor);
 
     /**
      * Initializes the hardware renderer for the specified surface and setup the
@@ -1227,11 +1229,13 @@
         }
 
         @Override
-        void attachFunctor(View.AttachInfo attachInfo, int functor) {
+        boolean attachFunctor(View.AttachInfo attachInfo, int functor) {
             if (mCanvas != null) {
                 mCanvas.attachFunctor(functor);
                 scheduleFunctors(attachInfo);
+                return true;
             }
+            return false;
         }
 
         /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 551b6cc..3138692 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -670,10 +670,11 @@
         }
     }
 
-    public void attachFunctor(int functor) {
+    public boolean attachFunctor(int functor) {
         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
-            mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
+            return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
         }
+        return false;
     }
 
     public void detachFunctor(int functor) {
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 65fd59a..d1da53b 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -7827,15 +7827,18 @@
         mSendScrollEvent = true;
 
         int functor = 0;
+        boolean forceInval = isPictureAfterFirstLayout;
         ViewRootImpl viewRoot = mWebView.getViewRootImpl();
         if (mWebView.isHardwareAccelerated() && viewRoot != null) {
             functor = nativeGetDrawGLFunction(mNativeClass);
             if (functor != 0) {
-                viewRoot.attachFunctor(functor);
+                // force an invalidate if functor attach not successful
+                forceInval |= !viewRoot.attachFunctor(functor);
             }
         }
 
         if (functor == 0
+                || forceInval
                 || mWebView.getLayerType() != View.LAYER_TYPE_NONE) {
             // invalidate the screen so that the next repaint will show new content
             // TODO: partial invalidate
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index d80bfb3..89058a7 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -42,12 +42,13 @@
 } gDisplayEventReceiverClassInfo;
 
 
-class NativeDisplayEventReceiver : public RefBase {
+class NativeDisplayEventReceiver : public LooperCallback {
 public:
     NativeDisplayEventReceiver(JNIEnv* env,
             jobject receiverObj, const sp<MessageQueue>& messageQueue);
 
     status_t initialize();
+    void dispose();
     status_t scheduleVsync();
 
 protected:
@@ -59,7 +60,7 @@
     DisplayEventReceiver mReceiver;
     bool mWaitingForVsync;
 
-    static int handleReceiveCallback(int receiveFd, int events, void* data);
+    virtual int handleEvent(int receiveFd, int events, void* data);
     bool readLastVsyncMessage(nsecs_t* outTimestamp, uint32_t* outCount);
 };
 
@@ -72,12 +73,6 @@
 }
 
 NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
-    ALOGV("receiver %p ~ Disposing display event receiver.", this);
-
-    if (!mReceiver.initCheck()) {
-        mMessageQueue->getLooper()->removeFd(mReceiver.getFd());
-    }
-
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->DeleteGlobalRef(mReceiverObjGlobal);
 }
@@ -90,13 +85,21 @@
     }
 
     int rc = mMessageQueue->getLooper()->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
-            handleReceiveCallback, this);
+            this, NULL);
     if (rc < 0) {
         return UNKNOWN_ERROR;
     }
     return OK;
 }
 
+void NativeDisplayEventReceiver::dispose() {
+    ALOGV("receiver %p ~ Disposing display event receiver.", this);
+
+    if (!mReceiver.initCheck()) {
+        mMessageQueue->getLooper()->removeFd(mReceiver.getFd());
+    }
+}
+
 status_t NativeDisplayEventReceiver::scheduleVsync() {
     if (!mWaitingForVsync) {
         ALOGV("receiver %p ~ Scheduling vsync.", this);
@@ -117,9 +120,7 @@
     return OK;
 }
 
-int NativeDisplayEventReceiver::handleReceiveCallback(int receiveFd, int events, void* data) {
-    sp<NativeDisplayEventReceiver> r = static_cast<NativeDisplayEventReceiver*>(data);
-
+int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* data) {
     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
         ALOGE("Display event receiver pipe was closed or an error occurred.  "
                 "events=0x%x", events);
@@ -135,23 +136,23 @@
     // Drain all pending events, keep the last vsync.
     nsecs_t vsyncTimestamp;
     uint32_t vsyncCount;
-    if (!r->readLastVsyncMessage(&vsyncTimestamp, &vsyncCount)) {
-        ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", data);
+    if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncCount)) {
+        ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this);
         return 1; // keep the callback, did not obtain a vsync pulse
     }
 
     ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d",
-            data, vsyncTimestamp, vsyncCount);
-    r->mWaitingForVsync = false;
+            this, vsyncTimestamp, vsyncCount);
+    mWaitingForVsync = false;
 
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
-    ALOGV("receiver %p ~ Invoking vsync handler.", data);
-    env->CallVoidMethod(r->mReceiverObjGlobal,
+    ALOGV("receiver %p ~ Invoking vsync handler.", this);
+    env->CallVoidMethod(mReceiverObjGlobal,
             gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
-    ALOGV("receiver %p ~ Returned from vsync handler.", data);
+    ALOGV("receiver %p ~ Returned from vsync handler.", this);
 
-    r->mMessageQueue->raiseAndClearException(env, "dispatchVsync");
+    mMessageQueue->raiseAndClearException(env, "dispatchVsync");
     return 1; // keep the callback
 }
 
@@ -201,6 +202,7 @@
 static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) {
     sp<NativeDisplayEventReceiver> receiver =
             reinterpret_cast<NativeDisplayEventReceiver*>(receiverPtr);
+    receiver->dispose();
     receiver->decStrong(gDisplayEventReceiverClassInfo.clazz); // drop reference held by the object
 }
 
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 08e08b9..9501cf2 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -44,13 +44,14 @@
 } gInputEventReceiverClassInfo;
 
 
-class NativeInputEventReceiver : public RefBase {
+class NativeInputEventReceiver : public LooperCallback {
 public:
     NativeInputEventReceiver(JNIEnv* env,
             jobject receiverObj, const sp<InputChannel>& inputChannel,
             const sp<MessageQueue>& messageQueue);
 
     status_t initialize();
+    void dispose();
     status_t finishInputEvent(uint32_t seq, bool handled);
     status_t consumeEvents(JNIEnv* env, bool consumeBatches, nsecs_t frameTime);
 
@@ -68,7 +69,7 @@
         return mInputConsumer.getChannel()->getName().string();
     }
 
-    static int handleReceiveCallback(int receiveFd, int events, void* data);
+    virtual int handleEvent(int receiveFd, int events, void* data);
 };
 
 
@@ -84,23 +85,24 @@
 }
 
 NativeInputEventReceiver::~NativeInputEventReceiver() {
-#if DEBUG_DISPATCH_CYCLE
-    ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
-#endif
-
-    mMessageQueue->getLooper()->removeFd(mInputConsumer.getChannel()->getFd());
-
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     env->DeleteGlobalRef(mReceiverObjGlobal);
 }
 
 status_t NativeInputEventReceiver::initialize() {
     int receiveFd = mInputConsumer.getChannel()->getFd();
-    mMessageQueue->getLooper()->addFd(
-            receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
+    mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL);
     return OK;
 }
 
+void NativeInputEventReceiver::dispose() {
+#if DEBUG_DISPATCH_CYCLE
+    ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
+#endif
+
+    mMessageQueue->getLooper()->removeFd(mInputConsumer.getChannel()->getFd());
+}
+
 status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
@@ -114,24 +116,22 @@
     return status;
 }
 
-int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, void* data) {
-    sp<NativeInputEventReceiver> r = static_cast<NativeInputEventReceiver*>(data);
-
+int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
     if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
         ALOGE("channel '%s' ~ Publisher closed input channel or an error occurred.  "
-                "events=0x%x", r->getInputChannelName(), events);
+                "events=0x%x", getInputChannelName(), events);
         return 0; // remove the callback
     }
 
     if (!(events & ALOOPER_EVENT_INPUT)) {
         ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
-                "events=0x%x", r->getInputChannelName(), events);
+                "events=0x%x", getInputChannelName(), events);
         return 1;
     }
 
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    status_t status = r->consumeEvents(env, false /*consumeBatches*/, -1);
-    r->mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
+    status_t status = consumeEvents(env, false /*consumeBatches*/, -1);
+    mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
     return status == OK || status == NO_MEMORY ? 1 : 0;
 }
 
@@ -256,6 +256,7 @@
 static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) {
     sp<NativeInputEventReceiver> receiver =
             reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+    receiver->dispose();
     receiver->decStrong(gInputEventReceiverClassInfo.clazz); // drop reference held by the object
 }