Bug 1474454 - Use GeckoResult in GeckoSession.NavigationDelegate.onNewSession() r=jchen,droeh
MozReview-Commit-ID: E59Scu8tnuq
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
@@ -636,18 +636,17 @@ public class CustomTabsActivity extends
Log.w(LOGTAG, "No activity handler found for: " + urlStr);
}
}
return GeckoResult.fromValue(true);
}
@Override
- public void onNewSession(final GeckoSession session, final String uri,
- final GeckoResponse<GeckoSession> response) {
+ public GeckoResult<GeckoSession> onNewSession(final GeckoSession session, final String uri) {
// We should never get here because we abort loads that need a new session in onLoadRequest()
throw new IllegalStateException("Unexpected new session");
}
/* GeckoSession.ProgressDelegate */
@Override
public void onPageStart(GeckoSession session, String url) {
mCurrentUrl = url;
--- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
@@ -430,18 +430,17 @@ public class WebAppActivity extends AppC
Log.w(LOGTAG, "No activity handler found for: " + urlStr);
}
}
return GeckoResult.fromValue(true);
}
@Override
- public void onNewSession(final GeckoSession session, final String uri,
- final GeckoResponse<GeckoSession> response) {
+ public GeckoResult<GeckoSession> onNewSession(final GeckoSession session, final String uri) {
// We should never get here because we abort loads that need a new session in onLoadRequest()
throw new IllegalStateException("Unexpected new session");
}
private void updateFullScreen() {
boolean fullScreen = mIsFullScreenContent || mIsFullScreenMode;
if (ActivityUtils.isFullScreen(this) == fullScreen) {
return;
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/ContentDelegateTest.kt
@@ -44,17 +44,18 @@ class ContentDelegateTest : BaseSessionT
@AssertCalled(count = 2)
override fun onLoadRequest(session: GeckoSession, uri: String,
where: Int, flags: Int): GeckoResult<Boolean> {
return GeckoResult.fromValue(false)
}
@AssertCalled(false)
- override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
+ return null
}
@AssertCalled(count = 1)
override fun onExternalResponse(session: GeckoSession, response: GeckoSession.WebResponseInfo) {
assertThat("Uri should start with data:", response.uri, startsWith("data:"))
assertThat("Content type should match", response.contentType, equalTo("text/plain"))
assertThat("Content length should be non-zero", response.contentLength, greaterThan(0L))
assertThat("Filename should match", response.filename, equalTo("download.txt"))
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt
@@ -13,16 +13,17 @@ import org.mozilla.geckoview.test.rule.G
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.ReuseSession
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.Setting
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDevToolsAPI
import org.mozilla.geckoview.test.util.Callbacks
import android.support.test.filters.MediumTest
import android.support.test.runner.AndroidJUnit4
import org.hamcrest.Matchers.*
+import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.geckoview.GeckoResult
@RunWith(AndroidJUnit4::class)
@MediumTest
@ReuseSession(false)
class NavigationDelegateTest : BaseSessionTest() {
@@ -127,18 +128,18 @@ class NavigationDelegateTest : BaseSessi
@AssertCalled(count = 1, order = [2])
override fun onCanGoForward(session: GeckoSession, canGoForward: Boolean) {
assertThat("Session should not be null", session, notNullValue())
assertThat("Cannot go forward", canGoForward, equalTo(false))
}
@AssertCalled(false)
- override fun onNewSession(session: GeckoSession, uri: String,
- response: GeckoResponse<GeckoSession>) {
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
+ return null
}
})
}
@Test fun load_dataUri() {
val dataUrl = "data:,Hello%2C%20World!"
sessionRule.session.loadUri(dataUrl);
sessionRule.waitForPageStop();
@@ -313,18 +314,18 @@ class NavigationDelegateTest : BaseSessi
}
@AssertCalled(count = 1, order = [2])
override fun onCanGoForward(session: GeckoSession, canGoForward: Boolean) {
assertThat("Cannot go forward", canGoForward, equalTo(false))
}
@AssertCalled(false)
- override fun onNewSession(session: GeckoSession, uri: String,
- response: GeckoResponse<GeckoSession>) {
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
+ return null
}
})
}
@Test fun goBackAndForward() {
sessionRule.session.loadTestPath(HELLO_HTML_PATH)
sessionRule.waitForPageStop()
@@ -362,18 +363,18 @@ class NavigationDelegateTest : BaseSessi
}
@AssertCalled(count = 1, order = [2])
override fun onCanGoForward(session: GeckoSession, canGoForward: Boolean) {
assertThat("Can go forward", canGoForward, equalTo(true))
}
@AssertCalled(false)
- override fun onNewSession(session: GeckoSession, uri: String,
- response: GeckoResponse<GeckoSession>) {
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
+ return null
}
})
sessionRule.session.goForward()
sessionRule.waitForPageStop()
sessionRule.forCallbacksDuringWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1, order = [1])
@@ -396,18 +397,18 @@ class NavigationDelegateTest : BaseSessi
}
@AssertCalled(count = 1, order = [2])
override fun onCanGoForward(session: GeckoSession, canGoForward: Boolean) {
assertThat("Cannot go forward", canGoForward, equalTo(false))
}
@AssertCalled(false)
- override fun onNewSession(session: GeckoSession, uri: String,
- response: GeckoResponse<GeckoSession>) {
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
+ return null
}
})
}
@Test fun onLoadUri_returnTrueCancelsLoad() {
sessionRule.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 2)
override fun onLoadRequest(session: GeckoSession, uri: String,
@@ -449,18 +450,19 @@ class NavigationDelegateTest : BaseSessi
where: Int, flags: Int): GeckoResult<Boolean> {
assertThat("URI should be correct", uri, endsWith(NEW_SESSION_CHILD_HTML_PATH))
assertThat("Where should be correct", where,
equalTo(GeckoSession.NavigationDelegate.TARGET_WINDOW_NEW))
return GeckoResult.fromValue(false)
}
@AssertCalled(count = 1, order = [2])
- override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
assertThat("URI should be correct", uri, endsWith(NEW_SESSION_CHILD_HTML_PATH))
+ return null
}
})
}
@WithDevToolsAPI
@Test fun onNewSession_calledForTargetBlankLink() {
// Disable popup blocker.
sessionRule.setPrefsUntilTestEnd(mapOf("dom.disable_open_during_load" to false))
@@ -478,29 +480,30 @@ class NavigationDelegateTest : BaseSessi
where: Int, flags: Int): GeckoResult<Boolean> {
assertThat("URI should be correct", uri, endsWith(NEW_SESSION_CHILD_HTML_PATH))
assertThat("Where should be correct", where,
equalTo(GeckoSession.NavigationDelegate.TARGET_WINDOW_NEW))
return GeckoResult.fromValue(false)
}
@AssertCalled(count = 1, order = [2])
- override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
assertThat("URI should be correct", uri, endsWith(NEW_SESSION_CHILD_HTML_PATH))
+ return null
}
})
}
private fun delegateNewSession(): GeckoSession {
val newSession = sessionRule.createClosedSession()
sessionRule.session.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1)
- override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
- response.respond(newSession)
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession> {
+ return GeckoResult.fromValue(newSession)
}
})
return newSession
}
@WithDevToolsAPI
@Test fun onNewSession_childShouldLoad() {
@@ -587,34 +590,36 @@ class NavigationDelegateTest : BaseSessi
override fun onLoadRequest(session: GeckoSession, uri: String,
where: Int, flags: Int): GeckoResult<Boolean> {
assertThat("URI must match", uri,
endsWith(forEachCall(NEW_SESSION_CHILD_HTML_PATH, NEW_SESSION_HTML_PATH)))
return GeckoResult.fromValue(false)
}
@AssertCalled(count = 0)
- override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
+ return null
}
})
}
@WithDevToolsAPI
@Test(expected = IllegalArgumentException::class)
+ @Ignore // FIXME: Bug 1474450
fun onNewSession_doesNotAllowOpened() {
// Disable popup blocker.
sessionRule.setPrefsUntilTestEnd(mapOf("dom.disable_open_during_load" to false))
sessionRule.session.loadTestPath(NEW_SESSION_HTML_PATH)
sessionRule.session.waitForPageStop()
sessionRule.session.delegateDuringNextWait(object : Callbacks.NavigationDelegate {
@AssertCalled(count = 1)
- override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
- response.respond(sessionRule.createOpenSession())
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession> {
+ return GeckoResult.fromValue(sessionRule.createOpenSession())
}
})
sessionRule.session.evaluateJS("$('#targetBlankLink').click()")
sessionRule.session.waitUntilCalled(GeckoSession.NavigationDelegate::class,
"onNewSession")
}
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestRunnerActivity.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/TestRunnerActivity.java
@@ -53,18 +53,18 @@ public class TestRunnerActivity extends
@Override
public GeckoResult<Boolean> onLoadRequest(GeckoSession session, String uri, int target,
int flags) {
// Allow Gecko to load all URIs
return GeckoResult.fromValue(false);
}
@Override
- public void onNewSession(GeckoSession session, String uri, GeckoResponse<GeckoSession> response) {
- response.respond(createBackgroundSession(session.getSettings()));
+ public GeckoResult<GeckoSession> onNewSession(GeckoSession session, String uri) {
+ return GeckoResult.fromValue(createBackgroundSession(session.getSettings()));
}
};
private GeckoSession.ContentDelegate mContentDelegate = new GeckoSession.ContentDelegate() {
@Override
public void onTitleChange(GeckoSession session, String title) {
}
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/rule/GeckoSessionTestRule.java
@@ -107,17 +107,17 @@ public class GeckoSessionTestRule extend
static {
try {
sOnPageStart = GeckoSession.ProgressDelegate.class.getMethod(
"onPageStart", GeckoSession.class, String.class);
sOnPageStop = GeckoSession.ProgressDelegate.class.getMethod(
"onPageStop", GeckoSession.class, boolean.class);
sOnNewSession = GeckoSession.NavigationDelegate.class.getMethod(
- "onNewSession", GeckoSession.class, String.class, GeckoResponse.class);
+ "onNewSession", GeckoSession.class, String.class);
sOnCrash = GeckoSession.ContentDelegate.class.getMethod(
"onCrash", GeckoSession.class);
} catch (final NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
/**
@@ -1177,44 +1177,69 @@ public class GeckoSessionTestRule extend
}
if (isExternalDelegate) {
assertThat("External delegate should be registered",
call, notNullValue());
}
}
- if (call != null && sOnNewSession.equals(method)) {
- // We're delegating an onNewSession call.
- // Make sure we wait on the newly opened session, if any.
- final GeckoSession oldSession = (GeckoSession) args[0];
- @SuppressWarnings("unchecked")
- final GeckoResponse<GeckoSession> realResponse =
- (GeckoResponse<GeckoSession>) args[2];
- args[2] = new GeckoResponse<GeckoSession>() {
- @Override
- public void respond(final GeckoSession newSession) {
- realResponse.respond(newSession);
- // `realResponse` has opened the session at this point, so wait on it.
- if (oldSession.isOpen() && newSession != null) {
- GeckoSessionTestRule.this.waitForOpenSession(newSession);
- }
- }
- };
- }
-
+ Object returnValue = null;
try {
mCurrentMethodCall = call;
- return method.invoke((call != null) ? call.target
+ returnValue = method.invoke((call != null) ? call.target
: Callbacks.Default.INSTANCE, args);
} catch (final IllegalAccessException | InvocationTargetException e) {
throw unwrapRuntimeException(e);
} finally {
mCurrentMethodCall = null;
}
+
+ if (call != null && returnValue != null && sOnNewSession.equals(method)) {
+ // We're delegating an onNewSession call.
+ // Make sure we wait on the newly opened session, if any.
+ @SuppressWarnings("unchecked")
+ final GeckoSession oldSession = (GeckoSession) args[0];
+
+ @SuppressWarnings("unchecked")
+ final GeckoResult<GeckoSession> result = (GeckoResult<GeckoSession>)returnValue;
+ if (oldSession.isOpen() && result != null) {
+ final GeckoResult<GeckoSession> tmpResult = new GeckoResult<>();
+ result.then(new OnValueListener<GeckoSession, Void>() {
+ @Override
+ public GeckoResult<Void> onValue(final GeckoSession newSession) throws Throwable {
+ tmpResult.complete(newSession);
+
+ // GeckoSession has already hooked up its then() listener earlier,
+ // so ours will run after. We can wait for the session to
+ // open here.
+ tmpResult.then(new OnValueListener<GeckoSession, Void>() {
+ @Override
+ public GeckoResult<Void> onValue(GeckoSession newSession) throws Throwable {
+ if (newSession != null) {
+ waitForOpenSession(newSession);
+ }
+ return null;
+ }
+ });
+ return null;
+ }
+ }, new OnExceptionListener<Void>() {
+ @Override
+ public GeckoResult<Void> onException(Throwable exception) throws Throwable {
+ tmpResult.completeExceptionally(exception);
+ return null;
+ }
+ });
+
+ return tmpResult;
+ }
+ }
+
+ return returnValue;
}
};
final Class<?>[] classes = DEFAULT_DELEGATES.toArray(
new Class<?>[DEFAULT_DELEGATES.size()]);
mCallbackProxy = Proxy.newProxyInstance(GeckoSession.class.getClassLoader(),
classes, recorder);
mAllDelegates = new HashSet<>(DEFAULT_DELEGATES);
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/Callbacks.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/util/Callbacks.kt
@@ -53,18 +53,18 @@ class Callbacks private constructor() {
override fun onCanGoForward(session: GeckoSession, canGoForward: Boolean) {
}
override fun onLoadRequest(session: GeckoSession, uri: String, where: Int,
flags: Int): GeckoResult<Boolean> {
return GeckoResult.fromValue(false)
}
- override fun onNewSession(session: GeckoSession, uri: String, response: GeckoResponse<GeckoSession>) {
- response.respond(null)
+ override fun onNewSession(session: GeckoSession, uri: String): GeckoResult<GeckoSession>? {
+ return null;
}
}
interface PermissionDelegate : GeckoSession.PermissionDelegate {
override fun onAndroidPermissionsRequest(session: GeckoSession, permissions: Array<out String>, callback: GeckoSession.PermissionDelegate.Callback) {
callback.reject()
}
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -224,37 +224,50 @@ public class GeckoSession extends LayerS
@Override
public GeckoResult<Void> onException(Throwable exception) throws Throwable {
callback.sendError(exception.getMessage());
return null;
}
});
} else if ("GeckoView:OnNewSession".equals(event)) {
final String uri = message.getString("uri");
- delegate.onNewSession(GeckoSession.this, uri,
- new GeckoResponse<GeckoSession>() {
- @Override
- public void respond(GeckoSession session) {
- if (session == null) {
- callback.sendSuccess(null);
- return;
- }
-
- if (session.isOpen()) {
- throw new IllegalArgumentException("Must use an unopened GeckoSession instance");
- }
-
- if (GeckoSession.this.mWindow == null) {
- callback.sendError("Session is not attached to a window");
- } else {
- session.open(GeckoSession.this.mWindow.runtime);
- callback.sendSuccess(session.getId());
- }
+ final GeckoResult<GeckoSession> result = delegate.onNewSession(GeckoSession.this, uri);
+ if (result == null) {
+ callback.sendSuccess(null);
+ return;
+ }
+
+ result.then(new GeckoResult.OnValueListener<GeckoSession, Void>() {
+ @Override
+ public GeckoResult<Void> onValue(GeckoSession session) throws Throwable {
+ if (session == null) {
+ callback.sendSuccess(null);
+ return null;
+ }
+
+ if (session.isOpen()) {
+ throw new IllegalArgumentException("Must use an unopened GeckoSession instance");
}
- });
+
+ if (GeckoSession.this.mWindow == null) {
+ callback.sendError("Session is not attached to a window");
+ } else {
+ session.open(GeckoSession.this.mWindow.runtime);
+ callback.sendSuccess(session.getId());
+ }
+
+ return null;
+ }
+ }, new GeckoResult.OnExceptionListener<Void>() {
+ @Override
+ public GeckoResult<Void> onException(Throwable exception) throws Throwable {
+ callback.sendError(exception.getMessage());
+ return null;
+ }
+ });
}
}
};
private final GeckoSessionHandler<ProgressDelegate> mProgressHandler =
new GeckoSessionHandler<ProgressDelegate>(
"GeckoViewProgress", this,
new String[]{
@@ -2169,19 +2182,19 @@ public class GeckoSession extends LayerS
/**
* 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
+ * @return A {@link GeckoResult} which holds the returned GeckoSession. May be null.
*/
- void onNewSession(GeckoSession session, String uri, GeckoResponse<GeckoSession> response);
+ GeckoResult<GeckoSession> onNewSession(GeckoSession session, String uri);
}
/**
* 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
@@ -565,27 +565,28 @@ public class GeckoViewActivity extends A
public GeckoResult<Boolean> onLoadRequest(final GeckoSession session, final String uri,
final int target, final int flags) {
Log.d(LOGTAG, "onLoadRequest=" + uri + " where=" + target +
" flags=" + flags);
return GeckoResult.fromValue(false);
}
@Override
- public void onNewSession(final GeckoSession session, final String uri, GeckoResponse<GeckoSession> response) {
+ public GeckoResult<GeckoSession> onNewSession(final GeckoSession session, final String uri) {
GeckoSession newSession = new GeckoSession(session.getSettings());
- response.respond(newSession);
Intent intent = new Intent(GeckoViewActivity.this, SessionActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(uri));
intent.putExtra("session", newSession);
startActivity(intent);
+
+ return GeckoResult.fromValue(newSession);
}
}
private class ExampleTrackingProtectionDelegate implements GeckoSession.TrackingProtectionDelegate {
private int mBlockedAds = 0;
private int mBlockedAnalytics = 0;
private int mBlockedSocial = 0;
private int mBlockedContent = 0;