Bug 1597793 - Track tab activation in GeckoViewTab. r=snorp

This avoids initialization issues with the previous approach.

Differential Revision: https://phabricator.services.mozilla.com/D60941

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Agi Sferro 2020-01-25 07:27:14 +00:00
parent baa36cbd6f
commit c4f3912001
8 changed files with 93 additions and 42 deletions

View File

@ -14,6 +14,12 @@ ChromeUtils.defineModuleGetter(
"resource://gre/modules/GeckoViewTab.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"mobileWindowTracker",
"resource://gre/modules/GeckoViewWebExtension.jsm"
);
const getBrowserWindow = window => {
return window.docShell.rootTreeItem.domWindow;
};
@ -126,9 +132,9 @@ this.tabs = class extends ExtensionAPI {
});
};
windowTracker.on("tab-activated", listener);
mobileWindowTracker.on("tab-activated", listener);
return () => {
windowTracker.off("tab-activated", listener);
mobileWindowTracker.off("tab-activated", listener);
};
},
}).api(),

View File

@ -14,6 +14,12 @@ ChromeUtils.defineModuleGetter(
"resource://gre/modules/GeckoViewTab.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"mobileWindowTracker",
"resource://gre/modules/GeckoViewWebExtension.jsm"
);
var { EventDispatcher } = ChromeUtils.import(
"resource://gre/modules/Messaging.jsm"
);
@ -125,35 +131,10 @@ class WindowTracker extends WindowTrackerBase {
super(...args);
this.progressListeners = new DefaultWeakMap(() => new WeakMap());
const self = this;
this._topWindowRef = null;
const listener = {
onEvent(event, data, callback) {
const { sessionId, active } = data;
const window = Services.ww.getWindowByName(sessionId, null);
const windowId = window.windowUtils.outerWindowID;
const tab = window.BrowserApp.selectedTab;
tab.active = active;
if (active) {
self._topWindowRef = Cu.getWeakReference(window);
self.emit("tab-activated", {
windowId,
tabId: tab.id,
});
}
},
};
GlobalEventDispatcher.registerListener(listener, [
"GeckoView:WebExtension:SetTabActive",
]);
}
get topWindow() {
if (this._topWindowRef) {
return this._topWindowRef.get();
}
return Services.wm.getMostRecentWindow(WINDOW_TYPE);
return mobileWindowTracker.topWindow;
}
get topNonPBWindow() {

View File

@ -22,10 +22,6 @@ add_task(async function testExecuteScript() {
async function background() {
try {
let [tab] = await browser.tabs.query({active: true, currentWindow: true});
// TODO bug 1565536: tab.active is broken in GeckoView.
browser.test.assertEq(undefined, tab, "currentWindow's tab is not active (bug 1565536)");
[tab] = await browser.tabs.query({currentWindow: true});
let frames = await browser.webNavigation.getAllFrames({tabId: tab.id});
browser.test.log(`FRAMES: ${frames[1].frameId} ${JSON.stringify(frames)}\n`);

View File

@ -48,9 +48,6 @@ add_task(async function testExecuteScript() {
try {
[tab] = await browser.tabs.query({active: true, currentWindow: true});
// TODO bug 1565536: tab.active is broken in GeckoView.
browser.test.assertEq(undefined, tab, "currentWindow's tab is not active (bug 1565536)");
[tab] = await browser.tabs.query({currentWindow: true});
let success = false;
for (let tries = 0; !success && tries < MAX_TRIES; tries++) {

View File

@ -37,6 +37,7 @@ public class TestRunnerActivity extends Activity {
static GeckoRuntime sRuntime;
private GeckoSession mActiveSession;
private GeckoSession mSession;
private GeckoView mView;
private boolean mKillProcessOnDestroy;
@ -70,6 +71,10 @@ public class TestRunnerActivity extends Activity {
}
}
private static WebExtensionController webExtensionController() {
return sRuntime.getWebExtensionController();
}
private HashSet<GeckoSession> mOwnedSessions = new HashSet<>();
private GeckoSession.PermissionDelegate mPermissionDelegate = new GeckoSession.PermissionDelegate() {
@ -109,7 +114,10 @@ public class TestRunnerActivity extends Activity {
@Override
public GeckoResult<GeckoSession> onNewSession(GeckoSession session, String uri) {
return GeckoResult.fromValue(createBackgroundSession(session.getSettings()));
webExtensionController().setTabActive(mActiveSession, false);
mActiveSession = createBackgroundSession(session.getSettings());
webExtensionController().setTabActive(mActiveSession, true);
return GeckoResult.fromValue(mActiveSession);
}
@Override
@ -204,12 +212,21 @@ public class TestRunnerActivity extends Activity {
}
private void closeSession(GeckoSession session) {
if (session == mActiveSession) {
webExtensionController().setTabActive(mActiveSession, false);
mActiveSession = null;
}
if (mDisplays.containsKey(session)) {
final Display display = mDisplays.remove(session);
display.release(session);
}
mOwnedSessions.remove(session);
session.close();
if (!mOwnedSessions.isEmpty()) {
// Pick a random session to set as active
mActiveSession = mOwnedSessions.iterator().next();
webExtensionController().setTabActive(mActiveSession, true);
}
}
@Override
@ -242,15 +259,18 @@ public class TestRunnerActivity extends Activity {
sRuntime = GeckoRuntime.create(this, runtimeSettingsBuilder.build());
sRuntime.getWebExtensionController().setTabDelegate(new WebExtensionController.TabDelegate() {
webExtensionController().setTabDelegate(new WebExtensionController.TabDelegate() {
@Override
public GeckoResult<GeckoSession> onNewTab(WebExtension source, String uri) {
return GeckoResult.fromValue(createSession());
webExtensionController().setTabActive(mActiveSession, false);
mActiveSession = createSession();
webExtensionController().setTabActive(mActiveSession, true);
return GeckoResult.fromValue(mActiveSession);
}
@Override
public GeckoResult<AllowOrDeny> onCloseTab(WebExtension source, GeckoSession session) {
closeSession(session);
return GeckoResult.fromValue(AllowOrDeny.ALLOW);
closeSession(session);
return GeckoResult.fromValue(AllowOrDeny.ALLOW);
}
});
sRuntime.setDelegate(() -> {
@ -260,6 +280,8 @@ public class TestRunnerActivity extends Activity {
}
mSession = createSession();
mActiveSession = mSession;
webExtensionController().setTabActive(mActiveSession, true);
mSession.open(sRuntime);
// If we were passed a URI in the Intent, open it

View File

@ -725,9 +725,10 @@ public class WebExtensionController {
@AnyThread
public void setTabActive(@NonNull final GeckoSession session, final boolean active) {
final GeckoBundle bundle = new GeckoBundle(1);
bundle.putString("sessionId", session.getId());
bundle.putBoolean("active", active);
EventDispatcher.getInstance().dispatch("GeckoView:WebExtension:SetTabActive", bundle);
session.getEventDispatcher().dispatch(
"GeckoView:WebExtension:SetTabActive",
bundle);
}
/* package */ void unregisterWebExtension(final WebExtension webExtension) {

View File

@ -16,6 +16,7 @@ const { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
EventDispatcher: "resource://gre/modules/Messaging.jsm",
Services: "resource://gre/modules/Services.jsm",
mobileWindowTracker: "resource://gre/modules/GeckoViewWebExtension.jsm",
});
// Based on the "Tab" prototype from mobile/android/chrome/content/browser.js
@ -205,6 +206,20 @@ const GeckoViewTabBridge = {
class GeckoViewTab extends GeckoViewModule {
onInit() {
BrowserAppShim.getBrowserApp(this.window);
this.registerListener(["GeckoView:WebExtension:SetTabActive"]);
}
onEvent(aEvent, aData, aCallback) {
debug`onEvent: event=${aEvent}, data=${aData}`;
switch (aEvent) {
case "GeckoView:WebExtension:SetTabActive": {
const { active } = aData;
mobileWindowTracker.setTabActive(this.window, active);
break;
}
}
}
}

View File

@ -8,6 +8,7 @@ var EXPORTED_SYMBOLS = [
"ExtensionActionHelper",
"GeckoViewConnection",
"GeckoViewWebExtension",
"mobileWindowTracker",
];
const { XPCOMUtils } = ChromeUtils.import(
@ -16,6 +17,9 @@ const { XPCOMUtils } = ChromeUtils.import(
const { GeckoViewUtils } = ChromeUtils.import(
"resource://gre/modules/GeckoViewUtils.jsm"
);
const { EventEmitter } = ChromeUtils.import(
"resource://gre/modules/EventEmitter.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
@ -364,6 +368,35 @@ class ExtensionPromptObserver {
new ExtensionPromptObserver();
class MobileWindowTracker extends EventEmitter {
constructor() {
super();
this._topWindow = null;
}
get topWindow() {
if (this._topWindow) {
return this._topWindow.get();
}
return null;
}
setTabActive(aWindow, aActive) {
const tab = aWindow.BrowserApp.selectedTab;
tab.active = aActive;
if (aActive) {
this._topWindow = Cu.getWeakReference(aWindow);
this.emit("tab-activated", {
windowId: aWindow.windowUtils.outerWindowID,
tabId: tab.id,
});
}
}
}
var mobileWindowTracker = new MobileWindowTracker();
var GeckoViewWebExtension = {
async registerWebExtension(aId, aUri, allowContentMessaging, aCallback) {
const params = {