Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3400)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java

Issue 1416093004: Remove CustomTab and have all CustomTabActivity using Tab (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed tests and nits Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..a0f2e805a853363243a8c6151830f1a864dc4b4f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -0,0 +1,240 @@
+// Copyright 2014 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 android.app.Application;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.os.TransactionTooLargeException;
+import android.text.TextUtils;
+import android.view.ContextMenu;
+import android.view.Menu;
+
+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.UrlUtilities;
+import org.chromium.chrome.browser.banners.AppBannerManager;
+import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
+import org.chromium.chrome.browser.contextmenu.ContextMenuParams;
+import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl;
+import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler;
+import org.chromium.chrome.browser.tab.InterceptNavigationDelegateImpl;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabContextMenuItemDelegate;
+import org.chromium.chrome.browser.tab.TabDelegateFactory;
+import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContents;
+
+/**
+ * A {@link TabDelegateFactory} class to be used in all {@link Tab} owned
+ * by a {@link CustomTabActivity}.
+ */
+public class CustomTabDelegateFactory extends TabDelegateFactory {
+ /**
+ * A custom external navigation delegate that forbids the intent picker from showing up.
+ */
+ static class CustomTabNavigationDelegate extends ExternalNavigationDelegateImpl {
+ private static final String TAG = "customtabs";
+ private boolean mHasActivityStarted;
+
+ /**
+ * Constructs a new instance of {@link CustomTabNavigationDelegate}.
+ */
+ public CustomTabNavigationDelegate(ChromeActivity activity) {
+ super(activity);
+ }
+
+ @Override
+ public void startActivity(Intent intent) {
+ super.startActivity(intent);
+ mHasActivityStarted = true;
+ }
+
+ @Override
+ public boolean startActivityIfNeeded(Intent intent) {
+ boolean isExternalProtocol = !UrlUtilities.isAcceptedScheme(intent.getDataString());
+ boolean hasDefaultHandler = hasDefaultHandler(intent);
+ try {
+ // For a url chrome can handle and there is no default set, handle it ourselves.
+ if (!hasDefaultHandler && !isExternalProtocol) return false;
+ // If android fails to find a handler, handle it ourselves.
+ if (!getActivity().startActivityIfNeeded(intent, -1)) return false;
+
+ mHasActivityStarted = true;
+ return true;
+ } catch (RuntimeException e) {
+ logTransactionTooLargeOrRethrow(e, intent);
+ return false;
+ }
+ }
+
+ /**
+ * Resolve the default external handler of an intent.
+ * @return Whether the default external handler is found: if chrome turns out to be the
+ * default handler, this method will return false.
+ */
+ private boolean hasDefaultHandler(Intent intent) {
+ try {
+ ResolveInfo info = getActivity().getPackageManager().resolveActivity(intent, 0);
+ if (info != null) {
+ final String chromePackage = getActivity().getPackageName();
+ // If a default handler is found and it is not chrome itself, fire the intent.
+ if (info.match != 0 && !chromePackage.equals(info.activityInfo.packageName)) {
+ return true;
+ }
+ }
+ } catch (RuntimeException e) {
+ logTransactionTooLargeOrRethrow(e, intent);
+ }
+ return false;
+ }
+
+ /**
+ * @return Whether an external activity has started to handle a url. For testing only.
+ */
+ @VisibleForTesting
+ public boolean hasExternalActivityStarted() {
+ return mHasActivityStarted;
+ }
+
+ private static void logTransactionTooLargeOrRethrow(RuntimeException e, Intent intent) {
+ // See http://crbug.com/369574.
+ if (e.getCause() instanceof TransactionTooLargeException) {
+ Log.e(TAG, "Could not resolve Activity for intent " + intent.toString(), e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ private static class CustomTabWebContentsDelegate extends TabWebContentsDelegateAndroid {
+ private String mTargetUrl;
+
+ /**
+ * See {@link TabWebContentsDelegateAndroid}.
+ */
+ public CustomTabWebContentsDelegate(Tab tab, CustomTabActivity activity) {
+ super(tab, activity);
+ }
+
+ @Override
+ public boolean shouldResumeRequestsForCreatedWindow() {
+ return true;
+ }
+
+ @Override
+ public void webContentsCreated(WebContents sourceWebContents, long openerRenderFrameId,
+ String frameName, String targetUrl, WebContents newWebContents) {
+ super.webContentsCreated(
+ sourceWebContents, openerRenderFrameId, frameName, targetUrl,
+ newWebContents);
+ mTargetUrl = targetUrl;
+ }
+
+ @Override
+ public boolean addNewContents(WebContents sourceWebContents, WebContents webContents,
+ int disposition, Rect initialPosition, boolean userGesture) {
+ assert mTargetUrl != null;
+ ((CustomTabActivity) mActivity).loadUrlInCurrentTab(
+ new LoadUrlParams(mTargetUrl), SystemClock.elapsedRealtime());
+ mTargetUrl = null;
+ return false;
+ }
+
+ @Override
+ protected void bringActivityToForeground() {
+ // No-op here. If client's task is in background Chrome is unable to foreground it.
+ }
+ }
+
+ private final Application mApplication;
+ private final IBinder mSession;
+ private CustomTabNavigationDelegate mNavigationDelegate;
+ private ExternalNavigationHandler mNavigationHandler;
+ private CustomTabObserver mTabObserver;
+
+ public CustomTabDelegateFactory(Application application, IBinder session) {
+ super();
+ mApplication = application;
+ mSession = session;
+ }
+
+ @Override
+ public TabWebContentsDelegateAndroid createWebContentsDelegate(Tab tab,
+ ChromeActivity activity) {
+ assert activity instanceof CustomTabActivity;
+ return new CustomTabWebContentsDelegate(tab, (CustomTabActivity) activity);
+ }
+
+ @Override
+ public InterceptNavigationDelegateImpl createInterceptNavigationDelegate(Tab tab,
+ ChromeActivity activity) {
+ mNavigationDelegate = new CustomTabNavigationDelegate(activity);
+ mNavigationHandler = new ExternalNavigationHandler(mNavigationDelegate);
+ return new InterceptNavigationDelegateImpl(mNavigationHandler, activity, tab);
+ }
+
+ @Override
+ public ContextMenuPopulator createContextMenuPopulator(Tab tab, ChromeActivity activity) {
+ return new ChromeContextMenuPopulator(new TabContextMenuItemDelegate(tab, activity)) {
+ @Override
+ public void buildContextMenu(ContextMenu menu, Context context,
+ ContextMenuParams params) {
+ String linkUrl = params.getLinkUrl();
+ if (linkUrl != null) linkUrl = linkUrl.trim();
+ if (!TextUtils.isEmpty(linkUrl)) {
+ menu.add(Menu.NONE, org.chromium.chrome.R.id.contextmenu_copy_link_address,
+ Menu.NONE, org.chromium.chrome.R.string.contextmenu_copy_link_address);
+ }
+
+ String linkText = params.getLinkText();
+ if (linkText != null) linkText = linkText.trim();
+ if (!TextUtils.isEmpty(linkText) && !params.isImage()) {
+ menu.add(Menu.NONE, org.chromium.chrome.R.id.contextmenu_copy_link_text,
+ Menu.NONE, org.chromium.chrome.R.string.contextmenu_copy_link_text);
+ }
+ if (params.isImage()) {
+ menu.add(Menu.NONE, R.id.contextmenu_save_image, Menu.NONE,
+ R.string.contextmenu_save_image);
+ menu.add(Menu.NONE, R.id.contextmenu_open_image, Menu.NONE,
+ R.string.contextmenu_open_image);
+ } else if (UrlUtilities.isDownloadableScheme(params.getLinkUrl())) {
+ // "Save link" is not shown for image.
+ menu.add(Menu.NONE, R.id.contextmenu_save_link_as, Menu.NONE,
+ R.string.contextmenu_save_link);
+ }
+ }
+ };
+ }
+
+ /**
+ * @return The {@link ExternalNavigationHandler} in this tab. For test purpose only.
+ */
+ @VisibleForTesting
+ ExternalNavigationHandler getExternalNavigationHandler() {
+ return mNavigationHandler;
+ }
+
+ /**
+ * @return The {@link CustomTabNavigationDelegate} in this tab. For test purpose only.
+ */
+ @VisibleForTesting
+ CustomTabNavigationDelegate getExternalNavigationDelegate() {
+ return mNavigationDelegate;
+ }
+
+ @Override
+ public AppBannerManager createAppBannerManager(Tab tab) {
+ return null;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698