Bug 1330257 - 2. Separate out session focused state from active state; r=droeh
☠☠ backed out by 3aca6b42ca4e ☠ ☠
authorJim Chen <nchen@mozilla.com>
Mon, 20 Aug 2018 22:28:20 -0400
changeset 487621 aa0ef9b0e96a0d943e6272156408cbd30bf5883c
parent 487620 7186e64192f742776dc089d62a27a078c97c860a
child 487622 9085b9fd557c5cb371a7f8be9ad65fc78c377282
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdroeh
bugs1330257
milestone63.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 1330257 - 2. Separate out session focused state from active state; r=droeh Make a distinction between a session being active (i.e. being visible) and it being focused. More than one session may be active at a time, but only one session is focused at a time. This means the focused session is always active, but an active session may not be focused. Also, manage setting of active/focused states in GeckoView itself, so consumers don't generally have to worry about these states. Differential Revision: https://phabricator.services.mozilla.com/D3251
mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java
mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
mobile/android/modules/geckoview/GeckoViewContent.jsm
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
@@ -146,28 +146,16 @@ public class CustomTabsActivity extends 
             finish();
         }
 
         sendTelemetry();
         recordCustomTabUsage(getReferrerHost());
     }
 
     @Override
-    public void onResume() {
-        mGeckoSession.setActive(true);
-        super.onResume();
-    }
-
-    @Override
-    public void onPause() {
-        mGeckoSession.setActive(false);
-        super.onPause();
-    }
-
-    @Override
     public void onDestroy() {
         mGeckoSession.close();
         mTextSelection.destroy();
         mFormAssistPopup.destroy();
         mDoorHangerPopup.destroy();
         mPromptService.destroy();
 
         super.onDestroy();
--- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
@@ -192,28 +192,16 @@ public class WebAppActivity extends AppC
         if (android.os.Build.VERSION.SDK_INT >= 21) {
             finishAndRemoveTask();
         } else {
             finish();
         }
     }
 
     @Override
-    public void onResume() {
-        mGeckoSession.setActive(true);
-        super.onResume();
-    }
-
-    @Override
-    public void onPause() {
-        mGeckoSession.setActive(false);
-        super.onPause();
-    }
-
-    @Override
     public void onDestroy() {
         mGeckoSession.close();
         mTextSelection.destroy();
         mFormAssistPopup.destroy();
         mDoorHangerPopup.destroy();
         mPromptService.destroy();
         super.onDestroy();
     }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -1292,28 +1292,47 @@ public class GeckoSession extends LayerS
     public SessionFinder getFinder() {
         if (mFinder == null) {
             mFinder = new SessionFinder(getEventDispatcher());
         }
         return mFinder;
     }
 
     /**
-    * Set this GeckoSession as active or inactive. Setting a GeckoSession to inactive will
-    * significantly reduce its memory footprint, but should only be done if the
-    * GeckoSession is not currently visible.
-    * @param active A boolean determining whether the GeckoSession is active
-    */
+     * Set this GeckoSession as active or inactive, which represents if the session is currently
+     * visible or not. Setting a GeckoSession to inactive will significantly reduce its memory
+     * footprint, but should only be done if the GeckoSession is not currently visible. Note that
+     * a session can be active (i.e. visible) but not focused.
+     *
+     * @param active A boolean determining whether the GeckoSession is active.
+     *
+     * @see #setFocused
+     */
     public void setActive(boolean active) {
-        final GeckoBundle msg = new GeckoBundle();
+        final GeckoBundle msg = new GeckoBundle(1);
         msg.putBoolean("active", active);
         mEventDispatcher.dispatch("GeckoView:SetActive", msg);
     }
 
     /**
+     * Move focus to this session or away from this session. Only one session has focus at
+     * a given time. Note that a session can be unfocused but still active (i.e. visible).
+     *
+     * @param focused True if the session should gain focus or
+     *                false if the session should lose focus.
+     *
+     * @see #setActive
+     */
+    public void setFocused(boolean focused) {
+        final GeckoBundle msg = new GeckoBundle(1);
+        msg.putBoolean("focused", focused);
+        mEventDispatcher.dispatch("GeckoView:SetFocused", msg);
+    }
+
+    /**
      * Class representing a saved session state.
      */
     public static class SessionState implements Parcelable {
         private String mState;
 
         /**
          * Construct a SessionState from a String.
          *
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoView.java
@@ -103,21 +103,23 @@ public class GeckoView extends FrameLayo
 
             // Tell display there is already a surface.
             onGlobalLayout();
             if (GeckoView.this.mSurfaceView != null) {
                 final SurfaceHolder holder = GeckoView.this.mSurfaceView.getHolder();
                 final Rect frame = holder.getSurfaceFrame();
                 mDisplay.surfaceChanged(holder.getSurface(), frame.right, frame.bottom);
             }
+            GeckoView.this.setActive(true);
         }
 
         public GeckoDisplay release() {
             if (mValid) {
                 mDisplay.surfaceDestroyed();
+                GeckoView.this.setActive(false);
             }
 
             final GeckoDisplay display = mDisplay;
             mDisplay = null;
             return display;
         }
 
         @Override // SurfaceHolder.Callback
@@ -125,24 +127,26 @@ public class GeckoView extends FrameLayo
         }
 
         @Override // SurfaceHolder.Callback
         public void surfaceChanged(final SurfaceHolder holder, final int format,
                                    final int width, final int height) {
             if (mDisplay != null) {
                 mDisplay.surfaceChanged(holder.getSurface(), width, height);
             }
+            GeckoView.this.setActive(true);
             mValid = true;
         }
 
         @Override // SurfaceHolder.Callback
         public void surfaceDestroyed(final SurfaceHolder holder) {
             if (mDisplay != null) {
                 mDisplay.surfaceDestroyed();
             }
+            GeckoView.this.setActive(false);
             mValid = false;
         }
 
         public void onGlobalLayout() {
             if (mDisplay == null) {
                 return;
             }
             if (GeckoView.this.mSurfaceView != null) {
@@ -198,16 +202,22 @@ public class GeckoView extends FrameLayo
      * @param color Cover color.
      */
     public void coverUntilFirstPaint(final int color) {
         if (mSurfaceView != null) {
             mSurfaceView.setBackgroundColor(color);
         }
     }
 
+    /* package */ void setActive(final boolean active) {
+        if (mSession != null) {
+            mSession.setActive(active);
+        }
+    }
+
     public GeckoSession releaseSession() {
         if (mSession == null) {
             return null;
         }
 
         // Cover the view while we are not drawing to the surface.
         coverUntilFirstPaint(Color.WHITE);
 
@@ -219,20 +229,23 @@ public class GeckoView extends FrameLayo
         if (mSession.getAccessibility().getView() == this) {
             mSession.getAccessibility().setView(null);
         }
 
         if (mSession.getTextInput().getView() == this) {
             mSession.getTextInput().setView(null);
         }
 
-        if (session.getSelectionActionDelegate() == mSelectionActionDelegate) {
+        if (mSession.getSelectionActionDelegate() == mSelectionActionDelegate) {
             mSession.setSelectionActionDelegate(null);
         }
 
+        if (isFocused()) {
+            mSession.setFocused(false);
+        }
         mSession = null;
         return session;
     }
 
     /**
      * Attach a session to this view. The session should be opened before
      * attaching.
      *
@@ -310,16 +323,20 @@ public class GeckoView extends FrameLayo
 
         if (session.getAccessibility().getView() == null) {
             session.getAccessibility().setView(this);
         }
 
         if (session.getSelectionActionDelegate() == null && mSelectionActionDelegate != null) {
             session.setSelectionActionDelegate(mSelectionActionDelegate);
         }
+
+        if (isFocused()) {
+            session.setFocused(true);
+        }
     }
 
     public GeckoSession getSession() {
         return mSession;
     }
 
     public EventDispatcher getEventDispatcher() {
         return mSession.getEventDispatcher();
@@ -411,20 +428,37 @@ public class GeckoView extends FrameLayo
             setSession(ss.session, ss.session.getRuntime());
         } else if (ss.session != null) {
             mSession.transferFrom(ss.session);
             mRuntime = mSession.getRuntime();
         }
     }
 
     @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+
+        if (mSession != null) {
+            mSession.setFocused(hasWindowFocus && isFocused());
+        }
+    }
+
+    @Override
     public void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
 
-        if (!gainFocus || mIsResettingFocus) {
+        if (mIsResettingFocus) {
+            return;
+        }
+
+        if (mSession != null) {
+            mSession.setFocused(gainFocus);
+        }
+
+        if (!gainFocus) {
             return;
         }
 
         post(new Runnable() {
             @Override
             public void run() {
                 if (!isFocused()) {
                     return;
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -189,28 +189,16 @@ public class GeckoViewActivity extends A
     }
 
     private void updateTrackingProtection(GeckoSession session) {
         session.getSettings().setBoolean(
             GeckoSessionSettings.USE_TRACKING_PROTECTION, mUseTrackingProtection);
     }
 
     @Override
-    protected void onPause() {
-        mGeckoSession.setActive(false);
-        super.onPause();
-    }
-
-    @Override
-    protected void onResume() {
-        mGeckoSession.setActive(true);
-        super.onResume();
-    }
-
-    @Override
     public void onBackPressed() {
         if (mFullScreen) {
             mGeckoSession.exitFullScreen();
             return;
         }
 
         if (mCanGoBack && mGeckoSession != null) {
             mGeckoSession.goBack();
--- a/mobile/android/modules/geckoview/GeckoViewContent.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewContent.jsm
@@ -18,16 +18,17 @@ class GeckoViewContent extends GeckoView
     this.registerListener([
         "GeckoViewContent:ExitFullScreen",
         "GeckoView:ClearMatches",
         "GeckoView:DisplayMatches",
         "GeckoView:FindInPage",
         "GeckoView:RestoreState",
         "GeckoView:SaveState",
         "GeckoView:SetActive",
+        "GeckoView:SetFocused",
         "GeckoView:ZoomToInput",
     ]);
 
     this.messageManager.addMessageListener("GeckoView:SaveStateFinish", this);
   }
 
   onEnable() {
     this.window.addEventListener("MozDOMFullscreen:Entered", this,
@@ -73,22 +74,27 @@ class GeckoViewContent extends GeckoView
         this._findInPage(aData, aCallback);
         break;
       }
       case "GeckoView:ZoomToInput":
         this.messageManager.sendAsyncMessage(aEvent);
         break;
       case "GeckoView:SetActive":
         if (aData.active) {
-          this.browser.setAttribute("primary", "true");
-          this.browser.focus();
           this.browser.docShellIsActive = true;
         } else {
+          this.browser.docShellIsActive = false;
+        }
+        break;
+      case "GeckoView:SetFocused":
+        if (aData.focused) {
+          this.browser.focus();
+          this.browser.setAttribute("primary", "true");
+        } else {
           this.browser.removeAttribute("primary");
-          this.browser.docShellIsActive = false;
           this.browser.blur();
         }
         break;
       case "GeckoView:SaveState":
         if (!this._saveStateCallbacks) {
           this._saveStateCallbacks = new Map();
           this._saveStateNextId = 0;
         }