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
This commit is contained in:
Agi Sferro 2019-12-17 23:23:52 +00:00
Родитель 6c81d2a85b
Коммит f8d68e46e1
2 изменённых файлов: 98 добавлений и 107 удалений

Просмотреть файл

@ -68,28 +68,14 @@ public class WebExtension {
/* package */ interface DelegateController { /* package */ interface DelegateController {
void onMessageDelegate(final String nativeApp, final MessageDelegate delegate); void onMessageDelegate(final String nativeApp, final MessageDelegate delegate);
void onActionDelegate(final ActionDelegate delegate); void onActionDelegate(final ActionDelegate delegate);
ActionDelegate getActionDelegate();
} }
private WeakReference<DelegateController> mDelegateController = new WeakReference<>(null); private DelegateController mDelegateController = null;
/* package */ void setDelegateController(final DelegateController observer) { /* package */ void setDelegateController(final DelegateController delegate) {
mDelegateController = new WeakReference<>(observer); mDelegateController = delegate;
if (observer != null) {
// Notify observers of already attached delegates
for (final Map.Entry<String, MessageDelegate> entry : messageDelegates.entrySet()) {
observer.onMessageDelegate(entry.getKey(), entry.getValue());
} }
observer.onActionDelegate(actionDelegate);
}
}
/**
* Delegates that handle messaging between this WebExtension and the app.
*/
/* package */ final @NonNull Map<String, MessageDelegate> messageDelegates;
/* package */ @NonNull ActionDelegate actionDelegate;
@Override @Override
public String toString() { public String toString() {
@ -128,7 +114,6 @@ public class WebExtension {
flags = bundle.getInt("webExtensionFlags", 0); flags = bundle.getInt("webExtensionFlags", 0);
isBuiltIn = bundle.getBoolean("isBuiltIn", false); isBuiltIn = bundle.getBoolean("isBuiltIn", false);
isEnabled = bundle.getBoolean("isEnabled", false); isEnabled = bundle.getBoolean("isEnabled", false);
messageDelegates = new HashMap<>();
if (bundle.containsKey("metaData")) { if (bundle.containsKey("metaData")) {
metaData = new MetaData(bundle.getBundle("metaData")); metaData = new MetaData(bundle.getBundle("metaData"));
} else { } else {
@ -164,10 +149,10 @@ public class WebExtension {
public WebExtension(final @NonNull String location, final @NonNull String id, public WebExtension(final @NonNull String location, final @NonNull String id,
final @WebExtensionFlags long flags, final @WebExtensionFlags long flags,
final @NonNull WebExtensionController controller) { final @NonNull WebExtensionController controller) {
setDelegateController(controller.delegateFor(this));
this.location = location; this.location = location;
this.id = id; this.id = id;
this.flags = flags; this.flags = flags;
this.messageDelegates = new HashMap<>();
// TODO: // TODO:
this.isEnabled = false; this.isEnabled = false;
@ -244,15 +229,9 @@ public class WebExtension {
@UiThread @UiThread
public void setMessageDelegate(final @Nullable MessageDelegate messageDelegate, public void setMessageDelegate(final @Nullable MessageDelegate messageDelegate,
final @NonNull String nativeApp) { final @NonNull String nativeApp) {
final DelegateController observer = mDelegateController.get(); if (mDelegateController != null) {
if (observer != null) { mDelegateController.onMessageDelegate(nativeApp, messageDelegate);
observer.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 { /* package */ final static class Listener implements BundleEventListener {
final private HashMap<Sender, WebExtension.MessageDelegate> mMessageDelegates; final private HashMap<Sender, WebExtension.MessageDelegate> mMessageDelegates;
final private HashMap<String, WebExtension.ActionDelegate> mActionDelegates; final private HashMap<String, WebExtension.ActionDelegate> mActionDelegates;
private WebExtensionController.TabDelegate mTabDelegate = null;
final private GeckoSession mSession; final private GeckoSession mSession;
final private EventDispatcher mEventDispatcher; final private EventDispatcher mEventDispatcher;
@ -498,6 +479,28 @@ public class WebExtension {
this.runtime = runtime; 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, public void setActionDelegate(final WebExtension webExtension,
final WebExtension.ActionDelegate delegate) { final WebExtension.ActionDelegate delegate) {
if (!mActionDelegateRegistered && delegate != null) { if (!mActionDelegateRegistered && delegate != null) {
@ -555,10 +558,30 @@ public class WebExtension {
|| "GeckoView:BrowserAction:OpenPopup".equals(event)) { || "GeckoView:BrowserAction:OpenPopup".equals(event)) {
controller.handleMessage(event, message, callback, mSession); controller.handleMessage(event, message, callback, mSession);
return; 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; 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 @UiThread
public void click() { public void click() {
if (mPopupUri != null && !mPopupUri.isEmpty()) { if (mPopupUri != null && !mPopupUri.isEmpty()) {
if (mExtension.actionDelegate == null) { final ActionDelegate delegate = mExtension.mDelegateController.getActionDelegate();
if (delegate == null) {
return; return;
} }
GeckoResult<GeckoSession> popup = GeckoResult<GeckoSession> popup = delegate.onTogglePopup(mExtension, this);
mExtension.actionDelegate.onTogglePopup(mExtension, this);
openPopup(popup); openPopup(popup);
// When popupUri is specified, the extension doesn't get a callback // When popupUri is specified, the extension doesn't get a callback
@ -1143,13 +1166,10 @@ public class WebExtension {
*/ */
@AnyThread @AnyThread
public void setActionDelegate(final @Nullable ActionDelegate delegate) { public void setActionDelegate(final @Nullable ActionDelegate delegate) {
final DelegateController observer = mDelegateController.get(); if (mDelegateController != null) {
if (observer != null) { mDelegateController.onActionDelegate(delegate);
observer.onActionDelegate(delegate);
} }
actionDelegate = delegate;
final GeckoBundle bundle = new GeckoBundle(1); final GeckoBundle bundle = new GeckoBundle(1);
bundle.putString("extensionId", id); bundle.putString("extensionId", id);

Просмотреть файл

@ -21,10 +21,8 @@ import java.util.Map;
public class WebExtensionController { public class WebExtensionController {
private final static String LOGTAG = "WebExtension"; private final static String LOGTAG = "WebExtension";
private GeckoRuntime mRuntime;
private TabDelegate mTabDelegate;
private PromptDelegate mPromptDelegate; private PromptDelegate mPromptDelegate;
private final WebExtension.Listener mListener;
private static class ExtensionStore { private static class ExtensionStore {
final private Map<String, WebExtension> mData = new HashMap<>(); final private Map<String, WebExtension> mData = new HashMap<>();
@ -66,11 +64,7 @@ public class WebExtensionController {
// Avoids exposing listeners to the API // Avoids exposing listeners to the API
private class Internals implements BundleEventListener, private class Internals implements BundleEventListener,
WebExtension.Port.DisconnectDelegate, WebExtension.Port.DisconnectDelegate {
WebExtension.DelegateController {
private boolean mMessageListenersAttached = false;
private boolean mActionListenersAttached = false;
@Override @Override
// BundleEventListener // BundleEventListener
public void handleMessage(final String event, final GeckoBundle message, 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. // we just need to remove it from our list of ports.
mPorts.remove(port.id); mPorts.remove(port.id);
} }
}
private class DelegateController implements WebExtension.DelegateController {
private WebExtension mExtension;
public DelegateController(final WebExtension extension) {
mExtension = extension;
}
@Override @Override
// WebExtension.DelegateController
public void onMessageDelegate(final String nativeApp, public void onMessageDelegate(final String nativeApp,
final WebExtension.MessageDelegate delegate) { final WebExtension.MessageDelegate delegate) {
if (delegate != null && !mMessageListenersAttached) { mListener.setMessageDelegate(mExtension, delegate, nativeApp);
EventDispatcher.getInstance().registerUiThreadListener(
this,
"GeckoView:WebExtension:Message",
"GeckoView:WebExtension:PortMessage",
"GeckoView:WebExtension:Connect",
"GeckoView:WebExtension:Disconnect");
mMessageListenersAttached = true;
}
} }
@Override @Override
// WebExtension.DelegateController
public void onActionDelegate(final WebExtension.ActionDelegate delegate) { public void onActionDelegate(final WebExtension.ActionDelegate delegate) {
if (delegate != null && !mActionListenersAttached) { mListener.setActionDelegate(mExtension, delegate);
EventDispatcher.getInstance().registerUiThreadListener( }
this,
"GeckoView:BrowserAction:Update", @Override
"GeckoView:BrowserAction:OpenPopup", public WebExtension.ActionDelegate getActionDelegate() {
"GeckoView:PageAction:Update", return mListener.getActionDelegate(mExtension);
"GeckoView:PageAction:OpenPopup");
mActionListenersAttached = true;
} }
} }
// TODO: remove once we remove GeckoRuntime#registerWebExtension
/* package */ DelegateController delegateFor(final WebExtension extension) {
return new DelegateController(extension);
} }
public interface TabDelegate { public interface TabDelegate {
@ -155,27 +149,12 @@ public class WebExtensionController {
@UiThread @UiThread
public @Nullable TabDelegate getTabDelegate() { public @Nullable TabDelegate getTabDelegate() {
return mTabDelegate; return mListener.getTabDelegate();
} }
@UiThread @UiThread
public void setTabDelegate(final @Nullable TabDelegate delegate) { public void setTabDelegate(final @Nullable TabDelegate delegate) {
if (delegate == null) { mListener.setTabDelegate(delegate);
if (mTabDelegate != null) {
EventDispatcher.getInstance().unregisterUiThreadListener(
mInternals,
"GeckoView:WebExtension:NewTab"
);
}
} else {
if (mTabDelegate == null) {
EventDispatcher.getInstance().registerUiThreadListener(
mInternals,
"GeckoView:WebExtension:NewTab"
);
}
}
mTabDelegate = delegate;
} }
/** /**
@ -454,20 +433,17 @@ public class WebExtensionController {
} }
/* package */ WebExtensionController(final GeckoRuntime runtime) { /* package */ WebExtensionController(final GeckoRuntime runtime) {
mRuntime = runtime; mListener = new WebExtension.Listener(runtime);
} }
/* package */ void registerWebExtension(final WebExtension webExtension) { /* package */ void registerWebExtension(final WebExtension webExtension) {
webExtension.setDelegateController(mInternals); webExtension.setDelegateController(new DelegateController(webExtension));
mExtensions.put(webExtension.id, webExtension); mExtensions.put(webExtension.id, webExtension);
} }
/* package */ void handleMessage(final String event, final GeckoBundle message, /* package */ void handleMessage(final String event, final GeckoBundle message,
final EventCallback callback, final GeckoSession session) { final EventCallback callback, final GeckoSession session) {
if ("GeckoView:WebExtension:NewTab".equals(event)) { if ("GeckoView:WebExtension:Disconnect".equals(event)) {
newTab(message, callback);
return;
} else if ("GeckoView:WebExtension:Disconnect".equals(event)) {
disconnect(message.getLong("portId", -1), callback); disconnect(message.getLong("portId", -1), callback);
return; return;
} else if ("GeckoView:WebExtension:PortMessage".equals(event)) { } else if ("GeckoView:WebExtension:PortMessage".equals(event)) {
@ -532,6 +508,7 @@ public class WebExtensionController {
} }
final WebExtension extension = new WebExtension(extensionBundle); final WebExtension extension = new WebExtension(extensionBundle);
extension.setDelegateController(new DelegateController(extension));
if (mPromptDelegate == null) { if (mPromptDelegate == null) {
Log.e(LOGTAG, "Tried to install extension " + extension.id + 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) { /* package */ void newTab(final GeckoBundle message, final EventCallback callback,
if (mTabDelegate == null) { final TabDelegate delegate) {
callback.sendSuccess(null);
return;
}
mExtensions.get(message.getString("extensionId")).then(extension -> mExtensions.get(message.getString("extensionId")).then(extension ->
mTabDelegate.onNewTab(extension, message.getString("uri")) delegate.onNewTab(extension, message.getString("uri"))
).accept(session -> { ).accept(session -> {
if (session == null) { if (session == null) {
callback.sendSuccess(null); callback.sendSuccess(null);
@ -573,24 +546,22 @@ public class WebExtensionController {
throw new IllegalArgumentException("Must use an unopened GeckoSession instance"); throw new IllegalArgumentException("Must use an unopened GeckoSession instance");
} }
session.open(mRuntime); session.open(mListener.runtime);
callback.sendSuccess(session.getId()); callback.sendSuccess(session.getId());
}); });
} }
/* package */ void closeTab(final GeckoBundle message, final EventCallback callback, final GeckoSession session) { /* package */ void closeTab(final GeckoBundle message,
if (mTabDelegate == null) { final EventCallback callback,
callback.sendError(null); final TabDelegate delegate,
return; final GeckoSession session) {
}
mExtensions.get(message.getString("extensionId")).then( 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 // On uninstall, we close all extension pages, in that case
// the extension object may be gone already so we can't // the extension object may be gone already so we can't
// send it to the delegate // send it to the delegate
exception -> mTabDelegate.onCloseTab(null, session) exception -> delegate.onCloseTab(null, session)
).accept(value -> { ).accept(value -> {
if (value == AllowOrDeny.ALLOW) { if (value == AllowOrDeny.ALLOW) {
callback.sendSuccess(null); callback.sendSuccess(null);
@ -701,7 +672,7 @@ public class WebExtensionController {
if (sender.session != null) { if (sender.session != null) {
delegate = sender.session.getMessageDelegate(sender.webExtension, nativeApp); delegate = sender.session.getMessageDelegate(sender.webExtension, nativeApp);
} else if (sender.environmentType == WebExtension.MessageSender.ENV_TYPE_EXTENSION) { } else if (sender.environmentType == WebExtension.MessageSender.ENV_TYPE_EXTENSION) {
delegate = sender.webExtension.messageDelegates.get(nativeApp); delegate = mListener.getMessageDelegate(sender.webExtension, nativeApp);
} }
if (delegate == null) { if (delegate == null) {
@ -805,7 +776,7 @@ public class WebExtensionController {
private WebExtension.ActionDelegate actionDelegateFor(final WebExtension extension, private WebExtension.ActionDelegate actionDelegateFor(final WebExtension extension,
final GeckoSession session) { final GeckoSession session) {
if (session == null) { if (session == null) {
return extension.actionDelegate; return mListener.getActionDelegate(extension);
} }
return session.getWebExtensionActionDelegate(extension); return session.getWebExtensionActionDelegate(extension);