зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
6c81d2a85b
Коммит
f8d68e46e1
|
@ -68,29 +68,15 @@ 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() {
|
||||||
return "WebExtension {" +
|
return "WebExtension {" +
|
||||||
|
@ -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",
|
|
||||||
"GeckoView:BrowserAction:OpenPopup",
|
|
||||||
"GeckoView:PageAction:Update",
|
|
||||||
"GeckoView:PageAction:OpenPopup");
|
|
||||||
mActionListenersAttached = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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 {
|
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);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче