From f8d68e46e14d015746f99a7797e8e0ae412dc299 Mon Sep 17 00:00:00 2001 From: Agi Sferro Date: Tue, 17 Dec 2019 23:23:52 +0000 Subject: [PATCH] Bug 1600742 - Move event listeners from WebExtension to WebExtensionController. r=snorp,esawin Differential Revision: https://phabricator.services.mozilla.com/D57035 --HG-- extra : moz-landing-system : lando --- .../org/mozilla/geckoview/WebExtension.java | 96 +++++++++------ .../geckoview/WebExtensionController.java | 109 +++++++----------- 2 files changed, 98 insertions(+), 107 deletions(-) diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java index c47027652cad..97d767f74cef 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java @@ -68,29 +68,15 @@ public class WebExtension { /* package */ interface DelegateController { void onMessageDelegate(final String nativeApp, final MessageDelegate delegate); void onActionDelegate(final ActionDelegate delegate); + ActionDelegate getActionDelegate(); } - private WeakReference mDelegateController = new WeakReference<>(null); + private DelegateController mDelegateController = null; - /* package */ void setDelegateController(final DelegateController observer) { - mDelegateController = new WeakReference<>(observer); - - if (observer != null) { - // Notify observers of already attached delegates - for (final Map.Entry entry : messageDelegates.entrySet()) { - observer.onMessageDelegate(entry.getKey(), entry.getValue()); - } - observer.onActionDelegate(actionDelegate); - } + /* package */ void setDelegateController(final DelegateController delegate) { + mDelegateController = delegate; } - /** - * Delegates that handle messaging between this WebExtension and the app. - */ - /* package */ final @NonNull Map messageDelegates; - - /* package */ @NonNull ActionDelegate actionDelegate; - @Override public String toString() { return "WebExtension {" + @@ -128,7 +114,6 @@ public class WebExtension { flags = bundle.getInt("webExtensionFlags", 0); isBuiltIn = bundle.getBoolean("isBuiltIn", false); isEnabled = bundle.getBoolean("isEnabled", false); - messageDelegates = new HashMap<>(); if (bundle.containsKey("metaData")) { metaData = new MetaData(bundle.getBundle("metaData")); } else { @@ -164,10 +149,10 @@ public class WebExtension { public WebExtension(final @NonNull String location, final @NonNull String id, final @WebExtensionFlags long flags, final @NonNull WebExtensionController controller) { + setDelegateController(controller.delegateFor(this)); this.location = location; this.id = id; this.flags = flags; - this.messageDelegates = new HashMap<>(); // TODO: this.isEnabled = false; @@ -244,15 +229,9 @@ public class WebExtension { @UiThread public void setMessageDelegate(final @Nullable MessageDelegate messageDelegate, final @NonNull String nativeApp) { - final DelegateController observer = mDelegateController.get(); - if (observer != null) { - observer.onMessageDelegate(nativeApp, messageDelegate); + if (mDelegateController != null) { + mDelegateController.onMessageDelegate(nativeApp, messageDelegate); } - if (messageDelegate == null) { - messageDelegates.remove(nativeApp); - return; - } - messageDelegates.put(nativeApp, messageDelegate); } /** @@ -468,6 +447,8 @@ public class WebExtension { /* package */ final static class Listener implements BundleEventListener { final private HashMap mMessageDelegates; final private HashMap mActionDelegates; + private WebExtensionController.TabDelegate mTabDelegate = null; + final private GeckoSession mSession; final private EventDispatcher mEventDispatcher; @@ -498,6 +479,28 @@ public class WebExtension { this.runtime = runtime; } + public void setTabDelegate(final WebExtensionController.TabDelegate delegate) { + if (delegate != null && mTabDelegate == null) { + mEventDispatcher.registerUiThreadListener( + this, + "GeckoView:WebExtension:NewTab", + "GeckoView:WebExtension:CloseTab" + ); + } else if (delegate == null && mTabDelegate != null) { + mEventDispatcher.unregisterUiThreadListener( + this, + "GeckoView:WebExtension:NewTab", + "GeckoView:WebExtension:CloseTab" + ); + } + + mTabDelegate = delegate; + } + + public WebExtensionController.TabDelegate getTabDelegate() { + return mTabDelegate; + } + public void setActionDelegate(final WebExtension webExtension, final WebExtension.ActionDelegate delegate) { if (!mActionDelegateRegistered && delegate != null) { @@ -555,10 +558,30 @@ public class WebExtension { || "GeckoView:BrowserAction:OpenPopup".equals(event)) { controller.handleMessage(event, message, callback, mSession); return; - } else if ("GeckoView:WebExtension:CloseTab".equals(event)) { - controller.closeTab(message, callback, mSession); + } + + // If a tab delegate is not defined on the session, try the runtime + // + // TODO: The tab delegate is special because it's only set on the + // controller and not on the session, all other delegates are set + // on both, we should unify this and have a tab delegate for each + // session too. + WebExtensionController.TabDelegate delegate = mTabDelegate; + if (delegate == null && mSession != null) { + delegate = runtime.getWebExtensionController().getTabDelegate(); + } + + if (delegate == null) { + callback.sendError("No delegate registered."); return; } + + if ("GeckoView:WebExtension:CloseTab".equals(event)) { + controller.closeTab(message, callback, delegate, mSession); + return; + } else if ("GeckoView:WebExtension:NewTab".equals(event)) { + controller.newTab(message, callback, delegate); + } } } @@ -941,12 +964,12 @@ public class WebExtension { @UiThread public void click() { if (mPopupUri != null && !mPopupUri.isEmpty()) { - if (mExtension.actionDelegate == null) { + final ActionDelegate delegate = mExtension.mDelegateController.getActionDelegate(); + if (delegate == null) { return; } - GeckoResult popup = - mExtension.actionDelegate.onTogglePopup(mExtension, this); + GeckoResult popup = delegate.onTogglePopup(mExtension, this); openPopup(popup); // When popupUri is specified, the extension doesn't get a callback @@ -1143,13 +1166,10 @@ public class WebExtension { */ @AnyThread public void setActionDelegate(final @Nullable ActionDelegate delegate) { - final DelegateController observer = mDelegateController.get(); - if (observer != null) { - observer.onActionDelegate(delegate); + if (mDelegateController != null) { + mDelegateController.onActionDelegate(delegate); } - actionDelegate = delegate; - final GeckoBundle bundle = new GeckoBundle(1); bundle.putString("extensionId", id); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtensionController.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtensionController.java index dd1bf4094372..bfbf0ae5bfc4 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtensionController.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtensionController.java @@ -21,10 +21,8 @@ import java.util.Map; public class WebExtensionController { private final static String LOGTAG = "WebExtension"; - private GeckoRuntime mRuntime; - - private TabDelegate mTabDelegate; private PromptDelegate mPromptDelegate; + private final WebExtension.Listener mListener; private static class ExtensionStore { final private Map mData = new HashMap<>(); @@ -66,11 +64,7 @@ public class WebExtensionController { // Avoids exposing listeners to the API private class Internals implements BundleEventListener, - WebExtension.Port.DisconnectDelegate, - WebExtension.DelegateController { - private boolean mMessageListenersAttached = false; - private boolean mActionListenersAttached = false; - + WebExtension.Port.DisconnectDelegate { @Override // BundleEventListener public void handleMessage(final String event, final GeckoBundle message, @@ -85,35 +79,35 @@ public class WebExtensionController { // we just need to remove it from our list of ports. mPorts.remove(port.id); } + } + + private class DelegateController implements WebExtension.DelegateController { + private WebExtension mExtension; + + public DelegateController(final WebExtension extension) { + mExtension = extension; + } @Override - // WebExtension.DelegateController public void onMessageDelegate(final String nativeApp, final WebExtension.MessageDelegate delegate) { - if (delegate != null && !mMessageListenersAttached) { - EventDispatcher.getInstance().registerUiThreadListener( - this, - "GeckoView:WebExtension:Message", - "GeckoView:WebExtension:PortMessage", - "GeckoView:WebExtension:Connect", - "GeckoView:WebExtension:Disconnect"); - mMessageListenersAttached = true; - } + mListener.setMessageDelegate(mExtension, delegate, nativeApp); } @Override - // WebExtension.DelegateController public void onActionDelegate(final WebExtension.ActionDelegate delegate) { - if (delegate != null && !mActionListenersAttached) { - EventDispatcher.getInstance().registerUiThreadListener( - this, - "GeckoView:BrowserAction:Update", - "GeckoView:BrowserAction:OpenPopup", - "GeckoView:PageAction:Update", - "GeckoView:PageAction:OpenPopup"); - mActionListenersAttached = true; - } + mListener.setActionDelegate(mExtension, delegate); } + + @Override + public WebExtension.ActionDelegate getActionDelegate() { + return mListener.getActionDelegate(mExtension); + } + } + + // TODO: remove once we remove GeckoRuntime#registerWebExtension + /* package */ DelegateController delegateFor(final WebExtension extension) { + return new DelegateController(extension); } public interface TabDelegate { @@ -155,27 +149,12 @@ public class WebExtensionController { @UiThread public @Nullable TabDelegate getTabDelegate() { - return mTabDelegate; + return mListener.getTabDelegate(); } @UiThread public void setTabDelegate(final @Nullable TabDelegate delegate) { - if (delegate == null) { - if (mTabDelegate != null) { - EventDispatcher.getInstance().unregisterUiThreadListener( - mInternals, - "GeckoView:WebExtension:NewTab" - ); - } - } else { - if (mTabDelegate == null) { - EventDispatcher.getInstance().registerUiThreadListener( - mInternals, - "GeckoView:WebExtension:NewTab" - ); - } - } - mTabDelegate = delegate; + mListener.setTabDelegate(delegate); } /** @@ -454,20 +433,17 @@ public class WebExtensionController { } /* package */ WebExtensionController(final GeckoRuntime runtime) { - mRuntime = runtime; + mListener = new WebExtension.Listener(runtime); } /* package */ void registerWebExtension(final WebExtension webExtension) { - webExtension.setDelegateController(mInternals); + webExtension.setDelegateController(new DelegateController(webExtension)); mExtensions.put(webExtension.id, webExtension); } /* package */ void handleMessage(final String event, final GeckoBundle message, final EventCallback callback, final GeckoSession session) { - if ("GeckoView:WebExtension:NewTab".equals(event)) { - newTab(message, callback); - return; - } else if ("GeckoView:WebExtension:Disconnect".equals(event)) { + if ("GeckoView:WebExtension:Disconnect".equals(event)) { disconnect(message.getLong("portId", -1), callback); return; } else if ("GeckoView:WebExtension:PortMessage".equals(event)) { @@ -532,6 +508,7 @@ public class WebExtensionController { } final WebExtension extension = new WebExtension(extensionBundle); + extension.setDelegateController(new DelegateController(extension)); if (mPromptDelegate == null) { Log.e(LOGTAG, "Tried to install extension " + extension.id + @@ -555,14 +532,10 @@ public class WebExtensionController { }); } - private void newTab(final GeckoBundle message, final EventCallback callback) { - if (mTabDelegate == null) { - callback.sendSuccess(null); - return; - } - + /* package */ void newTab(final GeckoBundle message, final EventCallback callback, + final TabDelegate delegate) { mExtensions.get(message.getString("extensionId")).then(extension -> - mTabDelegate.onNewTab(extension, message.getString("uri")) + delegate.onNewTab(extension, message.getString("uri")) ).accept(session -> { if (session == null) { callback.sendSuccess(null); @@ -573,24 +546,22 @@ public class WebExtensionController { throw new IllegalArgumentException("Must use an unopened GeckoSession instance"); } - session.open(mRuntime); + session.open(mListener.runtime); callback.sendSuccess(session.getId()); }); } - /* package */ void closeTab(final GeckoBundle message, final EventCallback callback, final GeckoSession session) { - if (mTabDelegate == null) { - callback.sendError(null); - return; - } - + /* package */ void closeTab(final GeckoBundle message, + final EventCallback callback, + final TabDelegate delegate, + final GeckoSession session) { mExtensions.get(message.getString("extensionId")).then( - extension -> mTabDelegate.onCloseTab(extension, session), + extension -> delegate.onCloseTab(extension, session), // On uninstall, we close all extension pages, in that case // the extension object may be gone already so we can't // send it to the delegate - exception -> mTabDelegate.onCloseTab(null, session) + exception -> delegate.onCloseTab(null, session) ).accept(value -> { if (value == AllowOrDeny.ALLOW) { callback.sendSuccess(null); @@ -701,7 +672,7 @@ public class WebExtensionController { if (sender.session != null) { delegate = sender.session.getMessageDelegate(sender.webExtension, nativeApp); } else if (sender.environmentType == WebExtension.MessageSender.ENV_TYPE_EXTENSION) { - delegate = sender.webExtension.messageDelegates.get(nativeApp); + delegate = mListener.getMessageDelegate(sender.webExtension, nativeApp); } if (delegate == null) { @@ -805,7 +776,7 @@ public class WebExtensionController { private WebExtension.ActionDelegate actionDelegateFor(final WebExtension extension, final GeckoSession session) { if (session == null) { - return extension.actionDelegate; + return mListener.getActionDelegate(extension); } return session.getWebExtensionActionDelegate(extension);