Commit 3d5e851c authored by dfalcantara's avatar dfalcantara Committed by Commit bot

Herb: Show an icon allowing the user to open a tab in Chrome

* Adds an icon to CCTs opened by Chrome that allows the user
  to open the URL in the full Chrome browser.

* Allows CustomTabActivity to be finished() when it fires a
  PendingIntent that was created by Chrome itself.

* Adds an icon for the "open in chrome" action.

BUG=582539

Review URL: https://codereview.chromium.org/1683533002

Cr-Commit-Position: refs/heads/master@{#374797}
parent ad3331f7
......@@ -48,6 +48,7 @@ import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter;
import org.chromium.chrome.browser.compositor.layouts.phone.StackLayout;
import org.chromium.chrome.browser.cookies.CookiesFetcher;
import org.chromium.chrome.browser.device.DeviceClassManager;
import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.document.DocumentUma;
import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkUtils;
import org.chromium.chrome.browser.firstrun.FirstRunActivity;
......@@ -81,6 +82,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelUtils;
import org.chromium.chrome.browser.tabmodel.TabWindowManager;
import org.chromium.chrome.browser.toolbar.ToolbarControlContainer;
import org.chromium.chrome.browser.util.FeatureUtilities;
import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.chrome.browser.widget.emptybackground.EmptyBackgroundViewWrapper;
import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager;
import org.chromium.content.browser.ContentVideoView;
......@@ -467,7 +469,7 @@ public class ChromeTabbedActivity extends ChromeActivity implements OverviewMode
getToolbarManager().getToolbar().setReturnButtonListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (getActivityTab() != null) closeForegroundTab();
if (getActivityTab() != null) handleBackPressedWithoutBackStack();
}
});
......@@ -695,7 +697,8 @@ public class ChromeTabbedActivity extends ChromeActivity implements OverviewMode
break;
case OPEN_NEW_TAB:
Tab newTab = launchIntent(url, referer, headers, externalAppId, true, intent);
newTab.setIsAllowedToReturnToExternalApp(true);
newTab.setIsAllowedToReturnToExternalApp(IntentUtils.safeGetBooleanExtra(intent,
ChromeLauncherActivity.EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT, true));
RecordUserAction.record("MobileReceivedExternalIntent");
break;
case OPEN_NEW_INCOGNITO_TAB:
......@@ -1012,7 +1015,7 @@ public class ChromeTabbedActivity extends ChromeActivity implements OverviewMode
if (!getToolbarManager().back()) {
Log.i(TAG, "handleBackPressed() - no back stack");
if (closeForegroundTab()) return true;
if (handleBackPressedWithoutBackStack()) return true;
} else {
Log.i(TAG, "handleBackPressed() - moving back in navigation");
RecordUserAction.record("SystemBackForNavigation");
......@@ -1024,11 +1027,13 @@ public class ChromeTabbedActivity extends ChromeActivity implements OverviewMode
}
/**
* Closes the foreground tab, potentially sending the user back to the app that launched Chrome.
* Additional logic for handling situations where a user hits a 'back' or 'return' button.
*
* May result in closing the foreground tab or returning to the app that opened Chrome.
*
* @return Whether the tab closed was opened for a help page.
*/
private boolean closeForegroundTab() {
private boolean handleBackPressedWithoutBackStack() {
final Tab currentTab = getActivityTab();
final TabLaunchType type = currentTab.getLaunchType();
final int parentId = currentTab.getParentId();
......@@ -1039,7 +1044,7 @@ public class ChromeTabbedActivity extends ChromeActivity implements OverviewMode
// actual redirected URL is a different system language based help url.
if (type == TabLaunchType.FROM_MENU_OR_OVERVIEW && helpUrl) {
getCurrentTabModel().closeTab(currentTab);
Log.i(TAG, "closeForegroundTab() - help url");
Log.i(TAG, "handleBackPressedWithoutBackStack() - help url");
return true;
}
......@@ -1060,7 +1065,7 @@ public class ChromeTabbedActivity extends ChromeActivity implements OverviewMode
final boolean minimizeApp = !shouldCloseTab || currentTab.isCreatedForExternalApp();
if (minimizeApp) {
Log.i(TAG, "closeForegroundTab() - moveTaskToBack");
Log.i(TAG, "handleBackPressedWithoutBackStack() - moveTaskToBack");
moveTaskToBack(true);
if (shouldCloseTab) {
// In the case of closing a tab upon minimalization, don't allow the close
......
......@@ -39,6 +39,7 @@ import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
import org.chromium.chrome.browser.compositor.layouts.LayoutManagerDocument;
import org.chromium.chrome.browser.datausage.DataUseTabUIManager;
import org.chromium.chrome.browser.document.ChromeLauncherActivity;
import org.chromium.chrome.browser.rappor.RapporServiceBridge;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabIdManager;
......@@ -66,6 +67,7 @@ import java.util.List;
*/
public class CustomTabActivity extends ChromeActivity {
private static final String TAG = "CustomTabActivity";
private static CustomTabContentHandler sActiveContentHandler;
private FindToolbarManager mFindToolbarManager;
......@@ -172,7 +174,6 @@ public class CustomTabActivity extends ChromeActivity {
@Override
public void preInflationStartup() {
super.preInflationStartup();
mIntentDataProvider = new CustomTabIntentDataProvider(getIntent(), this);
supportRequestWindowFeature(Window.FEATURE_ACTION_MODE_OVERLAY);
}
......@@ -444,7 +445,7 @@ public class CustomTabActivity extends ChromeActivity {
* Configures the custom button on toolbar. Does nothing if invalid data is provided by clients.
*/
private void showCustomButtonOnToolbar() {
CustomButtonParams params = mIntentDataProvider.getCustomButtonOnToolbar();
final CustomButtonParams params = mIntentDataProvider.getCustomButtonOnToolbar();
if (params == null) return;
getToolbarManager().setCustomActionButton(
params.getIcon(getResources()),
......@@ -452,10 +453,18 @@ public class CustomTabActivity extends ChromeActivity {
new OnClickListener() {
@Override
public void onClick(View v) {
String creatorPackage =
ApiCompatibilityUtils.getCreatorPackage(params.getPendingIntent());
if (mIntentDataProvider.finishAfterOpeningInBrowser()
&& TextUtils.equals(getPackageName(), creatorPackage)) {
openCurrentUrlInBrowser();
finish();
} else {
mIntentDataProvider.sendButtonPendingIntentWithUrl(
getApplicationContext(), getActivityTab().getUrl());
RecordUserAction.record("CustomTabsCustomActionButtonClick");
}
}
});
}
......@@ -561,22 +570,7 @@ public class CustomTabActivity extends ChromeActivity {
|| id == R.id.new_tab_menu_id || id == R.id.open_history_menu_id) {
return true;
} else if (id == R.id.open_in_browser_id) {
String url = getTabModelSelector().getCurrentTab().getUrl();
if (DomDistillerUrlUtils.isDistilledPage(url)) {
url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url);
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Temporarily allowing disk access while fixing. TODO: http://crbug.com/581860
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
StrictMode.allowThreadDiskWrites();
try {
startActivity(intent);
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
openCurrentUrlInBrowser();
RecordUserAction.record("CustomTabsMenuOpenInChrome");
return true;
} else if (id == R.id.find_in_page_id) {
......@@ -621,4 +615,26 @@ public class CustomTabActivity extends ChromeActivity {
CustomTabIntentDataProvider getIntentDataProvider() {
return mIntentDataProvider;
}
/**
* Opens the URL currently being displayed in the Custom Tab in the regular browser.
*/
void openCurrentUrlInBrowser() {
String url = getTabModelSelector().getCurrentTab().getUrl();
if (DomDistillerUrlUtils.isDistilledPage(url)) {
url = DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(url);
}
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(ChromeLauncherActivity.EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT, false);
// Temporarily allowing disk access while fixing. TODO: http://crbug.com/581860
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
StrictMode.allowThreadDiskWrites();
try {
startActivity(intent);
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
}
......@@ -26,6 +26,7 @@ import org.chromium.base.Log;
import org.chromium.base.VisibleForTesting;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.chrome.browser.widget.TintedDrawable;
......@@ -44,6 +45,13 @@ public class CustomTabIntentDataProvider {
*/
public static final String EXTRA_KEEP_ALIVE = "android.support.customtabs.extra.KEEP_ALIVE";
/**
* Extra used by Chrome to tell the CustomTabActivity to finish itself and open the current URL
* in the browser. Guarded explicitly for use only by PendingIntents with the Chrome package.
*/
public static final String EXTRA_FINISH_AFTER_OPENING_IN_BROWSER =
"org.chromium.chrome.browser.customtabs.FINISH_AFTER_OPENING_IN_BROWSER";
private static final int MAX_CUSTOM_MENU_ITEMS = 5;
private static final String ANIMATION_BUNDLE_PREFIX =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? "android:activity." : "android:";
......@@ -63,6 +71,7 @@ public class CustomTabIntentDataProvider {
private List<Pair<String, PendingIntent>> mMenuEntries = new ArrayList<>();
private Bundle mAnimationBundle;
private boolean mShowShareItem;
private boolean mFinishAfterOpeningInBrowser;
private CustomButtonParams mToolbarButton;
private List<CustomButtonParams> mBottombarButtons = new ArrayList<>(2);
// OnFinished listener for PendingIntents. Used for testing only.
......@@ -74,6 +83,10 @@ public class CustomTabIntentDataProvider {
public CustomTabIntentDataProvider(Intent intent, Context context) {
if (intent == null) assert false;
mSession = IntentUtils.safeGetBinderExtra(intent, CustomTabsIntent.EXTRA_SESSION);
mFinishAfterOpeningInBrowser = !TextUtils.isEmpty(ChromePreferenceManager.getHerbFlavor())
&& IntentUtils.safeGetBooleanExtra(
intent, EXTRA_FINISH_AFTER_OPENING_IN_BROWSER, false);
retrieveCustomButtons(intent, context);
retrieveToolbarColor(intent, context);
retrieveBottomBarColor(intent);
......@@ -359,4 +372,11 @@ public class CustomTabIntentDataProvider {
void setPendingIntentOnFinishedForTesting(PendingIntent.OnFinished onFinished) {
mOnFinished = onFinished;
}
/**
* @return See {@link #EXTRA_FINISH_AFTER_OPENING_IN_BROWSER}.
*/
public boolean finishAfterOpeningInBrowser() {
return mFinishAfterOpeningInBrowser;
}
}
......@@ -18,6 +18,8 @@ import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
......@@ -31,6 +33,7 @@ import org.chromium.base.ApplicationStatus;
import org.chromium.base.CommandLineInitUtil;
import org.chromium.base.Log;
import org.chromium.base.TraceEvent;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeApplication;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ChromeTabbedActivity;
......@@ -41,6 +44,7 @@ import org.chromium.chrome.browser.ShortcutSource;
import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.WarmupManager;
import org.chromium.chrome.browser.customtabs.CustomTabActivity;
import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
import org.chromium.chrome.browser.externalnav.IntentWithGesturesHandler;
import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer;
import org.chromium.chrome.browser.metrics.LaunchMetrics;
......@@ -80,6 +84,12 @@ public class ChromeLauncherActivity extends Activity
public static final String EXTRA_LAUNCH_MODE =
"com.google.android.apps.chrome.EXTRA_LAUNCH_MODE";
/**
* Whether or not the toolbar should indicate that a tab was spawned by another Activity.
*/
public static final String EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT =
"org.chromium.chrome.browser.document.IS_ALLOWED_TO_RETURN_TO_PARENT";
/**
* Action fired when the user selects the "Close all incognito tabs" notification.
*/
......@@ -314,6 +324,29 @@ public class ChromeLauncherActivity extends Activity
}
}
private void addHerbIntentExtras(Intent newIntent, Uri uri) {
Bundle herbBundle = new Bundle();
Bitmap herbIcon =
BitmapFactory.decodeResource(getResources(), R.drawable.btn_open_in_chrome);
herbBundle.putParcelable(CustomTabsIntent.KEY_ICON, herbIcon);
// Fallback in case the Custom Tab fails to trigger opening in Chrome.
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT, false);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
herbBundle.putParcelable(CustomTabsIntent.KEY_PENDING_INTENT, pendingIntent);
herbBundle.putString(CustomTabsIntent.KEY_DESCRIPTION,
getResources().getString(R.string.menu_open_in_chrome));
newIntent.putExtra(CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE, herbBundle);
newIntent.putExtra(CustomTabIntentDataProvider.EXTRA_FINISH_AFTER_OPENING_IN_BROWSER, true);
}
/**
* @return Whether the intent sent is for launching a Custom Tab.
*/
......@@ -340,10 +373,14 @@ public class ChromeLauncherActivity extends Activity
// Create and fire a launch intent. Use the copy constructor to carry over the myriad of
// extras.
Uri uri = Uri.parse(IntentHandler.getUrlFromIntent(getIntent()));
Intent newIntent = new Intent(getIntent());
newIntent.setAction(Intent.ACTION_VIEW);
newIntent.setClassName(this, CustomTabActivity.class.getName());
newIntent.setData(Uri.parse(IntentHandler.getUrlFromIntent(getIntent())));
newIntent.setData(uri);
if (isIntentHandledByHerb()) addHerbIntentExtras(newIntent, uri);
startActivity(newIntent);
}
......
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