blob: 73ceea9e1b5d3f83eafe5c38c6fd52959a614049 [file] [log] [blame]
// Copyright 2015 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.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE;
import android.app.Application;
import android.app.Instrumentation;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.customtabs.CustomTabsCallback;
import android.support.customtabs.CustomTabsIntent;
import android.support.customtabs.ICustomTabsCallback;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import org.chromium.base.ThreadUtils;
import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.document.DocumentActivity;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.toolbar.CustomTabToolbar;
import org.chromium.chrome.browser.util.ColorUtils;
import org.chromium.chrome.browser.util.FeatureUtilities;
import org.chromium.chrome.test.util.TestHttpServerClient;
import org.chromium.chrome.test.util.browser.contextmenu.ContextMenuUtils;
import org.chromium.content.browser.BrowserStartupController;
import org.chromium.content.browser.BrowserStartupController.StartupCallback;
import org.chromium.content.browser.test.util.CallbackHelper;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.LoadUrlParams;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Instrumentation tests for app menu, context menu, and toolbar of a {@link CustomTabActivity}.
*/
public class CustomTabActivityTest extends CustomTabActivityTestBase {
/**
* An empty {@link BroadcastReceiver} that exists only to make the PendingIntent to carry an
* explicit intent. Otherwise the framework will not send it after {@link PendingIntent#send()}.
*/
public static class DummyBroadcastReceiver extends BroadcastReceiver {
// The url has to be copied from the instrumentation class, because a BroadcastReceiver is
// deployed as a different package, and it cannot get access to data from the
// instrumentation package.
private static final String TEST_PAGE_COPY = TestHttpServerClient.getUrl(
"chrome/test/data/android/google.html");
@Override
public void onReceive(Context context, Intent intent) {
// Note: even if this assertion fails, the test might still pass, because
// BroadcastReceiver is not treated as part of the instrumentation test.
assertEquals(TEST_PAGE_COPY, intent.getDataString());
}
}
private static final int MAX_MENU_CUSTOM_ITEMS = 5;
private static final int NUM_CHROME_MENU_ITEMS = 3;
private static final String
TEST_ACTION = "org.chromium.chrome.browser.customtabs.TEST_PENDING_INTENT_SENT";
private static final String TEST_PAGE = TestHttpServerClient.getUrl(
"chrome/test/data/android/google.html");
private static final String TEST_PAGE_2 = TestHttpServerClient.getUrl(
"chrome/test/data/android/test.html");
private static final String TEST_MENU_TITLE = "testMenuTitle";
private CustomTabActivity mActivity;
@Override
protected void startActivityCompletely(Intent intent) {
super.startActivityCompletely(intent);
mActivity = getActivity();
}
/**
* @see CustomTabsTestUtils#createMinimalCustomTabIntent(Context, String, IBinder).
*/
private Intent createMinimalCustomTabIntent() {
return CustomTabsTestUtils.createMinimalCustomTabIntent(
getInstrumentation().getTargetContext(), TEST_PAGE, null);
}
/**
* Add a bundle specifying a custom menu entry.
* @param intent The intent to modify.
* @return The pending intent associated with the menu entry.
*/
private PendingIntent addMenuEntriesToIntent(Intent intent, int numEntries) {
Intent menuIntent = new Intent();
menuIntent.setClass(getInstrumentation().getContext(), DummyBroadcastReceiver.class);
menuIntent.setAction(TEST_ACTION);
PendingIntent pi = PendingIntent.getBroadcast(getInstrumentation().getTargetContext(), 0,
menuIntent, 0);
ArrayList<Bundle> menuItems = new ArrayList<Bundle>();
for (int i = 0; i < numEntries; i++) {
Bundle bundle = new Bundle();
bundle.putString(CustomTabsIntent.KEY_MENU_ITEM_TITLE, TEST_MENU_TITLE);
bundle.putParcelable(CustomTabsIntent.KEY_PENDING_INTENT, pi);
menuItems.add(bundle);
}
intent.putParcelableArrayListExtra(CustomTabsIntent.EXTRA_MENU_ITEMS, menuItems);
return pi;
}
private void addToolbarColorToIntent(Intent intent, int color) {
intent.putExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR, color);
}
/**
* Adds an action button to the custom tab toolbar.
* @return The {@link PendingIntent} that will be triggered when the action button is clicked.
*/
private PendingIntent addActionButtonToIntent(Intent intent, Bitmap icon, String description) {
Intent actionIntent = new Intent();
actionIntent.setClass(getInstrumentation().getContext(), DummyBroadcastReceiver.class);
actionIntent.setAction(TEST_ACTION);
Bundle bundle = new Bundle();
bundle.putParcelable(CustomTabsIntent.KEY_ICON, icon);
bundle.putString(CustomTabsIntent.KEY_DESCRIPTION, description);
PendingIntent pi = PendingIntent.getBroadcast(getInstrumentation().getTargetContext(), 0,
actionIntent, 0);
bundle.putParcelable(CustomTabsIntent.KEY_PENDING_INTENT, pi);
intent.putExtra(CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE, bundle);
return pi;
}
private void openAppMenuAndAssertMenuShown() throws InterruptedException {
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
mActivity.onMenuOrKeyboardAction(R.id.show_menu, false);
}
});
assertTrue("App menu was not shown", CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
@Override
public boolean isSatisfied() {
return mActivity.getAppMenuHandler().isAppMenuShowing();
}
}));
}
/**
* Test the entries in the context menu shown when long clicking an image.
*/
@SmallTest
public void testContextMenuEntriesForImage() throws InterruptedException, TimeoutException {
startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
final int expectedMenuSize = 2;
Menu menu = ContextMenuUtils.openContextMenu(this, getActivity().getActivityTab(), "logo");
assertEquals(expectedMenuSize, menu.size());
assertNotNull(menu.findItem(R.id.contextmenu_save_image));
assertNotNull(menu.findItem(R.id.contextmenu_open_image));
}
/**
* Test the entries in the context menu shown when long clicking an link.
*/
@SmallTest
public void testContextMenuEntriesForLink() throws InterruptedException, TimeoutException {
startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
final int expectedMenuSize = 3;
Menu menu = ContextMenuUtils.openContextMenu(this, getActivity().getActivityTab(),
"aboutLink");
assertEquals(expectedMenuSize, menu.size());
assertNotNull(menu.findItem(R.id.contextmenu_copy_link_address));
assertNotNull(menu.findItem(R.id.contextmenu_copy_link_text));
assertNotNull(menu.findItem(R.id.contextmenu_save_link_as));
}
/**
* Test the entries in the app menu.
*/
@SmallTest
public void testCustomTabAppMenu() throws InterruptedException {
Intent intent = createMinimalCustomTabIntent();
int numMenuEntries = 1;
addMenuEntriesToIntent(intent, numMenuEntries);
startCustomTabActivityWithIntent(intent);
openAppMenuAndAssertMenuShown();
final int expectedMenuSize = numMenuEntries + NUM_CHROME_MENU_ITEMS;
Menu menu = getActivity().getAppMenuHandler().getAppMenuForTest().getMenuForTest();
assertNotNull("App menu is not initialized: ", menu);
assertEquals(expectedMenuSize, menu.size());
assertNotNull(menu.findItem(R.id.forward_menu_id));
assertNotNull(menu.findItem(R.id.info_menu_id));
assertNotNull(menu.findItem(R.id.reload_menu_id));
assertNotNull(menu.findItem(R.id.find_in_page_id));
assertNotNull(menu.findItem(R.id.open_in_chrome_id));
}
/**
* Test that only up to 5 entries are added to the custom menu.
*/
@SmallTest
public void testCustomTabMaxMenuItems() throws InterruptedException {
Intent intent = createMinimalCustomTabIntent();
int numMenuEntries = 7;
addMenuEntriesToIntent(intent, numMenuEntries);
startCustomTabActivityWithIntent(intent);
openAppMenuAndAssertMenuShown();
int expectedMenuSize = MAX_MENU_CUSTOM_ITEMS + NUM_CHROME_MENU_ITEMS;
Menu menu = getActivity().getAppMenuHandler().getAppMenuForTest().getMenuForTest();
assertNotNull("App menu is not initialized: ", menu);
assertEquals(expectedMenuSize, menu.size());
}
/**
* Test whether the custom menu is correctly shown and clicking it sends the right
* {@link PendingIntent}.
*/
@SmallTest
public void testCustomMenuEntry() throws InterruptedException {
Intent intent = createMinimalCustomTabIntent();
final PendingIntent pi = addMenuEntriesToIntent(intent, 1);
startCustomTabActivityWithIntent(intent);
final OnFinishedForTest onFinished = new OnFinishedForTest(pi);
mActivity.getIntentDataProvider().setPendingIntentOnFinishedForTesting(onFinished);
openAppMenuAndAssertMenuShown();
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
MenuItem item = mActivity.getAppMenuPropertiesDelegate().getMenuItemForTitle(
TEST_MENU_TITLE);
assertNotNull(item);
assertTrue(mActivity.onOptionsItemSelected(item));
}
});
assertTrue("Pending Intent was not sent.", CriteriaHelper.pollForCriteria(new Criteria() {
@Override
public boolean isSatisfied() {
return onFinished.isSent();
}
}));
}
/**
* Test whether clicking "Open in Chrome" takes us to a chrome normal tab, loading the same url.
*/
@SmallTest
public void testOpenInChrome() throws InterruptedException {
startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
boolean isDocumentMode = FeatureUtilities.isDocumentMode(
getInstrumentation().getTargetContext());
String activityName;
if (isDocumentMode) {
activityName = DocumentActivity.class.getName();
} else {
activityName = ChromeTabbedActivity.class.getName();
}
Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonitor(activityName,
null, false);
openAppMenuAndAssertMenuShown();
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
mActivity.onMenuOrKeyboardAction(R.id.open_in_chrome_id, false);
}
});
final ChromeActivity chromeActivity = (ChromeActivity) monitor
.waitForActivityWithTimeout(ACTIVITY_START_TIMEOUT_MS);
assertNotNull("A normal chrome activity did not start.", chromeActivity);
assertTrue("The normal tab was not initiated correctly.",
CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
@Override
public boolean isSatisfied() {
Tab tab = chromeActivity.getActivityTab();
return tab != null && tab.getUrl().equals(TEST_PAGE);
}
}));
}
/**
* Test whether the color of the toolbar is correctly customized. For L or later releases,
* status bar color is also tested.
*/
@SmallTest
public void testToolbarColor() throws InterruptedException {
Intent intent = createMinimalCustomTabIntent();
final int expectedColor = Color.RED;
addToolbarColorToIntent(intent, expectedColor);
startCustomTabActivityWithIntent(intent);
View toolbarView = getActivity().findViewById(R.id.toolbar);
assertTrue("A custom tab toolbar is never shown", toolbarView instanceof CustomTabToolbar);
CustomTabToolbar toolbar = (CustomTabToolbar) toolbarView;
assertEquals(expectedColor, toolbar.getBackground().getColor());
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
assertEquals(ColorUtils.getDarkenedColorForStatusBar(expectedColor),
getActivity().getWindow().getStatusBarColor());
}
}
/**
* Test if an action button is shown with correct image and size, and clicking it sends the
* correct {@link PendingIntent}.
*/
@SmallTest
public void testActionButton() throws InterruptedException {
final int iconHeightDp = 48;
final int iconWidthDp = 96;
Resources testRes = getInstrumentation().getTargetContext().getResources();
float density = testRes.getDisplayMetrics().density;
Bitmap expectedIcon = Bitmap.createBitmap((int) (iconWidthDp * density),
(int) (iconHeightDp * density), Bitmap.Config.ARGB_8888);
Intent intent = createMinimalCustomTabIntent();
final PendingIntent pi = addActionButtonToIntent(intent, expectedIcon, "Good test");
startCustomTabActivityWithIntent(intent);
final OnFinishedForTest onFinished = new OnFinishedForTest(pi);
mActivity.getIntentDataProvider().setPendingIntentOnFinishedForTesting(onFinished);
View toolbarView = getActivity().findViewById(R.id.toolbar);
assertTrue("A custom tab toolbar is never shown", toolbarView instanceof CustomTabToolbar);
CustomTabToolbar toolbar = (CustomTabToolbar) toolbarView;
final ImageButton actionButton = toolbar.getCustomActionButtonForTest();
assertNotNull(actionButton);
assertNotNull(actionButton.getDrawable());
assertTrue("Action button's background is not a BitmapDrawable.",
actionButton.getDrawable() instanceof BitmapDrawable);
assertTrue("Action button does not have the correct bitmap.",
expectedIcon.sameAs(((BitmapDrawable) actionButton.getDrawable()).getBitmap()));
ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@Override
public void run() {
actionButton.performClick();
}
});
assertTrue("Pending Intent was not sent.", CriteriaHelper.pollForCriteria(new Criteria() {
@Override
public boolean isSatisfied() {
return onFinished.isSent();
}
}));
}
/**
* Test the case that the action button should not be shown, given a bitmap with unacceptable
* height/width ratio.
*/
@SmallTest
public void testActionButtonBadRatio() throws InterruptedException {
final int iconHeightDp = 20;
final int iconWidthDp = 60;
Resources testRes = getInstrumentation().getTargetContext().getResources();
float density = testRes.getDisplayMetrics().density;
Bitmap expectedIcon = Bitmap.createBitmap((int) (iconWidthDp * density),
(int) (iconHeightDp * density), Bitmap.Config.ARGB_8888);
Intent intent = createMinimalCustomTabIntent();
addActionButtonToIntent(intent, expectedIcon, "Good test");
startCustomTabActivityWithIntent(intent);
View toolbarView = getActivity().findViewById(R.id.toolbar);
assertTrue("A custom tab toolbar is never shown", toolbarView instanceof CustomTabToolbar);
CustomTabToolbar toolbar = (CustomTabToolbar) toolbarView;
final ImageButton actionButton = toolbar.getCustomActionButtonForTest();
assertNotNull(actionButton);
assertTrue("Action button should not be shown",
View.VISIBLE != actionButton.getVisibility());
CustomTabIntentDataProvider dataProvider = mActivity.getIntentDataProvider();
assertNull(dataProvider.getActionButtonParams());
}
@SmallTest
public void testLaunchWithSession() throws InterruptedException {
IBinder session = warmUpAndLaunchUrlWithSession();
assertEquals(mActivity.getIntentDataProvider().getSession(), session);
}
@SmallTest
public void testLoadNewUrlWithSession() throws InterruptedException {
final IBinder session = warmUpAndLaunchUrlWithSession();
final Context context = getInstrumentation().getTargetContext();
assertEquals(mActivity.getIntentDataProvider().getSession(), session);
assertFalse("CustomTabContentHandler handled intent with wrong session",
ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return CustomTabActivity.handleInActiveContentIfNeeded(
CustomTabsTestUtils.createMinimalCustomTabIntent(context,
TEST_PAGE_2,
(new CustomTabsTestUtils.DummyCallback()).asBinder()));
}
}));
assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
@Override
public boolean isSatisfied() {
return mActivity.getActivityTab().getUrl().equals(TEST_PAGE);
}
}));
assertTrue("CustomTabContentHandler can't handle intent with same session",
ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return CustomTabActivity.handleInActiveContentIfNeeded(
CustomTabsTestUtils.createMinimalCustomTabIntent(context,
TEST_PAGE_2, session));
}
}));
final Tab tab = mActivity.getActivityTab();
final CallbackHelper pageLoadFinishedHelper = new CallbackHelper();
tab.addObserver(new EmptyTabObserver() {
@Override
public void onPageLoadFinished(Tab tab) {
pageLoadFinishedHelper.notifyCalled();
}
});
try {
pageLoadFinishedHelper.waitForCallback(0);
} catch (TimeoutException e) {
fail();
}
assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
@Override
public boolean isSatisfied() {
return mActivity.getActivityTab().getUrl().equals(TEST_PAGE_2);
}
}));
}
@SmallTest
public void testReferrerAddedAutomatically() throws InterruptedException {
final IBinder session = warmUpAndLaunchUrlWithSession();
assertEquals(mActivity.getIntentDataProvider().getSession(), session);
final Context context = getInstrumentation().getTargetContext().getApplicationContext();
CustomTabsConnection connection = CustomTabsConnection.getInstance((Application) context);
String packageName = context.getPackageName();
final String referrer =
IntentHandler.constructValidReferrerForAuthority(packageName).getUrl();
assertEquals(referrer, connection.getReferrerForSession(session).getUrl());
final Tab tab = mActivity.getActivityTab();
final CallbackHelper pageLoadFinishedHelper = new CallbackHelper();
tab.addObserver(new EmptyTabObserver() {
@Override
public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
assertEquals(referrer, params.getReferrer().getUrl());
}
@Override
public void onPageLoadFinished(Tab tab) {
pageLoadFinishedHelper.notifyCalled();
}
});
assertTrue("CustomTabContentHandler can't handle intent with same session",
ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return CustomTabActivity.handleInActiveContentIfNeeded(
CustomTabsTestUtils.createMinimalCustomTabIntent(context,
TEST_PAGE_2, session));
}
}));
try {
pageLoadFinishedHelper.waitForCallback(0);
} catch (TimeoutException e) {
fail();
}
}
/**
* Tests that the navigation callbacks are sent.
*/
@SmallTest
public void testCallbacksAreSent() {
final ArrayList<Integer> navigationEvents = new ArrayList<>();
ICustomTabsCallback cb = new CustomTabsTestUtils.DummyCallback() {
@Override
public void onNavigationEvent(int navigationEvent, Bundle extras) {
navigationEvents.add(navigationEvent);
}
};
try {
warmUpAndLaunchUrlWithSession(cb);
assertTrue(navigationEvents.contains(CustomTabsCallback.NAVIGATION_STARTED));
assertTrue(navigationEvents.contains(CustomTabsCallback.NAVIGATION_FINISHED));
assertFalse(navigationEvents.contains(CustomTabsCallback.NAVIGATION_FAILED));
assertFalse(navigationEvents.contains(CustomTabsCallback.NAVIGATION_ABORTED));
} catch (InterruptedException e) {
fail();
}
}
/**
* Tests that when we use a pre-created renderer, the page loaded is the
* only one in the navigation history.
*/
@SmallTest
@Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
public void testPrecreatedRenderer() {
CustomTabsConnection connection = warmUpAndWait();
ICustomTabsCallback cb = new CustomTabsTestUtils.DummyCallback();
assertTrue(connection.newSession(cb));
Bundle extras = new Bundle();
extras.putBoolean(CustomTabsConnection.NO_PRERENDERING_KEY, true);
assertTrue(connection.mayLaunchUrl(cb, Uri.parse(TEST_PAGE), extras, null));
Context context = getInstrumentation().getTargetContext().getApplicationContext();
try {
startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent(
context, TEST_PAGE, cb.asBinder()));
} catch (InterruptedException e) {
fail();
}
Tab tab = getActivity().getActivityTab();
assertEquals(TEST_PAGE, tab.getUrl());
assertFalse(tab.canGoBack());
}
/** Tests that calling mayLaunchUrl() without warmup() succeeds. */
@SmallTest
public void testMayLaunchUrlWithoutWarmup() {
mayLaunchUrlWithoutWarmup(false);
}
/** Tests that calling warmup() is optional without prerendering. */
@SmallTest
public void testMayLaunchUrlWithoutWarmupNoPrerendering() {
mayLaunchUrlWithoutWarmup(true);
}
private void mayLaunchUrlWithoutWarmup(boolean noPrerendering) {
Context context = getInstrumentation().getTargetContext().getApplicationContext();
CustomTabsConnection connection =
CustomTabsTestUtils.setUpConnection((Application) context);
ICustomTabsCallback cb = new CustomTabsTestUtils.DummyCallback();
connection.newSession(cb);
Bundle extras = null;
if (noPrerendering) {
extras = new Bundle();
extras.putBoolean(CustomTabsConnection.NO_PRERENDERING_KEY, true);
}
assertTrue(connection.mayLaunchUrl(cb, Uri.parse(TEST_PAGE), extras, null));
try {
startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent(
context, TEST_PAGE, cb.asBinder()));
} catch (InterruptedException e) {
fail();
}
Tab tab = getActivity().getActivityTab();
assertEquals(TEST_PAGE, tab.getUrl());
}
private CustomTabsConnection warmUpAndWait() {
final Context context = getInstrumentation().getTargetContext().getApplicationContext();
CustomTabsConnection connection =
CustomTabsTestUtils.setUpConnection((Application) context);
final CallbackHelper startupCallbackHelper = new CallbackHelper();
assertTrue(connection.warmup(0));
ThreadUtils.runOnUiThread(new Runnable() {
@Override
public void run() {
BrowserStartupController.get(context, LibraryProcessType.PROCESS_BROWSER)
.addStartupCompletedObserver(new StartupCallback() {
@Override
public void onSuccess(boolean alreadyStarted) {
startupCallbackHelper.notifyCalled();
}
@Override
public void onFailure() {
fail();
}
});
}
});
try {
startupCallbackHelper.waitForCallback(0);
} catch (TimeoutException | InterruptedException e) {
fail();
}
return connection;
}
private IBinder warmUpAndLaunchUrlWithSession(ICustomTabsCallback cb)
throws InterruptedException {
CustomTabsConnection connection = warmUpAndWait();
connection.newSession(cb);
Context context = getInstrumentation().getTargetContext().getApplicationContext();
startCustomTabActivityWithIntent(CustomTabsTestUtils.createMinimalCustomTabIntent(
context, TEST_PAGE, cb.asBinder()));
return cb.asBinder();
}
private IBinder warmUpAndLaunchUrlWithSession() throws InterruptedException {
ICustomTabsCallback cb = new CustomTabsTestUtils.DummyCallback();
return warmUpAndLaunchUrlWithSession(cb);
}
/**
* A helper class to monitor sending status of a {@link PendingIntent}.
*/
private static class OnFinishedForTest implements PendingIntent.OnFinished {
private PendingIntent mPi;
private AtomicBoolean mIsSent = new AtomicBoolean();
private String mUri;
/**
* Create an instance of {@link OnFinishedForTest}, testing the given {@link PendingIntent}.
*/
public OnFinishedForTest(PendingIntent pi) {
mPi = pi;
}
/**
* @return Whether {@link PendingIntent#send()} has been successfully triggered and the sent
* intent carries the correct Uri as data.
*/
public boolean isSent() {
return mIsSent.get() && TEST_PAGE.equals(mUri);
}
@Override
public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode,
String resultData, Bundle resultExtras) {
if (pendingIntent.equals(mPi)) {
mUri = intent.getDataString();
mIsSent.set(true);
}
}
}
}