--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
@@ -644,16 +644,23 @@ public class CustomTabsActivity extends
} catch (ActivityNotFoundException e) {
Log.w(LOGTAG, "No activity handler found for: " + urlStr);
}
}
return true;
}
+ @Override
+ public void onNewSession(final GeckoSession session, final String uri,
+ final GeckoSession.Response<GeckoSession> response) {
+ // We should never get here because we abort loads that need a new session in onLoadUri()
+ throw new IllegalStateException("Unexpected new session");
+ }
+
/* GeckoSession.ProgressListener */
@Override
public void onPageStart(GeckoSession session, String url) {
mCurrentUrl = url;
mCanStop = true;
updateActionBar();
updateCanStop();
updateProgress(20);
--- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
@@ -417,16 +417,23 @@ public class WebAppActivity extends AppC
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(LOGTAG, "No activity handler found for: " + urlStr);
}
}
return true;
}
+ @Override
+ public void onNewSession(final GeckoSession session, final String uri,
+ final GeckoSession.Response<GeckoSession> response) {
+ // We should never get here because we abort loads that need a new session in onLoadUri()
+ throw new IllegalStateException("Unexpected new session");
+ }
+
private void updateFullScreen() {
boolean fullScreen = mIsFullScreenContent || mIsFullScreenMode;
if (ActivityUtils.isFullScreen(this) == fullScreen) {
return;
}
ActivityUtils.setFullScreen(this, fullScreen);
}
--- a/mobile/android/chrome/geckoview/geckoview.js
+++ b/mobile/android/chrome/geckoview/geckoview.js
@@ -4,32 +4,34 @@
"use strict";
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "EventDispatcher",
"resource://gre/modules/Messaging.jsm");
+ChromeUtils.defineModuleGetter(this, "Services",
+ "resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "WindowEventDispatcher",
() => EventDispatcher.for(window));
XPCOMUtils.defineLazyGetter(this, "dump", () =>
ChromeUtils.import("resource://gre/modules/AndroidLog.jsm",
{}).AndroidLog.d.bind(null, "View"));
// Creates and manages GeckoView modules.
// A module must extend GeckoViewModule.
// Instantiate a module by calling
// add(<resource path>, <type name>)
// and remove by calling
// remove(<type name>)
var ModuleManager = {
- init: function() {
- this.browser = document.getElementById("content");
+ init: function(aBrowser) {
+ this.browser = aBrowser;
this.modules = {};
},
add: function(aResource, aType, ...aArgs) {
this.remove(aType);
let scope = {};
ChromeUtils.import(aResource, scope);
this.modules[aType] = new scope[aType](
@@ -40,18 +42,34 @@ var ModuleManager = {
remove: function(aType) {
if (!(aType in this.modules)) {
return;
}
delete this.modules[aType];
}
};
+function createBrowser() {
+ const browser = window.browser = document.createElement("browser");
+ browser.setAttribute("type", "content");
+ browser.setAttribute("primary", "true");
+ browser.setAttribute("flex", "1");
+
+ // There may be a GeckoViewNavigation module in another window waiting for us to
+ // create a browser so it can call presetOpenerWindow(), so allow them to do that now.
+ Services.obs.notifyObservers(window, "geckoview-window-created");
+ window.document.getElementById("main-window").appendChild(browser);
+
+ browser.stop();
+ return browser;
+}
+
function startup() {
- ModuleManager.init();
+ const browser = createBrowser();
+ ModuleManager.init(browser);
// GeckoViewNavigation needs to go first because nsIDOMBrowserWindow must set up
// before the first remote browser. Bug 1365364.
ModuleManager.add("resource://gre/modules/GeckoViewNavigation.jsm",
"GeckoViewNavigation");
ModuleManager.add("resource://gre/modules/GeckoViewSettings.jsm",
"GeckoViewSettings");
ModuleManager.add("resource://gre/modules/GeckoViewContent.jsm",
@@ -64,10 +82,10 @@ function startup() {
"GeckoViewTab");
ModuleManager.add("resource://gre/modules/GeckoViewRemoteDebugger.jsm",
"GeckoViewRemoteDebugger");
ModuleManager.add("resource://gre/modules/GeckoViewTrackingProtection.jsm",
"GeckoViewTrackingProtection");
// Move focus to the content window at the end of startup,
// so things like text selection can work properly.
- document.getElementById("content").focus();
+ browser.focus();
}
--- a/mobile/android/chrome/geckoview/geckoview.xul
+++ b/mobile/android/chrome/geckoview/geckoview.xul
@@ -1,16 +1,11 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
-<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
-
<window id="main-window"
onload="startup();"
windowtype="navigator:geckoview"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-
- <browser id="content" type="content" primary="true" src="about:blank" flex="1"/>
-
<script type="application/javascript" src="chrome://geckoview/content/geckoview.js"/>
</window>
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSession.java
@@ -4,16 +4,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.UUID;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.gfx.LayerSession;
import org.mozilla.gecko.mozglue.JNIObject;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.ThreadUtils;
@@ -64,16 +65,19 @@ public class GeckoSession extends LayerS
private final NativeQueue mNativeQueue =
new NativeQueue(State.INITIAL, State.READY);
private final EventDispatcher mEventDispatcher =
new EventDispatcher(mNativeQueue);
private final TextInputController mTextInput = new TextInputController(this, mNativeQueue);
+ private String mId = UUID.randomUUID().toString().replace("-", "");
+ /* package */ String getId() { return mId; }
+
private final GeckoSessionHandler<ContentListener> mContentHandler =
new GeckoSessionHandler<ContentListener>(
"GeckoViewContent", this,
new String[]{
"GeckoView:ContextMenu",
"GeckoView:DOMTitleChanged",
"GeckoView:DOMWindowFocus",
"GeckoView:FullScreenEnter",
@@ -105,17 +109,18 @@ public class GeckoSession extends LayerS
}
};
private final GeckoSessionHandler<NavigationListener> mNavigationHandler =
new GeckoSessionHandler<NavigationListener>(
"GeckoViewNavigation", this,
new String[]{
"GeckoView:LocationChange",
- "GeckoView:OnLoadUri"
+ "GeckoView:OnLoadUri",
+ "GeckoView:OnNewSession"
}
) {
@Override
public void handleMessage(final NavigationListener listener,
final String event,
final GeckoBundle message,
final EventCallback callback) {
if ("GeckoView:LocationChange".equals(event)) {
@@ -128,16 +133,29 @@ public class GeckoSession extends LayerS
} else if ("GeckoView:OnLoadUri".equals(event)) {
final String uri = message.getString("uri");
final NavigationListener.TargetWindow where =
NavigationListener.TargetWindow.forGeckoValue(
message.getInt("where"));
final boolean result =
listener.onLoadUri(GeckoSession.this, uri, where);
callback.sendSuccess(result);
+ } else if ("GeckoView:OnNewSession".equals(event)) {
+ final String uri = message.getString("uri");
+ listener.onNewSession(GeckoSession.this, uri,
+ new Response<GeckoSession>() {
+ @Override
+ public void respond(GeckoSession session) {
+ if (session.isOpen() && session.isReady()) {
+ throw new IllegalArgumentException("Must use a new GeckoSession instance");
+ }
+
+ callback.sendSuccess(session != null ? session.getId() : null);
+ }
+ });
}
}
};
private final GeckoSessionHandler<ProgressListener> mProgressHandler =
new GeckoSessionHandler<ProgressListener>(
"GeckoViewProgress", this,
new String[]{
@@ -344,17 +362,17 @@ public class GeckoSession extends LayerS
}
return mBinder;
}
@WrapForJNI(dispatchTo = "proxy")
public static native void open(Window instance, Compositor compositor,
EventDispatcher dispatcher,
GeckoBundle settings, String chromeUri,
- int screenId, boolean privateMode);
+ int screenId, boolean privateMode, String id);
@Override // JNIObject
protected void disposeNative() {
// Detach ourselves from the binder as well, to prevent this window from being
// read from any parcels.
asBinder().attachInterface(null, Window.class.getName());
// Reset our queue, so we don't end up with queued calls on a disposed object.
@@ -428,33 +446,39 @@ public class GeckoSession extends LayerS
protected Window mWindow;
private GeckoSessionSettings mSettings;
public GeckoSession() {
this(/* settings */ null);
}
+ public GeckoSession(GeckoSession otherSession) {
+ this(otherSession.getSettings());
+ }
+
public GeckoSession(final GeckoSessionSettings settings) {
if (settings == null) {
mSettings = new GeckoSessionSettings(this);
} else {
mSettings = new GeckoSessionSettings(settings, this);
}
mListener.registerListeners();
}
- private void transferFrom(final Window window, final GeckoSessionSettings settings) {
+ private void transferFrom(final Window window, final GeckoSessionSettings settings,
+ final String id) {
if (isOpen()) {
throw new IllegalStateException("Session is open");
}
mWindow = window;
mSettings = new GeckoSessionSettings(settings, this);
+ mId = id;
if (mWindow != null) {
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
mWindow.transfer(mCompositor, mEventDispatcher, mSettings.asBundle());
} else {
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
mWindow, "transfer",
Compositor.class, mCompositor,
@@ -462,41 +486,43 @@ public class GeckoSession extends LayerS
GeckoBundle.class, mSettings.asBundle());
}
}
onWindowChanged();
}
/* package */ void transferFrom(final GeckoSession session) {
- transferFrom(session.mWindow, session.mSettings);
+ transferFrom(session.mWindow, session.mSettings, session.mId);
session.mWindow = null;
session.onWindowChanged();
}
@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(mId);
}
// AIDL code may call readFromParcel even though it's not part of Parcelable.
public void readFromParcel(final Parcel source) {
final IBinder binder = source.readStrongBinder();
final IInterface ifce = (binder != null) ?
binder.queryLocalInterface(Window.class.getName()) : null;
final Window window = (ifce instanceof Window) ? (Window) ifce : null;
final GeckoSessionSettings settings =
source.readParcelable(getClass().getClassLoader());
- transferFrom(window, settings);
+ final String id = source.readString();
+ transferFrom(window, settings, id);
}
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;
@@ -537,16 +563,20 @@ public class GeckoSession extends LayerS
GeckoThread.launch();
}
}
public boolean isOpen() {
return mWindow != null;
}
+ /* package */ boolean isReady() {
+ return mNativeQueue.isReady();
+ }
+
public void openWindow(final Context appContext) {
ThreadUtils.assertOnUiThread();
if (isOpen()) {
throw new IllegalStateException("Session is open");
}
if (!GeckoThread.isLaunched()) {
@@ -558,27 +588,27 @@ public class GeckoSession extends LayerS
final String chromeUri = mSettings.getString(GeckoSessionSettings.CHROME_URI);
final int screenId = mSettings.getInt(GeckoSessionSettings.SCREEN_ID);
final boolean isPrivate = mSettings.getBoolean(GeckoSessionSettings.USE_PRIVATE_MODE);
mWindow = new Window(mNativeQueue);
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
Window.open(mWindow, mCompositor, mEventDispatcher,
- mSettings.asBundle(), chromeUri, screenId, isPrivate);
+ mSettings.asBundle(), chromeUri, screenId, isPrivate, mId);
} else {
GeckoThread.queueNativeCallUntil(
GeckoThread.State.PROFILE_READY,
Window.class, "open",
Window.class, mWindow,
Compositor.class, mCompositor,
EventDispatcher.class, mEventDispatcher,
GeckoBundle.class, mSettings.asBundle(),
String.class, chromeUri,
- screenId, isPrivate);
+ screenId, isPrivate, mId);
}
onWindowChanged();
}
public void closeWindow() {
ThreadUtils.assertOnUiThread();
@@ -1297,16 +1327,26 @@ public class GeckoSession extends LayerS
* image-links.
* @param elementSrc The source URI of the pressed element, set for
* (nested) images and media elements.
*/
void onContextMenu(GeckoSession session, int screenX, int screenY,
String uri, String elementSrc);
}
+ /**
+ * This is used to send responses in delegate methods that have asynchronous responses.
+ */
+ public interface Response<T> {
+ /**
+ * @param val The value contained in the response
+ */
+ void respond(T val);
+ }
+
public interface NavigationListener {
/**
* A view has started loading content from the network.
* @param session The GeckoSession that initiated the callback.
* @param url The resource being loaded.
*/
void onLocationChange(GeckoSession session, String url);
@@ -1369,20 +1409,32 @@ public class GeckoSession extends LayerS
}
/**
* A request to open an URI.
* @param session The GeckoSession that initiated the callback.
* @param uri The URI to be loaded.
* @param where The target window.
*
- * @return True if the URI loading has been handled, false if Gecko
- * should handle the loading.
+ * @return Whether or not the load was handled. Returning false will allow Gecko
+ * to continue the load as normal.
*/
boolean onLoadUri(GeckoSession session, String uri, TargetWindow where);
+
+ /**
+ * A request has been made to open a new session. The URI is provided only for
+ * informational purposes. Do not call GeckoSession.loadUri() here. Additionally, the
+ * returned GeckoSession must be a newly-created one.
+ *
+ * @param session The GeckoSession that initiated the callback.
+ * @param uri The URI to be loaded.
+ *
+ * @param response A Response which will hold the returned GeckoSession
+ */
+ void onNewSession(GeckoSession session, String uri, Response<GeckoSession> response);
}
/**
* GeckoSession applications implement this interface to handle prompts triggered by
* content in the GeckoSession, such as alerts, authentication dialogs, and select list
* pickers.
**/
public interface PromptDelegate {
--- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
+++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java
@@ -14,16 +14,17 @@ import android.os.Bundle;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.WindowManager;
import java.util.Locale;
import org.mozilla.gecko.GeckoSession;
+import org.mozilla.gecko.GeckoSession.Response;
import org.mozilla.gecko.GeckoSessionSettings;
import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.GeckoView;
import org.mozilla.gecko.GeckoSession.PermissionDelegate.MediaSource;
import org.mozilla.gecko.GeckoSession.TrackingProtectionDelegate;
import org.mozilla.gecko.util.GeckoBundle;
public class GeckoViewActivity extends Activity {
@@ -48,16 +49,17 @@ public class GeckoViewActivity extends A
" - application start");
String geckoArgs = null;
final String intentArgs = getIntent().getStringExtra("args");
if (BuildConfig.DEBUG) {
// In debug builds, we want to load JavaScript resources fresh with each build.
geckoArgs = "-purgecaches";
+
}
if (!TextUtils.isEmpty(intentArgs)) {
if (geckoArgs == null) {
geckoArgs = intentArgs;
} else {
geckoArgs += " " + intentArgs;
}
@@ -82,18 +84,18 @@ public class GeckoViewActivity extends A
final BasicGeckoViewPrompt prompt = new BasicGeckoViewPrompt(this);
prompt.filePickerRequestCode = REQUEST_FILE_PICKER;
mGeckoSession.setPromptDelegate(prompt);
final MyGeckoViewPermission permission = new MyGeckoViewPermission();
permission.androidPermissionRequestCode = REQUEST_PERMISSIONS;
mGeckoSession.setPermissionDelegate(permission);
- mGeckoView.getSettings().setBoolean(GeckoSessionSettings.USE_MULTIPROCESS,
- useMultiprocess);
+ mGeckoSession.getSettings().setBoolean(GeckoSessionSettings.USE_MULTIPROCESS,
+ useMultiprocess);
mGeckoSession.enableTrackingProtection(
TrackingProtectionDelegate.CATEGORY_AD |
TrackingProtectionDelegate.CATEGORY_ANALYTIC |
TrackingProtectionDelegate.CATEGORY_SOCIAL
);
loadSettings(getIntent());
@@ -341,23 +343,22 @@ public class GeckoViewActivity extends A
@Override
public void onCanGoForward(GeckoSession session, boolean value) {
}
@Override
public boolean onLoadUri(final GeckoSession session, final String uri,
final TargetWindow where) {
- Log.d(LOGTAG, "onLoadUri=" + uri +
- " where=" + where);
- if (where != TargetWindow.NEW) {
- return false;
- }
- session.loadUri(uri);
- return true;
+ return false;
+ }
+
+ @Override
+ public void onNewSession(final GeckoSession session, final String uri, Response<GeckoSession> response) {
+ response.respond(null);
}
}
private class MyTrackingProtection implements GeckoSession.TrackingProtectionDelegate {
private int mBlockedAds = 0;
private int mBlockedAnalytics = 0;
private int mBlockedSocial = 0;
--- a/mobile/android/modules/geckoview/GeckoViewNavigation.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewNavigation.jsm
@@ -93,80 +93,122 @@ class GeckoViewNavigation extends GeckoV
this.eventDispatcher.sendRequestForResult(message).then(response => {
handled = response;
});
Services.tm.spinEventLoopUntil(() => handled !== undefined);
return handled;
}
+ waitAndSetOpener(sessionId, opener) {
+ if (!sessionId) {
+ return Promise.resolve(null);
+ }
+
+ return new Promise(resolve => {
+ const handler = {
+ observe(aSubject, aTopic, aData) {
+ if (aTopic === "geckoview-window-created" && aSubject.name === sessionId) {
+ aSubject.browser.presetOpenerWindow(opener);
+ Services.obs.removeObserver(handler, "geckoview-window-created");
+ resolve(aSubject);
+ }
+ }
+ };
+
+ // This event is emitted from createBrowser() in geckoview.js
+ Services.obs.addObserver(handler, "geckoview-window-created");
+ });
+ }
+
+ handleNewSession(aUri, aOpener, aWhere, aFlags, aTriggeringPrincipal) {
+ debug("handleNewSession: aUri=" + (aUri && aUri.spec) +
+ " aWhere=" + aWhere +
+ " aFlags=" + aFlags);
+
+ if (!this.isRegistered) {
+ return null;
+ }
+
+ const message = {
+ type: "GeckoView:OnNewSession",
+ uri: aUri ? aUri.displaySpec : ""
+ };
+
+ let browser = undefined;
+ this.eventDispatcher.sendRequestForResult(message).then(sessionId => {
+ return this.waitAndSetOpener(sessionId, aOpener);
+ }).then(window => {
+ browser = (window && window.browser);
+ });
+
+ // Wait indefinitely for app to respond with a browser or null
+ Services.tm.spinEventLoopUntil(() => browser !== undefined);
+ return browser;
+ }
+
// nsILoadURIDelegate.
loadURI(aUri, aWhere, aFlags, aTriggeringPrincipal) {
debug("loadURI " + aUri + " " + aWhere + " " + aFlags + " " +
aTriggeringPrincipal);
- let handled = this.handleLoadUri(aUri, null, aWhere, aFlags,
- aTriggeringPrincipal);
+ const handled = this.handleLoadUri(aUri, null, aWhere, aFlags,
+ aTriggeringPrincipal);
if (!handled) {
throw Cr.NS_ERROR_ABORT;
}
}
// nsIBrowserDOMWindow.
createContentWindow(aUri, aOpener, aWhere, aFlags, aTriggeringPrincipal) {
debug("createContentWindow: aUri=" + (aUri && aUri.spec) +
" aWhere=" + aWhere +
" aFlags=" + aFlags);
- let handled = this.handleLoadUri(aUri, aOpener, aWhere, aFlags,
- aTriggeringPrincipal);
- if (!handled &&
- (aWhere === Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW ||
- aWhere === Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW)) {
- return this.browser.contentWindow;
+ const browser = this.handleNewSession(aUri, aOpener, aWhere, aFlags,
+ aTriggeringPrincipal);
+ if (!browser) {
+ return null;
}
- throw Cr.NS_ERROR_ABORT;
+ return browser.contentWindow;
}
// nsIBrowserDOMWindow.
createContentWindowInFrame(aUri, aParams, aWhere, aFlags, aNextTabParentId,
aName) {
debug("createContentWindowInFrame: aUri=" + (aUri && aUri.spec) +
" aParams=" + aParams +
" aWhere=" + aWhere +
" aFlags=" + aFlags +
" aNextTabParentId=" + aNextTabParentId +
" aName=" + aName);
- let handled = this.handleLoadUri(aUri, null, aWhere, aFlags, null);
- if (!handled &&
- (aWhere === Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW ||
- aWhere === Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW)) {
- return this.browser;
+ const browser = this.handleNewSession(aUri, null, aWhere, aFlags, null);
+ if (browser) {
+ browser.setAttribute("nextTabParentId", aNextTabParentId);
}
- throw Cr.NS_ERROR_ABORT;
+ return browser;
}
// nsIBrowserDOMWindow.
openURI(aUri, aOpener, aWhere, aFlags, aTriggeringPrincipal) {
return this.createContentWindow(aUri, aOpener, aWhere, aFlags,
aTriggeringPrincipal);
}
// nsIBrowserDOMWindow.
openURIInFrame(aUri, aParams, aWhere, aFlags, aNextTabParentId, aName) {
return this.createContentWindowInFrame(aUri, aParams, aWhere, aFlags,
aNextTabParentId, aName);
}
// nsIBrowserDOMWindow.
isTabContentWindow(aWindow) {
- debug("isTabContentWindow " + this.browser.contentWindow === aWindow);
return this.browser.contentWindow === aWindow;
}
// nsIBrowserDOMWindow.
canClose() {
debug("canClose");
return false;
}
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -2349,20 +2349,21 @@ public:
typedef void SetterType;
typedef mozilla::jni::Args<
Window::Param,
mozilla::jni::Object::Param,
mozilla::jni::Object::Param,
mozilla::jni::Object::Param,
mozilla::jni::String::Param,
int32_t,
- bool> Args;
+ bool,
+ mozilla::jni::String::Param> Args;
static constexpr char name[] = "open";
static constexpr char signature[] =
- "(Lorg/mozilla/gecko/GeckoSession$Window;Lorg/mozilla/gecko/gfx/LayerSession$Compositor;Lorg/mozilla/gecko/EventDispatcher;Lorg/mozilla/gecko/util/GeckoBundle;Ljava/lang/String;IZ)V";
+ "(Lorg/mozilla/gecko/GeckoSession$Window;Lorg/mozilla/gecko/gfx/LayerSession$Compositor;Lorg/mozilla/gecko/EventDispatcher;Lorg/mozilla/gecko/util/GeckoBundle;Ljava/lang/String;IZLjava/lang/String;)V";
static const bool isStatic = true;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::PROXY;
};
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -277,17 +277,18 @@ public:
// Create and attach a window.
static void Open(const jni::Class::LocalRef& aCls,
GeckoSession::Window::Param aWindow,
jni::Object::Param aCompositor,
jni::Object::Param aDispatcher,
jni::Object::Param aSettings,
jni::String::Param aChromeURI,
int32_t aScreenId,
- bool aPrivateMode);
+ bool aPrivateMode,
+ jni::String::Param aId);
// Close and destroy the nsWindow.
void Close();
// Transfer this nsWindow to new GeckoSession objects.
void Transfer(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aCompositor,
jni::Object::Param aDispatcher,
@@ -1243,17 +1244,18 @@ nsWindow::GeckoViewSupport::~GeckoViewSu
/* static */ void
nsWindow::GeckoViewSupport::Open(const jni::Class::LocalRef& aCls,
GeckoSession::Window::Param aWindow,
jni::Object::Param aCompositor,
jni::Object::Param aDispatcher,
jni::Object::Param aSettings,
jni::String::Param aChromeURI,
int32_t aScreenId,
- bool aPrivateMode)
+ bool aPrivateMode,
+ jni::String::Param aId)
{
MOZ_ASSERT(NS_IsMainThread());
AUTO_PROFILER_LABEL("nsWindow::GeckoViewSupport::Open", OTHER);
nsCOMPtr<nsIWindowWatcher> ww = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
MOZ_RELEASE_ASSERT(ww);
@@ -1273,17 +1275,17 @@ nsWindow::GeckoViewSupport::Open(const j
java::EventDispatcher::Ref::From(aDispatcher), nullptr);
androidView->mSettings = java::GeckoBundle::Ref::From(aSettings);
nsAutoCString chromeFlags("chrome,dialog=0,resizable,scrollbars");
if (aPrivateMode) {
chromeFlags += ",private";
}
nsCOMPtr<mozIDOMWindowProxy> domWindow;
- ww->OpenWindow(nullptr, url.get(), nullptr, chromeFlags.get(),
+ ww->OpenWindow(nullptr, url.get(), aId->ToCString().get(), chromeFlags.get(),
androidView, getter_AddRefs(domWindow));
MOZ_RELEASE_ASSERT(domWindow);
nsCOMPtr<nsPIDOMWindowOuter> pdomWindow =
nsPIDOMWindowOuter::From(domWindow);
nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(pdomWindow);
MOZ_ASSERT(widget);