Commit 5d35578a authored by Rohit Agarwal's avatar Rohit Agarwal Committed by Commit Bot

Change the incognito CCT overflow menu.

This CL changes the CCT overflow menu as follows:

1. The top action icon buttons in the toolbar would be always fixed
i.e non customisable to:

  a) Forward
  b) Page Info
  c) Refresh only
  d) Bookmarks

2. The menu items in the toolbar would be always fixed i.e non
customisable to:

  a) Find in page
  b) Desktop site
  c) Translate
  d) Share (this would be hidden by default, unless specified.)

This CL also adds instrumentation tests and refactors some code out
from CustomTabActivityTest to CustomTabsTestUtils which was needed
to avoid duplication in the CustomTabActivityIncognitoTest.

Bug: 1104180
Change-Id: I6c3d44cd3a32b7437a67bac0c66f894e4d2d62ac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2338935
Commit-Queue: Rohit Agarwal <roagarwal@chromium.org>
Reviewed-by: default avatarPeter Conn <peconn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797356}
parent 7037fb45
...@@ -460,6 +460,7 @@ chrome_java_sources = [ ...@@ -460,6 +460,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java", "java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java",
"java/src/org/chromium/chrome/browser/customtabs/FirstMeaningfulPaintObserver.java", "java/src/org/chromium/chrome/browser/customtabs/FirstMeaningfulPaintObserver.java",
"java/src/org/chromium/chrome/browser/customtabs/HiddenTabHolder.java", "java/src/org/chromium/chrome/browser/customtabs/HiddenTabHolder.java",
"java/src/org/chromium/chrome/browser/customtabs/IncognitoCustomTabIntentDataProvider.java",
"java/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTrigger.java", "java/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTrigger.java",
"java/src/org/chromium/chrome/browser/customtabs/PageLoadMetricsObserver.java", "java/src/org/chromium/chrome/browser/customtabs/PageLoadMetricsObserver.java",
"java/src/org/chromium/chrome/browser/customtabs/PaymentHandlerActivity.java", "java/src/org/chromium/chrome/browser/customtabs/PaymentHandlerActivity.java",
......
...@@ -198,6 +198,9 @@ public class CustomTabActivity extends BaseCustomTabActivity { ...@@ -198,6 +198,9 @@ public class CustomTabActivity extends BaseCustomTabActivity {
@Override @Override
protected BrowserServicesIntentDataProvider buildIntentDataProvider( protected BrowserServicesIntentDataProvider buildIntentDataProvider(
Intent intent, @CustomTabsIntent.ColorScheme int colorScheme) { Intent intent, @CustomTabsIntent.ColorScheme int colorScheme) {
if (IncognitoCustomTabIntentDataProvider.isValidIncognitoIntent(intent)) {
return new IncognitoCustomTabIntentDataProvider(intent, this, colorScheme);
}
return new CustomTabIntentDataProvider(intent, this, colorScheme); return new CustomTabIntentDataProvider(intent, this, colorScheme);
} }
......
...@@ -174,6 +174,8 @@ public class CustomTabAppMenuPropertiesDelegate extends AppMenuPropertiesDelegat ...@@ -174,6 +174,8 @@ public class CustomTabAppMenuPropertiesDelegate extends AppMenuPropertiesDelegat
if (mIsIncognito) { if (mIsIncognito) {
addToHomeScreenVisible = false; addToHomeScreenVisible = false;
downloadItemVisible = false;
openInChromeItemVisible = false;
} }
boolean isChromeScheme = url.startsWith(UrlConstants.CHROME_URL_PREFIX) boolean isChromeScheme = url.startsWith(UrlConstants.CHROME_URL_PREFIX)
......
...@@ -79,12 +79,12 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid ...@@ -79,12 +79,12 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
*/ */
public static final String EXTRA_KEEP_ALIVE = "android.support.customtabs.extra.KEEP_ALIVE"; public static final String EXTRA_KEEP_ALIVE = "android.support.customtabs.extra.KEEP_ALIVE";
private static final String ANIMATION_BUNDLE_PREFIX = public static final String ANIMATION_BUNDLE_PREFIX =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? "android:activity." : "android:"; Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? "android:activity." : "android:";
private static final String BUNDLE_PACKAGE_NAME = ANIMATION_BUNDLE_PREFIX + "packageName"; public static final String BUNDLE_PACKAGE_NAME = ANIMATION_BUNDLE_PREFIX + "packageName";
private static final String BUNDLE_ENTER_ANIMATION_RESOURCE = public static final String BUNDLE_ENTER_ANIMATION_RESOURCE =
ANIMATION_BUNDLE_PREFIX + "animEnterRes"; ANIMATION_BUNDLE_PREFIX + "animEnterRes";
private static final String BUNDLE_EXIT_ANIMATION_RESOURCE = public static final String BUNDLE_EXIT_ANIMATION_RESOURCE =
ANIMATION_BUNDLE_PREFIX + "animExitRes"; ANIMATION_BUNDLE_PREFIX + "animExitRes";
/** /**
...@@ -179,7 +179,6 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid ...@@ -179,7 +179,6 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
private final Integer mNavigationBarColor; private final Integer mNavigationBarColor;
@Nullable @Nullable
private final Integer mNavigationBarDividerColor; private final Integer mNavigationBarDividerColor;
private final boolean mIsIncognito;
@Nullable @Nullable
private final List<String> mTrustedWebActivityAdditionalOrigins; private final List<String> mTrustedWebActivityAdditionalOrigins;
@Nullable @Nullable
...@@ -276,15 +275,10 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid ...@@ -276,15 +275,10 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
IntentUtils.safeGetIntExtra(intent, EXTRA_UI_TYPE, CustomTabsUiType.DEFAULT); IntentUtils.safeGetIntExtra(intent, EXTRA_UI_TYPE, CustomTabsUiType.DEFAULT);
mUiType = verifiedUiType(requestedUiType); mUiType = verifiedUiType(requestedUiType);
// TODO(https://crbug.com/1023759): WARNING: Current implementation uses
// a common off-the-record profile with browser's incognito mode and is
// not privacy-safe.
mIsIncognito = isValidIncognitoIntent(intent);
CustomTabColorSchemeParams params = getColorSchemeParams(intent, colorScheme); CustomTabColorSchemeParams params = getColorSchemeParams(intent, colorScheme);
retrieveCustomButtons(intent, context); retrieveCustomButtons(intent, context);
retrieveToolbarColor(params, context); mToolbarColor = retrieveToolbarColor(params, context);
retrieveBottomBarColor(params); mBottomBarColor = retrieveBottomBarColor(params);
mNavigationBarColor = params.navigationBarColor == null mNavigationBarColor = params.navigationBarColor == null
? null ? null
: ColorUtils.getOpaqueColor(params.navigationBarColor); : ColorUtils.getOpaqueColor(params.navigationBarColor);
...@@ -310,17 +304,8 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid ...@@ -310,17 +304,8 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
List<Bundle> menuItems = List<Bundle> menuItems =
IntentUtils.getParcelableArrayListExtra(intent, CustomTabsIntent.EXTRA_MENU_ITEMS); IntentUtils.getParcelableArrayListExtra(intent, CustomTabsIntent.EXTRA_MENU_ITEMS);
if (menuItems != null) {
for (int i = 0; i < Math.min(MAX_CUSTOM_MENU_ITEMS, menuItems.size()); i++) { updateExtraMenuItems(menuItems);
Bundle bundle = menuItems.get(i);
String title =
IntentUtils.safeGetString(bundle, CustomTabsIntent.KEY_MENU_ITEM_TITLE);
PendingIntent pendingIntent =
IntentUtils.safeGetParcelable(bundle, CustomTabsIntent.KEY_PENDING_INTENT);
if (TextUtils.isEmpty(title) || pendingIntent == null) continue;
mMenuEntries.add(new Pair<String, PendingIntent>(title, pendingIntent));
}
}
mActivityType = IntentUtils.safeGetBooleanExtra( mActivityType = IntentUtils.safeGetBooleanExtra(
intent, TrustedWebUtils.EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY, false) intent, TrustedWebUtils.EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY, false)
...@@ -364,6 +349,18 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid ...@@ -364,6 +349,18 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
mGsaExperimentIds = IntentUtils.safeGetIntArrayExtra(intent, EXPERIMENT_IDS); mGsaExperimentIds = IntentUtils.safeGetIntArrayExtra(intent, EXPERIMENT_IDS);
} }
private void updateExtraMenuItems(List<Bundle> menuItems) {
if (menuItems == null) return;
for (int i = 0; i < Math.min(MAX_CUSTOM_MENU_ITEMS, menuItems.size()); i++) {
Bundle bundle = menuItems.get(i);
String title = IntentUtils.safeGetString(bundle, CustomTabsIntent.KEY_MENU_ITEM_TITLE);
PendingIntent pendingIntent =
IntentUtils.safeGetParcelable(bundle, CustomTabsIntent.KEY_PENDING_INTENT);
if (TextUtils.isEmpty(title) || pendingIntent == null) continue;
mMenuEntries.add(new Pair<String, PendingIntent>(title, pendingIntent));
}
}
/** /**
* Triggers the client-defined action when the user clicks a custom menu item. * Triggers the client-defined action when the user clicks a custom menu item.
* @param activity The {@link ChromeActivity} to use for sending the {@link PendingIntent}. * @param activity The {@link ChromeActivity} to use for sending the {@link PendingIntent}.
...@@ -416,28 +413,6 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid ...@@ -416,28 +413,6 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
} }
} }
// TODO(https://crbug.com/1023759): Remove this function and enable
// incognito CCT request for all apps.
private boolean isValidIncognitoIntent(Intent intent) {
if (!isIncognitoRequested(intent)) return false;
// Incognito requests for payments flow are supported without
// INCOGNITO_CCT flag as an exceptional case that can use Chrome
// incognito profile.
if (isForPaymentsFlow(intent)) return true;
assert ChromeFeatureList.isInitialized();
return ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_INCOGNITO);
}
private boolean isForPaymentsFlow(Intent intent) {
return isIncognitoRequested(intent) && isTrustedIntent() && isOpenedByChrome()
&& isForPaymentRequest();
}
private static boolean isIncognitoRequested(Intent intent) {
return IntentUtils.safeGetBooleanExtra(
intent, IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, false);
}
/** /**
* Get the verified UI type, according to the intent extras, and whether the intent is trusted. * Get the verified UI type, according to the intent extras, and whether the intent is trusted.
* @param requestedUiType requested UI type in the intent, unqualified * @param requestedUiType requested UI type in the intent, unqualified
...@@ -481,31 +456,24 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid ...@@ -481,31 +456,24 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
} }
/** /**
* Processes the color passed from the client app and updates {@link #mToolbarColor}. * Returns the color passed from the client app.
*/ */
private void retrieveToolbarColor(CustomTabColorSchemeParams schemeParams, Context context) { private int retrieveToolbarColor(CustomTabColorSchemeParams schemeParams, Context context) {
int defaultColor = ChromeColors.getDefaultThemeColor(context.getResources(), isIncognito()); int defaultColor = ChromeColors.getDefaultThemeColor(
if (isIncognito()) { context.getResources(), /*forceDarkBgColor*/ false);
mToolbarColor = defaultColor;
return; // Don't allow toolbar color customization for incognito tabs.
}
mHasCustomToolbarColor = (schemeParams.toolbarColor != null); mHasCustomToolbarColor = (schemeParams.toolbarColor != null);
int color = mHasCustomToolbarColor ? schemeParams.toolbarColor : defaultColor; int color = mHasCustomToolbarColor ? schemeParams.toolbarColor : defaultColor;
mToolbarColor = ColorUtils.getOpaqueColor(color); return ColorUtils.getOpaqueColor(color);
} }
/** /**
* Must be called after calling {@link #retrieveToolbarColor}. * Must be called after calling {@link #retrieveToolbarColor}.
*/ */
private void retrieveBottomBarColor(CustomTabColorSchemeParams schemeParams) { private int retrieveBottomBarColor(CustomTabColorSchemeParams schemeParams) {
if (isIncognito()) {
mBottomBarColor = mToolbarColor;
return;
}
int defaultColor = mToolbarColor; int defaultColor = mToolbarColor;
int color = schemeParams.secondaryToolbarColor != null ? schemeParams.secondaryToolbarColor int color = schemeParams.secondaryToolbarColor != null ? schemeParams.secondaryToolbarColor
: defaultColor; : defaultColor;
mBottomBarColor = ColorUtils.getOpaqueColor(color); return ColorUtils.getOpaqueColor(color);
} }
/** /**
...@@ -796,7 +764,7 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid ...@@ -796,7 +764,7 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
@Override @Override
public boolean isIncognito() { public boolean isIncognito() {
return mIsIncognito; return false;
} }
@Nullable @Nullable
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.customtabs;
import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.BUNDLE_ENTER_ANIMATION_RESOURCE;
import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.BUNDLE_EXIT_ANIMATION_RESOURCE;
import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.BUNDLE_PACKAGE_NAME;
import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_CHROME;
import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.EXTRA_UI_TYPE;
import static org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.isTrustedCustomTab;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.browser.customtabs.CustomTabsSessionToken;
import org.chromium.base.IntentUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.flags.ActivityType;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.browser_ui.widget.TintedDrawable;
/**
* A model class that parses the incoming intent for incognito Custom Tabs specific customization
* data.
*
* Lifecycle: is activity-scoped, i.e. one instance per CustomTabActivity instance. Must be
* re-created when color scheme changes, which happens automatically since color scheme change leads
* to activity re-creation.
*/
public class IncognitoCustomTabIntentDataProvider extends BrowserServicesIntentDataProvider {
private final Intent mIntent;
private final CustomTabsSessionToken mSession;
private final boolean mIsTrustedIntent;
private final Bundle mAnimationBundle;
@Nullable
private final String mUrlToLoad;
private final int mToolbarColor;
private final int mBottomBarColor;
private final Drawable mCloseButtonIcon;
private final boolean mShowShareItem;
/** Whether this CustomTabActivity was explicitly started by another Chrome Activity. */
private final boolean mIsOpenedByChrome;
/**
* Constructs a {@link IncognitoCustomTabIntentDataProvider}.
* Incognito CCT would have a fix color scheme.
*/
public IncognitoCustomTabIntentDataProvider(Intent intent, Context context, int colorScheme) {
assert intent != null;
mIntent = intent;
mUrlToLoad = resolveUrlToLoad(intent);
mSession = CustomTabsSessionToken.getSessionTokenFromIntent(intent);
mIsTrustedIntent = isTrustedCustomTab(intent, mSession);
mAnimationBundle = IntentUtils.safeGetBundleExtra(
intent, CustomTabsIntent.EXTRA_EXIT_ANIMATION_BUNDLE);
mIsOpenedByChrome =
IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OPENED_BY_CHROME, false);
mToolbarColor = ChromeColors.getDefaultThemeColor(
context.getResources(), /*forceDarkBgColor*/ true);
mBottomBarColor = ChromeColors.getDefaultThemeColor(
context.getResources(), /*forceDarkBgColor*/ true);
mCloseButtonIcon = TintedDrawable.constructTintedDrawable(context, R.drawable.btn_close);
mShowShareItem = IntentUtils.safeGetBooleanExtra(
intent, CustomTabsIntent.EXTRA_DEFAULT_SHARE_MENU_ITEM, false);
}
private static boolean isIncognitoRequested(Intent intent) {
return IntentUtils.safeGetBooleanExtra(
intent, IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, false);
}
private static boolean isForPaymentsFlow(Intent intent) {
CustomTabsSessionToken session = CustomTabsSessionToken.getSessionTokenFromIntent(intent);
boolean isOpenedByChrome =
IntentUtils.safeGetBooleanExtra(intent, EXTRA_IS_OPENED_BY_CHROME, false);
final int requestedUiType =
IntentUtils.safeGetIntExtra(intent, EXTRA_UI_TYPE, CustomTabsUiType.DEFAULT);
return (isTrustedCustomTab(intent, session) && isOpenedByChrome
&& (requestedUiType == CustomTabsUiType.PAYMENT_REQUEST));
}
// TODO(https://crbug.com/1023759): Remove this function and enable
// incognito CCT request for all apps.
public static boolean isValidIncognitoIntent(Intent intent) {
if (!isIncognitoRequested(intent)) return false;
// Incognito requests for payments flow are supported without
// INCOGNITO_CCT flag as an exceptional case that can use Chrome
// incognito profile.
if (isForPaymentsFlow(intent)) return true;
assert ChromeFeatureList.isInitialized();
return ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_INCOGNITO);
}
private String resolveUrlToLoad(Intent intent) {
return IntentHandler.getUrlFromIntent(intent);
}
@Override
public @ActivityType int getActivityType() {
return ActivityType.CUSTOM_TAB;
}
@Override
@Nullable
public Intent getIntent() {
return mIntent;
}
@Override
@Nullable
public CustomTabsSessionToken getSession() {
return mSession;
}
@Override
public boolean shouldAnimateOnFinish() {
return mAnimationBundle != null && getClientPackageName() != null;
}
@Override
public String getClientPackageName() {
if (mAnimationBundle == null) return null;
return mAnimationBundle.getString(BUNDLE_PACKAGE_NAME);
}
@Override
public int getAnimationEnterRes() {
return shouldAnimateOnFinish() ? mAnimationBundle.getInt(BUNDLE_ENTER_ANIMATION_RESOURCE)
: 0;
}
@Override
public int getAnimationExitRes() {
return shouldAnimateOnFinish() ? mAnimationBundle.getInt(BUNDLE_EXIT_ANIMATION_RESOURCE)
: 0;
}
@Deprecated
@Override
public boolean isTrustedIntent() {
return mIsTrustedIntent;
}
@Override
@Nullable
public String getUrlToLoad() {
return mUrlToLoad;
}
@Override
public boolean shouldEnableUrlBarHiding() {
return false;
}
@Override
public int getToolbarColor() {
return mToolbarColor;
}
@Override
@Nullable
public Drawable getCloseButtonDrawable() {
return mCloseButtonIcon;
}
@Override
public boolean shouldShowShareMenuItem() {
return mShowShareItem;
}
@Override
public int getBottomBarColor() {
return mBottomBarColor;
}
@Override
public boolean isOpenedByChrome() {
return mIsOpenedByChrome;
}
@Override
public boolean shouldShowStarButton() {
return true;
}
@Override
public boolean shouldShowDownloadButton() {
return false;
}
@Override
public boolean isIncognito() {
return true;
}
}
...@@ -4,33 +4,40 @@ ...@@ -4,33 +4,40 @@
package org.chromium.chrome.browser.customtabs; package org.chromium.chrome.browser.customtabs;
import android.app.PendingIntent;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Process; import android.os.Process;
import android.support.test.InstrumentationRegistry; import android.support.test.InstrumentationRegistry;
import android.view.Menu;
import android.view.MenuItem;
import androidx.browser.customtabs.CustomTabsCallback;
import androidx.browser.customtabs.CustomTabsClient;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.browser.customtabs.CustomTabsServiceConnection;
import androidx.browser.customtabs.CustomTabsSession;
import org.junit.Assert; import org.junit.Assert;
import org.chromium.base.task.PostTask; import org.chromium.base.task.PostTask;
import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CallbackHelper;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.content_public.browser.UiThreadTaskTraits; import org.chromium.content_public.browser.UiThreadTaskTraits;
import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils;
import java.util.ArrayList;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import androidx.browser.customtabs.CustomTabsCallback;
import androidx.browser.customtabs.CustomTabsClient;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.browser.customtabs.CustomTabsServiceConnection;
import androidx.browser.customtabs.CustomTabsSession;
/** /**
* Utility class that contains convenience calls related with custom tabs testing. * Utility class that contains convenience calls related with custom tabs testing.
*/ */
...@@ -51,6 +58,39 @@ public class CustomTabsTestUtils { ...@@ -51,6 +58,39 @@ public class CustomTabsTestUtils {
} }
} }
/**
* A utility class to ensure that a pending intent assigned to a menu item in CCT was invoked.
*/
public static class OnFinishedForTest implements PendingIntent.OnFinished {
private final PendingIntent mPendingIntent;
private final CallbackHelper mCallbackHelper = new CallbackHelper();
private Intent mCallbackIntent;
/**
* Create an instance of {@link OnFinishedForTest}, testing the given {@link PendingIntent}.
*/
public OnFinishedForTest(PendingIntent pendingIntent) {
mPendingIntent = pendingIntent;
}
public Intent getCallbackIntent() {
return mCallbackIntent;
}
public void waitForCallback(String failureReason) throws TimeoutException {
mCallbackHelper.waitForCallback(failureReason, 0);
}
@Override
public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
String resultData, Bundle resultExtras) {
if (pendingIntent.equals(mPendingIntent)) {
mCallbackIntent = intent;
mCallbackHelper.notifyCalled();
}
}
}
/** /**
* Creates the simplest intent that is sufficient to let {@link ChromeLauncherActivity} launch * Creates the simplest intent that is sufficient to let {@link ChromeLauncherActivity} launch
* the {@link CustomTabActivity}. * the {@link CustomTabActivity}.
...@@ -68,6 +108,20 @@ public class CustomTabsTestUtils { ...@@ -68,6 +108,20 @@ public class CustomTabsTestUtils {
return intent; return intent;
} }
/**
* Creates the simplest intent that that is sufficient to let {@link ChromeLauncherActivity}
* launch the incognito {@link CustomTabActivity}.
*
* @param context The instrumentation context to use.
* @param url The URL to load in the incognito CCT.
* @return Returns the intent to launch the incognito CCT.
*/
public static Intent createMinimalIncognitoCustomTabIntent(Context context, String url) {
Intent intent = CustomTabsTestUtils.createMinimalCustomTabIntent(context, url);
intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, true);
return intent;
}
public static CustomTabsConnection setUpConnection() { public static CustomTabsConnection setUpConnection() {
CustomTabsConnection connection = CustomTabsConnection.getInstance(); CustomTabsConnection connection = CustomTabsConnection.getInstance();
connection.resetThrottling(Process.myUid()); connection.resetThrottling(Process.myUid());
...@@ -127,4 +181,102 @@ public class CustomTabsTestUtils { ...@@ -127,4 +181,102 @@ public class CustomTabsTestUtils {
.getAppMenuHandler()::isAppMenuShowing, .getAppMenuHandler()::isAppMenuShowing,
"App menu was not shown"); "App menu was not shown");
} }
public static int getVisibleMenuSize(Menu menu) {
int visibleMenuSize = 0;
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
if (item.isVisible()) visibleMenuSize++;
}
return visibleMenuSize;
}
/**
* Add a bundle specifying a a number of custom menu entries.
*
* @param customTabIntent The intent to modify.
* @param numEntries The number of menu entries to add.
* @param menuTitle The title of the menu.
*
* @return The pending intent associated with the menu entries.
*/
public static PendingIntent addMenuEntriesToIntent(
Intent customTabIntent, int numEntries, String menuTitle) {
return addMenuEntriesToIntent(customTabIntent, numEntries, new Intent(), menuTitle);
}
/**
* Add a bundle specifying a custom menu entry.
*
* @param customTabIntent The intent to modify.
* @param numEntries The number of menu entries to add.
* @param callbackIntent The intent to use as the base for the pending intent.
* @param menuTitle The title of the menu.
*
* @return The pending intent associated with the menu entry.
*/
public static PendingIntent addMenuEntriesToIntent(
Intent customTabIntent, int numEntries, Intent callbackIntent, String menuTitle) {
PendingIntent pi = PendingIntent.getBroadcast(InstrumentationRegistry.getTargetContext(), 0,
callbackIntent, PendingIntent.FLAG_UPDATE_CURRENT);
ArrayList<Bundle> menuItems = new ArrayList<>();
for (int i = 0; i < numEntries; i++) {
Bundle bundle = new Bundle();
bundle.putString(CustomTabsIntent.KEY_MENU_ITEM_TITLE, menuTitle);
bundle.putParcelable(CustomTabsIntent.KEY_PENDING_INTENT, pi);
menuItems.add(bundle);
}
customTabIntent.putParcelableArrayListExtra(CustomTabsIntent.EXTRA_MENU_ITEMS, menuItems);
return pi;
}
/**
* Creates a CCT Toolbar menu item bundle.
*
* @param icon The Bitmap icon to be add in the toolbar.
* @param description The description about the icon which will be added.
* @param pi The pending intent that would be triggered when the icon is clicked on.
* @param id A unique id for this new icon.
*
* @return Returns the bundle encapsulating the toolbar item.
*/
public static Bundle makeToolbarItemBundle(
Bitmap icon, String description, PendingIntent pi, int id) {
Bundle bundle = new Bundle();
bundle.putInt(CustomTabsIntent.KEY_ID, id);
bundle.putParcelable(CustomTabsIntent.KEY_ICON, icon);
bundle.putString(CustomTabsIntent.KEY_DESCRIPTION, description);
bundle.putParcelable(CustomTabsIntent.KEY_PENDING_INTENT, pi);
bundle.putBoolean(CustomButtonParams.SHOW_ON_TOOLBAR, true);
return bundle;
}
/**
* Adds an action button to the custom tab toolbar.
*
* @param intent The intent where the action button would be added.
* @param icon The icon representing the action button.
* @param description The description associated with the action button.
* @param id The unique id that would be used for this new Action button.
*
* @return The {@link PendingIntent} that will be triggered when the action button is clicked.
*/
public static PendingIntent addActionButtonToIntent(
Intent intent, Bitmap icon, String description, int id) {
PendingIntent pi = PendingIntent.getBroadcast(
InstrumentationRegistry.getTargetContext(), 0, new Intent(), 0);
intent.putExtra(CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE,
makeToolbarItemBundle(icon, description, pi, id));
return pi;
}
/**
* @return The test bitmap which can be used to represent an action item on the Toolbar.
*/
public static Bitmap createTestBitmap(int widthDp, int heightDp) {
Resources testRes = InstrumentationRegistry.getTargetContext().getResources();
float density = testRes.getDisplayMetrics().density;
return Bitmap.createBitmap(
(int) (widthDp * density), (int) (heightDp * density), Bitmap.Config.ARGB_8888);
}
} }
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