[Magnifier-26] Wire up frame callback for realsies

Test: none yet
Bug: 73810478
Bug: 72041926
Change-Id: I7154ed4b3d2cd820dc8c8ff55eed130be87d1606
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 6da51d1..db19681 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -1008,10 +1008,8 @@
             final long vsync = AnimationUtils.currentAnimationTimeMillis() * 1000000L;
             mFrameInfo.setVsync(vsync, vsync);
             mFrameInfo.addFlags(1 << 2 /* VSYNC */);
-            // TODO: remove this fence
-            nFence(mNativeProxy);
             if (callback != null) {
-                callback.onFrameDraw(mSurface.getNextFrameNumber());
+                nSetFrameCallback(mNativeProxy, callback);
             }
             nSyncAndDrawFrame(mNativeProxy, mFrameInfo.mFrameInfo, mFrameInfo.mFrameInfo.length);
         }
@@ -1184,6 +1182,7 @@
     private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
     private static native void nSetContentDrawBounds(long nativeProxy, int left,
              int top, int right, int bottom);
+    private static native void nSetFrameCallback(long nativeProxy, FrameDrawingCallback callback);
 
     private static native long nAddFrameMetricsObserver(long nativeProxy, FrameMetricsObserver observer);
     private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 6427965..68ce3d9 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -471,12 +471,12 @@
          * Destroys this instance.
          */
         public void destroy() {
-            mRenderer.destroy();
-            mSurface.destroy();
-            mSurfaceControl.destroy();
-            mSurfaceSession.kill();
-            mBitmapRenderNode.destroy();
             synchronized (mLock) {
+                mRenderer.destroy();
+                mSurface.destroy();
+                mSurfaceControl.destroy();
+                mSurfaceSession.kill();
+                mBitmapRenderNode.destroy();
                 mHandler.removeCallbacks(mMagnifierUpdater);
                 if (mBitmap != null) {
                     mBitmap.recycle();
@@ -518,17 +518,22 @@
                     final int pendingY = mWindowPositionY;
 
                     callback = frame -> {
-                        mRenderer.setLightCenter(mDisplay, pendingX, pendingY);
-                        // Show or move the window at the content draw frame.
-                        SurfaceControl.openTransaction();
-                        mSurfaceControl.deferTransactionUntil(mSurface, frame);
-                        if (updateWindowPosition) {
-                            mSurfaceControl.setPosition(pendingX, pendingY);
+                        synchronized (mLock) {
+                            if (!mSurface.isValid()) {
+                                return;
+                            }
+                            mRenderer.setLightCenter(mDisplay, pendingX, pendingY);
+                            // Show or move the window at the content draw frame.
+                            SurfaceControl.openTransaction();
+                            mSurfaceControl.deferTransactionUntil(mSurface, frame);
+                            if (updateWindowPosition) {
+                                mSurfaceControl.setPosition(pendingX, pendingY);
+                            }
+                            if (firstDraw) {
+                                mSurfaceControl.show();
+                            }
+                            SurfaceControl.closeTransaction();
                         }
-                        if (firstDraw) {
-                            mSurfaceControl.show();
-                        }
-                        SurfaceControl.closeTransaction();
                     };
                 } else {
                     callback = null;
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 9f3475a..13e0e4a 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -68,6 +68,10 @@
     jmethodID callback;
 } gFrameMetricsObserverClassInfo;
 
+struct {
+    jmethodID onFrameDraw;
+} gFrameDrawingCallback;
+
 static JNIEnv* getenv(JavaVM* vm) {
     JNIEnv* env;
     if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
@@ -849,6 +853,44 @@
     proxy->setContentDrawBounds(left, top, right, bottom);
 }
 
+class JGlobalRefHolder {
+public:
+    JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {}
+
+    virtual ~JGlobalRefHolder() {
+        getenv(mVm)->DeleteGlobalRef(mObject);
+        mObject = nullptr;
+    }
+
+    jobject object() { return mObject; }
+    JavaVM* vm() { return mVm; }
+
+private:
+    JGlobalRefHolder(const JGlobalRefHolder&) = delete;
+    void operator=(const JGlobalRefHolder&) = delete;
+
+    JavaVM* mVm;
+    jobject mObject;
+};
+
+static void android_view_ThreadedRenderer_setFrameCallback(JNIEnv* env,
+        jobject clazz, jlong proxyPtr, jobject frameCallback) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    if (!frameCallback) {
+        proxy->setFrameCallback(nullptr);
+    } else {
+        JavaVM* vm = nullptr;
+        LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&vm) != JNI_OK, "Unable to get Java VM");
+        auto globalCallbackRef = std::make_shared<JGlobalRefHolder>(vm,
+                env->NewGlobalRef(frameCallback));
+        proxy->setFrameCallback([globalCallbackRef](int64_t frameNr) {
+            JNIEnv* env = getenv(globalCallbackRef->vm());
+            env->CallVoidMethod(globalCallbackRef->object(), gFrameDrawingCallback.onFrameDraw,
+                    static_cast<jlong>(frameNr));
+        });
+    }
+}
+
 static jint android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
         jobject clazz, jobject jsurface, jint left, jint top,
         jint right, jint bottom, jobject jbitmap) {
@@ -1034,6 +1076,8 @@
     { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
     { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
     { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
+    { "nSetFrameCallback", "(JLandroid/view/ThreadedRenderer$FrameDrawingCallback;)V",
+            (void*)android_view_ThreadedRenderer_setFrameCallback},
     { "nAddFrameMetricsObserver",
             "(JLandroid/view/FrameMetricsObserver;)J",
             (void*)android_view_ThreadedRenderer_addFrameMetricsObserver },
@@ -1078,6 +1122,11 @@
     gFrameMetricsObserverClassInfo.timingDataBuffer = GetFieldIDOrDie(
             env, metricsClass, "mTimingData", "[J");
 
+    jclass frameCallbackClass = FindClassOrDie(env,
+            "android/view/ThreadedRenderer$FrameDrawingCallback");
+    gFrameDrawingCallback.onFrameDraw = GetMethodIDOrDie(env, frameCallbackClass,
+            "onFrameDraw", "(J)V");
+
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }