Commit 3c311875 authored by Peter E Conn's avatar Peter E Conn Committed by Commit Bot

🛃 Notify Custom Tab host when the user Opens in Browser.

Chrome Custom Tabs have a menu item allowing users to open that page in
their browser. Pass an extraCallback to the Custom Tab host to notify
them.

Bug: 806891
Change-Id: Ia67e8033d261f9be4735f446a3e5a96b58a24f6c
Reviewed-on: https://chromium-review.googlesource.com/890746
Commit-Queue: Peter Conn <peconn@chromium.org>
Reviewed-by: default avatarBernhard Bauer <bauerb@chromium.org>
Reviewed-by: default avatarBenoit L <lizeb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#533302}
parent f18cc9d3
...@@ -1020,8 +1020,10 @@ public class CustomTabActivity extends ChromeActivity { ...@@ -1020,8 +1020,10 @@ public class CustomTabActivity extends ChromeActivity {
RecordUserAction.record("MobileMenuAddToBookmarks"); RecordUserAction.record("MobileMenuAddToBookmarks");
return true; return true;
} else if (id == R.id.open_in_browser_id) { } else if (id == R.id.open_in_browser_id) {
openCurrentUrlInBrowser(false); if (openCurrentUrlInBrowser(false)) {
RecordUserAction.record("CustomTabsMenuOpenInChrome"); RecordUserAction.record("CustomTabsMenuOpenInChrome");
mConnection.notifyOpenInBrowser(mSession);
}
return true; return true;
} else if (id == R.id.info_menu_id) { } else if (id == R.id.info_menu_id) {
if (getTabModelSelector().getCurrentTab() == null) return false; if (getTabModelSelector().getCurrentTab() == null) return false;
......
...@@ -88,6 +88,8 @@ public class CustomTabsConnection { ...@@ -88,6 +88,8 @@ public class CustomTabsConnection {
@VisibleForTesting @VisibleForTesting
static final String PAGE_LOAD_METRICS_CALLBACK = "NavigationMetrics"; static final String PAGE_LOAD_METRICS_CALLBACK = "NavigationMetrics";
static final String BOTTOM_BAR_SCROLL_STATE_CALLBACK = "onBottomBarScrollStateChanged"; static final String BOTTOM_BAR_SCROLL_STATE_CALLBACK = "onBottomBarScrollStateChanged";
@VisibleForTesting
static final String OPEN_IN_BROWSER_CALLBACK = "onOpenInBrowser";
// For CustomTabs.SpeculationStatusOnStart, see tools/metrics/enums.xml. Append only. // For CustomTabs.SpeculationStatusOnStart, see tools/metrics/enums.xml. Append only.
private static final int SPECULATION_STATUS_ON_START_ALLOWED = 0; private static final int SPECULATION_STATUS_ON_START_ALLOWED = 0;
...@@ -1010,18 +1012,10 @@ public class CustomTabsConnection { ...@@ -1010,18 +1012,10 @@ public class CustomTabsConnection {
* @param hidden Whether the bottom bar is hidden or shown. * @param hidden Whether the bottom bar is hidden or shown.
*/ */
public void onBottomBarScrollStateChanged(CustomTabsSessionToken session, boolean hidden) { public void onBottomBarScrollStateChanged(CustomTabsSessionToken session, boolean hidden) {
if (!shouldSendBottomBarScrollStateForSession(session)) return;
CustomTabsCallback callback = mClientManager.getCallbackForSession(session);
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putBoolean("hidden", hidden); args.putBoolean("hidden", hidden);
try {
callback.extraCallback(BOTTOM_BAR_SCROLL_STATE_CALLBACK, args); if (safeExtraCallback(session, BOTTOM_BAR_SCROLL_STATE_CALLBACK, args) && mLogRequests) {
} catch (Exception e) {
// Pokemon exception handling, see below and crbug.com/517023.
return;
}
if (mLogRequests) {
logCallback("extraCallback(" + BOTTOM_BAR_SCROLL_STATE_CALLBACK + ")", hidden); logCallback("extraCallback(" + BOTTOM_BAR_SCROLL_STATE_CALLBACK + ")", hidden);
} }
} }
...@@ -1108,16 +1102,38 @@ public class CustomTabsConnection { ...@@ -1108,16 +1102,38 @@ public class CustomTabsConnection {
* should be a key specifying the metric name and the metric value as the value. * should be a key specifying the metric name and the metric value as the value.
*/ */
boolean notifyPageLoadMetrics(CustomTabsSessionToken session, Bundle args) { boolean notifyPageLoadMetrics(CustomTabsSessionToken session, Bundle args) {
if (safeExtraCallback(session, PAGE_LOAD_METRICS_CALLBACK, args)) {
logPageLoadMetricsCallback(args);
return true;
}
return false;
}
/**
* Notifies the application that the user has selected to open the page in their browser.
* @param session Session identifier.
* @return true if success. To protect Chrome exceptions in the client application are swallowed
* and false is returned.
*/
boolean notifyOpenInBrowser(CustomTabsSessionToken session) {
return safeExtraCallback(session, OPEN_IN_BROWSER_CALLBACK,
getExtrasBundleForNavigationEventForSession(session));
}
/**
* Wraps calling extraCallback in a try/catch so exceptions thrown by the host app don't crash
* Chrome. See https://crbug.com/517023.
*/
private boolean safeExtraCallback(CustomTabsSessionToken session, String callbackName,
Bundle args) {
CustomTabsCallback callback = mClientManager.getCallbackForSession(session); CustomTabsCallback callback = mClientManager.getCallbackForSession(session);
if (callback == null) return false; if (callback == null) return false;
try { try {
callback.extraCallback(PAGE_LOAD_METRICS_CALLBACK, args); callback.extraCallback(callbackName, args);
} catch (Exception e) { } catch (Exception e) {
// Pokemon exception handling, see above and crbug.com/517023.
return false; return false;
} }
logPageLoadMetricsCallback(args);
return true; return true;
} }
......
...@@ -678,8 +678,26 @@ public class CustomTabActivityTest { ...@@ -678,8 +678,26 @@ public class CustomTabActivityTest {
@Test @Test
@SmallTest @SmallTest
@RetryOnFailure @RetryOnFailure
public void testOpenInBrowser() throws InterruptedException { public void testOpenInBrowser() throws InterruptedException, TimeoutException {
mCustomTabActivityTestRule.startCustomTabActivityWithIntent(createMinimalCustomTabIntent()); // Augment the CustomTabsSession to catch the callback.
CallbackHelper callbackTriggered = new CallbackHelper();
CustomTabsSession session = bindWithCallback(new CustomTabsCallback() {
@Override
public void extraCallback(String callbackName, Bundle args) {
if (callbackName.equals(CustomTabsConnection.OPEN_IN_BROWSER_CALLBACK)) {
callbackTriggered.notifyCalled();
}
}
});
Intent intent = new CustomTabsIntent.Builder(session).build().intent;
intent.setData(Uri.parse(mTestPage));
intent.setComponent(new ComponentName(
InstrumentationRegistry.getTargetContext(), ChromeLauncherActivity.class));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mCustomTabActivityTestRule.startCustomTabActivityWithIntent(intent);
IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW); IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
filter.addDataScheme(Uri.parse(mTestServer.getURL("/")).getScheme()); filter.addDataScheme(Uri.parse(mTestServer.getURL("/")).getScheme());
final ActivityMonitor monitor = final ActivityMonitor monitor =
...@@ -702,6 +720,8 @@ public class CustomTabActivityTest { ...@@ -702,6 +720,8 @@ public class CustomTabActivityTest {
return InstrumentationRegistry.getInstrumentation().checkMonitorHit(monitor, 1); return InstrumentationRegistry.getInstrumentation().checkMonitorHit(monitor, 1);
} }
}); });
callbackTriggered.waitForCallback(0);
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment