Bug 1413698 - 3. Recorganize GeckoViewSettings; r=snorp
authorJim Chen <nchen@mozilla.com>
Mon, 06 Nov 2017 14:54:09 -0500
changeset 443658 8ce593cc1b2d1bd0cfc6cc158f5211e35312e963
parent 443657 2bb89a9a83080ef1bc41ebb18d28437b560cf1d8
child 443659 bff0682273b310d8604161cf551fa103ad7d1ba1
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1413698
milestone58.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 1413698 - 3. Recorganize GeckoViewSettings; r=snorp * Move the chromeUri and screenId settings to GeckoViewSettings. * Add a private data-dir setting that the debugger-socket-dir setting falls backs to. Set the data-dir setting inside `GeckoSession.openWindow`. * Add optional init-only and values properties for settings. * Use integer constants for display-mode setting. MozReview-Commit-ID: HgJg0t0oade
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSession.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoViewSettings.java
mobile/android/modules/geckoview/GeckoViewRemoteDebugger.jsm
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSession.java
@@ -338,56 +338,50 @@ public class GeckoSession implements Par
             if ("GeckoView:Prompt".equals(event)) {
                 handlePromptEvent(GeckoSession.this, message, callback);
             }
         }
     }
 
     protected Window mWindow;
     private GeckoViewSettings mSettings;
-    private String mChromeUri;
-    private int mScreenId = 0; // default to the primary screen
 
     public GeckoSession() {
         this(/* settings */ null);
     }
 
     public GeckoSession(final GeckoViewSettings settings) {
         if (settings == null) {
-            mSettings = new GeckoViewSettings(mEventDispatcher);
+            mSettings = new GeckoViewSettings(this);
         } else {
-            mSettings = new GeckoViewSettings(settings, mEventDispatcher);
+            mSettings = new GeckoViewSettings(settings, this);
         }
 
         mListener.registerListeners();
     }
 
     /* package */ void transferFrom(final GeckoSession session) {
         if (isOpen()) {
             throw new IllegalStateException("Session is open");
         }
+
         mWindow = session.mWindow;
+        mSettings = new GeckoViewSettings(session.mSettings, this);
         session.mWindow = null;
-
-        mSettings = new GeckoViewSettings(session.mSettings, getEventDispatcher());
-        mChromeUri = session.mChromeUri;
-        mScreenId = session.mScreenId;
     }
 
     @Override // Parcelable
     public int describeContents() {
         return 0;
     }
 
     @Override // Parcelable
     public void writeToParcel(Parcel out, int flags) {
         out.writeStrongInterface(mWindow);
         out.writeParcelable(mSettings, flags);
-        out.writeString(mChromeUri);
-        out.writeInt(mScreenId);
     }
 
     // AIDL code may call readFromParcel even though it's not part of Parcelable.
     public void readFromParcel(final Parcel source) {
         if (isOpen()) {
             throw new IllegalStateException("Session is open");
         }
 
@@ -397,20 +391,17 @@ public class GeckoSession implements Par
         if (window instanceof Window) {
             mWindow = (Window) window;
         } else {
             mWindow = null;
         }
 
         final GeckoViewSettings settings =
                 source.readParcelable(getClass().getClassLoader());
-        mSettings = new GeckoViewSettings(settings, getEventDispatcher());
-
-        mChromeUri = source.readString();
-        mScreenId = source.readInt();
+        mSettings = new GeckoViewSettings(settings, this);
     }
 
     public static final Creator<GeckoSession> CREATOR = new Creator<GeckoSession>() {
         @Override
         public GeckoSession createFromParcel(final Parcel in) {
             final GeckoSession session = new GeckoSession();
             session.readFromParcel(in);
             return session;
@@ -447,86 +438,54 @@ public class GeckoSession implements Par
         }
 
         final int flags = multiprocess ? GeckoThread.FLAG_PRELOAD_CHILD : 0;
         if (GeckoThread.initMainProcess(/* profile */ null, geckoArgs, flags)) {
             GeckoThread.launch();
         }
     }
 
-    /**
-     * Return the URI of the underlying chrome window opened or to be opened, or null if
-     * using the default GeckoSession URI.
-     *
-     * @return Current chrome URI or null.
-     */
-    public String getChromeUri() {
-        return mChromeUri;
-    }
-
-    /**
-     * Set the URI of the underlying chrome window to be opened, or null to use the
-     * default GeckoSession URI. Can only be called before the chrome window is opened during
-     * {@link #onAttachedToWindow}.
-     *
-     * @param uri New chrome URI or null.
-     */
-    public void setChromeUri(final String uri) {
-        if (isOpen()) {
-            throw new IllegalStateException("Session is open");
-        }
-        mChromeUri = uri;
-    }
-
-    public int getScreenId() {
-        return mScreenId;
-    }
-
-    public void setScreenId(final int id) {
-        if (isOpen()) {
-            throw new IllegalStateException("Session is open");
-        }
-        mScreenId = id;
-    }
-
     public boolean isOpen() {
         return mWindow != null;
     }
 
     public void openWindow(final Context appContext) {
         if (isOpen()) {
             throw new IllegalStateException("Session is open");
         }
 
         if (!GeckoThread.isLaunched()) {
             final boolean multiprocess =
                     mSettings.getBoolean(GeckoViewSettings.USE_MULTIPROCESS);
             preload(appContext, /* geckoArgs */ null, multiprocess);
         }
 
-        if (mSettings.getString(GeckoViewSettings.DEBUGGER_SOCKET_DIR) == null) {
-            mSettings.setString(GeckoViewSettings.DEBUGGER_SOCKET_DIR,
+        if (mSettings.getString(GeckoViewSettings.DATA_DIR) == null) {
+            mSettings.setString(GeckoViewSettings.DATA_DIR,
                                 appContext.getApplicationInfo().dataDir);
         }
 
+        final String chromeUri = mSettings.getString(GeckoViewSettings.CHROME_URI);
+        final int screenId = mSettings.getInt(GeckoViewSettings.SCREEN_ID);
+        final boolean isPrivate = mSettings.getBoolean(GeckoViewSettings.USE_PRIVATE_MODE);
+
         mWindow = new Window(mNativeQueue);
 
         if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
             Window.open(mWindow, mEventDispatcher, mSettings.asBundle(),
-                        mChromeUri, mScreenId,
-                        mSettings.getBoolean(GeckoViewSettings.USE_PRIVATE_MODE));
+                        chromeUri, screenId, isPrivate);
         } else {
             GeckoThread.queueNativeCallUntil(
                 GeckoThread.State.PROFILE_READY,
                 Window.class, "open",
                 Window.class, mWindow,
                 EventDispatcher.class, mEventDispatcher,
                 GeckoBundle.class, mSettings.asBundle(),
-                String.class, mChromeUri,
-                mScreenId, mSettings.getBoolean(GeckoViewSettings.USE_PRIVATE_MODE));
+                String.class, chromeUri,
+                screenId, isPrivate);
         }
     }
 
     public void attachView(final GeckoView view) {
         if (view == null) {
             return;
         }
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoViewSettings.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoViewSettings.java
@@ -7,160 +7,184 @@
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.util.GeckoBundle;
 
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
 
+import java.util.Arrays;
+import java.util.Collection;
+
 public final class GeckoViewSettings implements Parcelable {
     private static final String LOGTAG = "GeckoViewSettings";
     private static final boolean DEBUG = false;
 
-    private static class Key<T> {
-        private final String text;
+    // This needs to match nsIDocShell.idl
+    public static final int DISPLAY_MODE_BROWSER = 0;
+    public static final int DISPLAY_MODE_MINIMAL_UI = 1;
+    public static final int DISPLAY_MODE_STANDALONE = 2;
+    public static final int DISPLAY_MODE_FULLSCREEN = 3;
 
-        public Key(final String text) {
-            this.text = text;
+    private static class Key<T> {
+        public final String name;
+        public final boolean initOnly;
+        public final Collection<T> values;
+
+        public Key(final String name) {
+            this(name, /* initOnly */ false, /* values */ null);
+        }
+
+        public Key(final String name, final boolean initOnly, final Collection<T> values) {
+            this.name = name;
+            this.initOnly = initOnly;
+            this.values = values;
         }
     }
 
-    public enum DisplayMode {
-        // This needs to match nsIDocShell.idl
-        BROWSER(0),
-        MINIMAL_UI(1),
-        STANDALONE(2),
-        FULLSCREEN(3);
-
-        private final int mMode;
-
-        DisplayMode(int mode) {
-            mMode = mode;
-        }
-
-        public int value() {
-            return mMode;
-        }
-    }
+    /**
+     * Key to set the chrome window URI, or null to use default URI.
+     * Read-only once session is open.
+     */
+    public static final Key<String> CHROME_URI =
+        new Key<String>("chromeUri", /* initOnly */ true, /* values */ null);
+    /**
+     * Key to set the window screen ID, or 0 to use default ID.
+     * Read-only once session is open.
+     */
+    public static final Key<Integer> SCREEN_ID =
+        new Key<Integer>("screenId", /* initOnly */ true, /* values */ null);
 
     /*
-     * Key to enabled and disable tracking protection.
+     * Key to enable and disable tracking protection.
      */
     public static final Key<Boolean> USE_TRACKING_PROTECTION =
         new Key<Boolean>("useTrackingProtection");
     /*
-     * Key to enabled and disable private mode browsing.
+     * Key to enable and disable private mode browsing.
+     * Read-only once session is open.
      */
     public static final Key<Boolean> USE_PRIVATE_MODE =
-        new Key<Boolean>("usePrivateMode");
+        new Key<Boolean>("usePrivateMode", /* initOnly */ true, /* values */ null);
 
     /*
-     * Key to enabled and disable multiprocess browsing (e10s).
-     * Note: can only be set during GeckoView initialization, changes during an
-     * active GeckoView session will be ignored.
+     * Key to enable and disable multiprocess browsing (e10s).
+     * Read-only once session is open.
      */
     public static final Key<Boolean> USE_MULTIPROCESS =
-        new Key<Boolean>("useMultiprocess");
+        new Key<Boolean>("useMultiprocess", /* initOnly */ true, /* values */ null);
 
     /*
      * Key to specify which display-mode we should use
      */
     public static final Key<Integer> DISPLAY_MODE =
-        new Key<Integer>("displayMode");
+        new Key<Integer>("displayMode", /* initOnly */ false,
+                         Arrays.asList(DISPLAY_MODE_BROWSER, DISPLAY_MODE_MINIMAL_UI,
+                                       DISPLAY_MODE_STANDALONE, DISPLAY_MODE_FULLSCREEN));
 
     public static final Key<Boolean> USE_REMOTE_DEBUGGER =
         new Key<Boolean>("useRemoteDebugger");
 
     public static final Key<String> DEBUGGER_SOCKET_DIR =
         new Key<String>("debuggerSocketDir");
 
-    private final EventDispatcher mEventDispatcher;
+    /* package */ static final Key<String> DATA_DIR =
+        new Key<String>("dataDir", /* initOnly */ true, /* values */ null);
+
+    private final GeckoSession mSession;
     private final GeckoBundle mBundle;
 
     public GeckoViewSettings() {
         this(null);
     }
 
-    /* package */ GeckoViewSettings(EventDispatcher eventDispatcher) {
-        mEventDispatcher = eventDispatcher;
+    /* package */ GeckoViewSettings(final GeckoSession session) {
+        mSession = session;
         mBundle = new GeckoBundle();
 
-        setBoolean(USE_TRACKING_PROTECTION, false);
-        setBoolean(USE_PRIVATE_MODE, false);
-        setBoolean(USE_MULTIPROCESS, true);
-        setInt(DISPLAY_MODE, DisplayMode.BROWSER.value());
-        setBoolean(USE_REMOTE_DEBUGGER, false);
-        // Set in GeckoView.init().
-        setString(DEBUGGER_SOCKET_DIR, ".");
+        mBundle.putString(CHROME_URI.name, null);
+        mBundle.putInt(SCREEN_ID.name, 0);
+        mBundle.putBoolean(USE_TRACKING_PROTECTION.name, false);
+        mBundle.putBoolean(USE_PRIVATE_MODE.name, false);
+        mBundle.putBoolean(USE_MULTIPROCESS.name, true);
+        mBundle.putInt(DISPLAY_MODE.name, DISPLAY_MODE_BROWSER);
+        mBundle.putBoolean(USE_REMOTE_DEBUGGER.name, false);
+        mBundle.putString(DEBUGGER_SOCKET_DIR.name, null);
     }
 
-    /* package */ GeckoViewSettings(GeckoViewSettings settings, EventDispatcher eventDispatcher) {
+    /* package */ GeckoViewSettings(final GeckoViewSettings settings,
+                                    final GeckoSession session) {
+        mSession = session;
         mBundle = new GeckoBundle(settings.mBundle);
-        mEventDispatcher = eventDispatcher;
     }
 
-    public void setBoolean(final Key<Boolean> key, boolean value) {
+    public void setBoolean(final Key<Boolean> key, final boolean value) {
         synchronized (mBundle) {
-            final Object old = mBundle.get(key.text);
-            if (old != null && old.equals(value)) {
-                return;
+            if (valueChangedLocked(key, value)) {
+                mBundle.putBoolean(key.name, value);
+                dispatchUpdate();
             }
-            mBundle.putBoolean(key.text, value);
         }
-        dispatchUpdate();
     }
 
     public boolean getBoolean(final Key<Boolean> key) {
         synchronized (mBundle) {
-            return mBundle.getBoolean(key.text);
+            return mBundle.getBoolean(key.name);
         }
     }
 
-    public void setInt(final Key<Integer> key, int value) {
+    public void setInt(final Key<Integer> key, final int value) {
         synchronized (mBundle) {
-            final Object old = mBundle.get(key.text);
-            if (old != null && old.equals(value)) {
-                return;
+            if (valueChangedLocked(key, value)) {
+                mBundle.putInt(key.name, value);
+                dispatchUpdate();
             }
-            mBundle.putInt(key.text, value);
         }
-        dispatchUpdate();
     }
 
     public int getInt(final Key<Integer> key) {
         synchronized (mBundle) {
-            return mBundle.getInt(key.text);
+            return mBundle.getInt(key.name);
         }
     }
 
     public void setString(final Key<String> key, final String value) {
         synchronized (mBundle) {
-            final Object old = mBundle.get(key.text);
-            if (old != null && old.equals(value)) {
-                return;
+            if (valueChangedLocked(key, value)) {
+                mBundle.putString(key.name, value);
+                dispatchUpdate();
             }
-            mBundle.putString(key.text, value);
         }
-        dispatchUpdate();
     }
 
     public String getString(final Key<String> key) {
         synchronized (mBundle) {
-            return mBundle.getString(key.text);
+            return mBundle.getString(key.name);
         }
     }
 
     /* package */ GeckoBundle asBundle() {
         return mBundle;
     }
 
+    private <T> boolean valueChangedLocked(final Key<T> key, T value) {
+        if (key.initOnly && mSession != null && mSession.isOpen()) {
+            throw new IllegalStateException("Read-only property");
+        } else if (key.values != null && !key.values.contains(value)) {
+            throw new IllegalArgumentException("Invalid value");
+        }
+
+        final Object old = mBundle.get(key.name);
+        return (old != value) && (old == null || !old.equals(value));
+    }
+
     private void dispatchUpdate() {
-        if (mEventDispatcher != null) {
-            mEventDispatcher.dispatch("GeckoView:UpdateSettings", null);
+        if (mSession != null) {
+            mSession.getEventDispatcher().dispatch("GeckoView:UpdateSettings", null);
         }
     }
 
     @Override // Parcelable
     public int describeContents() {
         return 0;
     }
 
--- a/mobile/android/modules/geckoview/GeckoViewRemoteDebugger.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewRemoteDebugger.jsm
@@ -51,17 +51,17 @@ class GeckoViewRemoteDebugger extends Ge
       DebuggerServer.allowChromeProcess = true;
     }
     this._isEnabled = true;
     this._usbDebugger.stop();
 
     let windowId = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIDOMWindowUtils)
                               .outerWindowID;
-    let portOrPath = this.settings.debuggerSocketDir +
+    let portOrPath = (this.settings.debuggerSocketDir || this.settings.dataDir) +
                      "/firefox-debugger-socket-" +
                      windowId;
     this._usbDebugger.start(portOrPath);
   }
 
   unregister() {
     this._isEnabled = false;
     this._usbDebugger.stop();