Commit f8cdd3cb authored by Peter E Conn's avatar Peter E Conn Committed by Commit Bot

📎 Call client provided intent when focus is requested.

For CCTs (and TWAs) to have a "bring tab to front" functionality, we
need an Intent provided by the client that will launch in the client's
Task.

The client should provide an Intent to an Activity that immediately
exits. This way the Task will be brought to the foreground with the
CustomTabActivity visible.

There are a few cases that this method breaks down. First, the client
may have another Activity on top of the Custom Tab - in this case that
Activity will be brought to the foreground instead. We deem this to
be acceptable as it is unlikely to happen often and still brings the
user into the context of the app. (Note that this method won't be
called if there is no currently running CustomTabActivity.)

Another case is that the client provides an Intent that does not
simply exit. There is little we can do to check for this case.

Bug: 989908
Change-Id: I8dc5384b4631c7a0c895114621e4810cffb21259
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1849682
Commit-Queue: Peter Conn <peconn@chromium.org>
Reviewed-by: default avatarPavel Shmakov <pshmakov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#711264}
parent f96e9281
......@@ -5,13 +5,17 @@
package org.chromium.chrome.browser.customtabs;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.PackageManagerUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.browser.ChromeActivity;
......@@ -155,20 +159,23 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
private static class CustomTabWebContentsDelegate
extends ActivityTabWebContentsDelegateAndroid {
private static final String TAG = "CustomTabWebContentsDelegate";
private final MultiWindowUtils mMultiWindowUtils;
private final boolean mShouldEnableEmbeddedMediaExperience;
private final boolean mIsTrustedWebActivity;
private final @Nullable PendingIntent mFocusIntent;
/**
* See {@link TabWebContentsDelegateAndroid}.
*/
public CustomTabWebContentsDelegate(Tab tab, ChromeActivity activity,
MultiWindowUtils multiWindowUtils, boolean shouldEnableEmbeddedMediaExperience,
boolean isTrustedWebActivity) {
boolean isTrustedWebActivity, @Nullable PendingIntent focusIntent) {
super(tab, activity);
mMultiWindowUtils = multiWindowUtils;
mShouldEnableEmbeddedMediaExperience = shouldEnableEmbeddedMediaExperience;
mIsTrustedWebActivity = isTrustedWebActivity;
mFocusIntent = focusIntent;
}
@Override
......@@ -178,7 +185,23 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
@Override
protected void bringActivityToForeground() {
// No-op here. If client's task is in background Chrome is unable to foreground it.
// super.bringActivityToForeground creates an Intent to ChromeLauncherActivity for the
// current Tab. This will then bring to the foreground the Chrome Task that contains
// the Chrome Activity displaying the tab (this will usually be a ChromeTabbedActivity).
// Since Custom Tabs will be launched as part of the client's Task, we can't launch a
// Chrome Intent specifically to the Chrome Activity in that Task. Therefore we must
// use an Intent the client has provided to bring its Task to the foreground.
// If we've not been provided with an Intent to focus the client's Task, we can't do
// anything.
if (mFocusIntent == null) return;
try {
mFocusIntent.send();
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "CanceledException when sending pending intent.");
}
}
@Override
......@@ -232,6 +255,7 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
private final BrowserControlsVisibilityDelegate mBrowserStateVisibilityDelegate;
private final ExternalAuthUtils mExternalAuthUtils;
private final MultiWindowUtils mMultiWindowUtils;
private final PendingIntent mFocusIntent;
private ExternalNavigationDelegateImpl mNavigationDelegate;
......@@ -243,12 +267,15 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
* @param shouldEnableEmbeddedMediaExperience Whether embedded media experience is enabled.
* @param visibilityDelegate The delegate that handles browser control visibility associated
* with browser actions (as opposed to tab state).
* @param authUtils To determine whether apps are Google signed.
* @param multiWindowUtils To use to determine which ChromeTabbedActivity to open new tabs in.
* @param focusIntent A PendingIntent to launch to focus the client.
*/
private CustomTabDelegateFactory(ChromeActivity activity, boolean shouldHideBrowserControls,
boolean isOpenedByChrome, boolean isTrustedWebActivity,
boolean shouldEnableEmbeddedMediaExperience,
BrowserControlsVisibilityDelegate visibilityDelegate, ExternalAuthUtils authUtils,
MultiWindowUtils multiWindowUtils) {
MultiWindowUtils multiWindowUtils, @Nullable PendingIntent focusIntent) {
mActivity = activity;
mShouldHideBrowserControls = shouldHideBrowserControls;
mIsOpenedByChrome = isOpenedByChrome;
......@@ -257,6 +284,7 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
mBrowserStateVisibilityDelegate = visibilityDelegate;
mExternalAuthUtils = authUtils;
mMultiWindowUtils = multiWindowUtils;
mFocusIntent = focusIntent;
}
@Inject
......@@ -269,7 +297,7 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
this(activity, intentDataProvider.shouldEnableUrlBarHiding(),
intentDataProvider.isOpenedByChrome(), intentDataProvider.isTrustedWebActivity(),
intentDataProvider.shouldEnableEmbeddedMediaExperience(), visibilityDelegate,
authUtils, multiWindowUtils);
authUtils, multiWindowUtils, intentDataProvider.getFocusIntent());
}
/**
......@@ -277,7 +305,8 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
* be replaced when the hidden Tab becomes shown.
*/
static CustomTabDelegateFactory createDummy() {
return new CustomTabDelegateFactory(null, false, false, false, false, null, null, null);
return new CustomTabDelegateFactory(
null, false, false, false, false, null, null, null, null);
}
@Override
......@@ -301,7 +330,7 @@ public class CustomTabDelegateFactory implements TabDelegateFactory {
@Override
public TabWebContentsDelegateAndroid createWebContentsDelegate(Tab tab) {
return new CustomTabWebContentsDelegate(tab, mActivity, mMultiWindowUtils,
mShouldEnableEmbeddedMediaExperience, mIsTrustedWebActivity);
mShouldEnableEmbeddedMediaExperience, mIsTrustedWebActivity, mFocusIntent);
}
@Override
......
......@@ -177,6 +177,13 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
private static final String EXTRA_TRANSLATE_LANGUAGE =
"androidx.browser.customtabs.extra.TRANSLATE_LANGUAGE";
/**
* Extra used to provide a PendingIntent that we can launch to focus the client.
* TODO(peconn): Move to AndroidX.
*/
private static final String EXTRA_FOCUS_INTENT =
"androidx.browser.customtabs.extra.FOCUS_INTENT";
private static final int MAX_CUSTOM_MENU_ITEMS = 5;
private static final int MAX_CUSTOM_TOOLBAR_ITEMS = 2;
......@@ -233,6 +240,7 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
private PendingIntent mRemoteViewsPendingIntent;
// OnFinished listener for PendingIntents. Used for testing only.
private PendingIntent.OnFinished mOnFinished;
private PendingIntent mFocusIntent;
/** Whether this CustomTabActivity was explicitly started by another Chrome Activity. */
private final boolean mIsOpenedByChrome;
......@@ -363,6 +371,7 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OPENED_BY_WEBAPK, false);
mTranslateLanguage = IntentUtils.safeGetStringExtra(intent, EXTRA_TRANSLATE_LANGUAGE);
mFocusIntent = IntentUtils.safeGetParcelableExtra(intent, EXTRA_FOCUS_INTENT);
String modulePackageName =
IntentUtils.safeGetStringExtra(intent, EXTRA_MODULE_PACKAGE_NAME);
......@@ -878,4 +887,9 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
return null;
}
}
@Nullable
public PendingIntent getFocusIntent() {
return mFocusIntent;
}
}
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