Bug 1508457 - Add GeckoView API to get first composite callback after a compositor start. r=snorp,droeh
authorRandall Barker <rbarker@mozilla.com>
Tue, 20 Nov 2018 18:18:24 +0000
changeset 447341 a0fb2044780dd738d8fbd9b5c6ec074cf7b05a3e
parent 447340 53f688575d39c4d28c25db6c87e5892b8c0ea9b3
child 447342 b4bc0fa77a1e3f0828e7b0c53a6910820b0cdedc
push id35075
push usershindli@mozilla.com
push dateWed, 21 Nov 2018 04:04:02 +0000
treeherdermozilla-central@8540104bb0bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp, droeh
bugs1508457
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1508457 - Add GeckoView API to get first composite callback after a compositor start. r=snorp,droeh Differential Revision: https://phabricator.services.mozilla.com/D12357
mobile/android/geckoview/api.txt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
--- a/mobile/android/geckoview/api.txt
+++ b/mobile/android/geckoview/api.txt
@@ -319,16 +319,17 @@ package org.mozilla.geckoview {
     field protected org.mozilla.geckoview.GeckoSession.Window mWindow;
   }
 
   public static interface GeckoSession.ContentDelegate {
     method public void onCloseRequest(org.mozilla.geckoview.GeckoSession);
     method public void onContextMenu(org.mozilla.geckoview.GeckoSession, int, int, java.lang.String, int, java.lang.String);
     method public void onCrash(org.mozilla.geckoview.GeckoSession);
     method public void onExternalResponse(org.mozilla.geckoview.GeckoSession, org.mozilla.geckoview.GeckoSession.WebResponseInfo);
+    method public void onFirstComposite(org.mozilla.geckoview.GeckoSession);
     method public void onFocusRequest(org.mozilla.geckoview.GeckoSession);
     method public void onFullScreen(org.mozilla.geckoview.GeckoSession, boolean);
     method public void onTitleChange(org.mozilla.geckoview.GeckoSession, java.lang.String);
     field public static final int ELEMENT_TYPE_AUDIO = 3;
     field public static final int ELEMENT_TYPE_IMAGE = 1;
     field public static final int ELEMENT_TYPE_NONE = 0;
     field public static final int ELEMENT_TYPE_VIDEO = 2;
   }
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
@@ -1,17 +1,19 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 package org.mozilla.geckoview.test
 
 import android.app.assist.AssistStructure
+import android.graphics.SurfaceTexture
 import android.os.Build
 import org.mozilla.geckoview.AllowOrDeny
+import org.mozilla.geckoview.GeckoDisplay
 import org.mozilla.geckoview.GeckoResult
 import org.mozilla.geckoview.GeckoSession
 import org.mozilla.geckoview.GeckoSession.NavigationDelegate.LoadRequest
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.IgnoreCrash
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.ReuseSession
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDevToolsAPI
 import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
@@ -19,16 +21,17 @@ import org.mozilla.geckoview.test.util.C
 import org.mozilla.geckoview.test.util.UiThreadUtils
 
 import android.os.Looper
 import android.support.test.filters.MediumTest
 import android.support.test.filters.SdkSuppress
 import android.support.test.runner.AndroidJUnit4
 import android.text.InputType
 import android.util.SparseArray
+import android.view.Surface
 import android.view.View
 import android.view.ViewStructure
 import android.widget.EditText
 import org.hamcrest.Matchers.*
 import org.junit.Assume.assumeThat
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -474,9 +477,32 @@ class ContentDelegateTest : BaseSessionT
     }
 
     @WithDevToolsAPI
     @Test fun sessionExitFullscreen() {
         goFullscreen()
         mainSession.exitFullScreen()
         waitForFullscreenExit()
     }
+
+    @Test fun firstComposite() {
+        val display = mainSession.acquireDisplay()
+        val texture = SurfaceTexture(0)
+        texture.setDefaultBufferSize(100, 100)
+        val surface = Surface(texture)
+        display.surfaceChanged(surface, 100, 100)
+        mainSession.loadTestPath(HELLO_HTML_PATH)
+        sessionRule.waitUntilCalled(object : Callbacks.ContentDelegate {
+            @AssertCalled(count = 1)
+            override fun onFirstComposite(session: GeckoSession) {
+            }
+        })
+        display.surfaceDestroyed()
+        display.surfaceChanged(surface, 100, 100)
+        sessionRule.waitUntilCalled(object : Callbacks.ContentDelegate {
+            @AssertCalled(count = 1)
+            override fun onFirstComposite(session: GeckoSession) {
+            }
+        })
+        display.surfaceDestroyed()
+        mainSession.releaseDisplay(display)
+    }
 }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -2588,16 +2588,24 @@ public class GeckoSession implements Par
          * GeckoSession is now closed and unusable. You may call
          * {@link #open(GeckoRuntime)} to recover the session, but no state
          * is preserved. Most applications will want to call
          * {@link #loadUri(Uri)} or {@link #restoreState(SessionState)} at this point.
          *
          * @param session The GeckoSession that crashed.
          */
         void onCrash(GeckoSession session);
+
+        /**
+         * Notification that the first content composition has occurred.
+         * This callback is invoked for the first content composite after either
+         * a start or a restart of the compositor.
+         * @param session The GeckoSession that had a first paint event.
+         */
+        default void onFirstComposite(GeckoSession session) {}
     }
 
     public interface SelectionActionDelegate {
         @IntDef(flag = true, value = {FLAG_IS_COLLAPSED,
                                       FLAG_IS_EDITABLE})
         /* package */ @interface Flag {}
 
         /**
@@ -4110,16 +4118,20 @@ public class GeckoSession implements Par
                 });
                 break;
             }
 
             case FIRST_PAINT: {
                 if (mController != null) {
                     mController.onFirstPaint();
                 }
+                ContentDelegate delegate = mContentHandler.getDelegate();
+                if (delegate != null) {
+                    delegate.onFirstComposite(this);
+                }
                 break;
             }
 
             case LAYERS_UPDATED: {
                 if (mController != null) {
                     mController.notifyDrawCallbacks();
                 }
                 break;