| Index: chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java
|
| diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ce3203ab4c66da4a8660154c6b3e77f6002aabc6
|
| --- /dev/null
|
| +++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/document/DocumentTab.java
|
| @@ -0,0 +1,350 @@
|
| +// 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.document;
|
| +
|
| +import android.graphics.Bitmap;
|
| +import android.graphics.Rect;
|
| +import android.util.LongSparseArray;
|
| +
|
| +import org.chromium.base.ObserverList.RewindableIterator;
|
| +import org.chromium.base.VisibleForTesting;
|
| +import org.chromium.base.metrics.RecordUserAction;
|
| +import org.chromium.chrome.browser.ChromeMobileApplication;
|
| +import org.chromium.chrome.browser.ContentViewUtil;
|
| +import org.chromium.chrome.browser.EmptyTabObserver;
|
| +import org.chromium.chrome.browser.IntentHandler;
|
| +import org.chromium.chrome.browser.Tab;
|
| +import org.chromium.chrome.browser.TabObserver;
|
| +import org.chromium.chrome.browser.TabState;
|
| +import org.chromium.chrome.browser.TabUma.TabCreationState;
|
| +import org.chromium.chrome.browser.WarmupManager;
|
| +import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
|
| +import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
|
| +import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
|
| +import org.chromium.chrome.browser.preferences.PrefServiceBridge;
|
| +import org.chromium.chrome.browser.tab.ChromeTab;
|
| +import org.chromium.chrome.browser.tabmodel.TabModel;
|
| +import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
|
| +import org.chromium.chrome.browser.tabmodel.document.ActivityDelegate;
|
| +import org.chromium.content_public.browser.LoadUrlParams;
|
| +import org.chromium.content_public.browser.WebContents;
|
| +import org.chromium.content_public.common.Referrer;
|
| +import org.chromium.ui.base.PageTransition;
|
| +import org.chromium.ui.base.WindowAndroid;
|
| +
|
| +/**
|
| + * A Tab child class with Chrome documents specific functionality.
|
| + */
|
| +public class DocumentTab extends ChromeTab {
|
| + private static final int DESIRED_ICON_SIZE_DP = 32;
|
| +
|
| + /**
|
| + * Observer class with extra calls specific to Chrome Documents
|
| + */
|
| + public static class DocumentTabObserver extends EmptyTabObserver {
|
| + /**
|
| + * Called when a Favicon is received for the current document.
|
| + * @param image The favicon image that was received.
|
| + */
|
| + protected void onFaviconReceived(Bitmap image) { }
|
| +
|
| + /**
|
| + * Called when a tab is set to be covered or uncovered by child activity.
|
| + */
|
| + protected void onSetCoveredByChildActivity() { }
|
| + }
|
| +
|
| + private int mDesiredIconSizePx;
|
| + private boolean mDidRestoreState;
|
| +
|
| + // Whether this document tab was constructed from passed-in web contents pointer.
|
| + private boolean mCreatedFromWebContents;
|
| +
|
| + private final DocumentActivity mActivity;
|
| +
|
| + // Whether this tab is covered by its child activity.
|
| + private boolean mIsCoveredByChildActivity;
|
| +
|
| + /**
|
| + * Standard constructor for the document tab.
|
| + * @param activity The document activity that will hold on to this tab.
|
| + * @param incognito Whether the tab is incognito.
|
| + * @param windowAndroid The window that this tab should be using.
|
| + * @param url The url to load on creation.
|
| + * @param parentTabId The id of the parent tab.
|
| + */
|
| + private DocumentTab(DocumentActivity activity, boolean incognito,
|
| + WindowAndroid windowAndroid, String url, int parentTabId) {
|
| + super(ActivityDelegate.getTabIdFromIntent(activity.getIntent()), activity,
|
| + incognito, windowAndroid, TabLaunchType.FROM_EXTERNAL_APP, parentTabId, null, null);
|
| + mActivity = activity;
|
| + initialize(url, null, activity.getTabContentManager(), false);
|
| + }
|
| +
|
| + /**
|
| + * Constructor for document tab from a frozen state.
|
| + * @param activity The document activity that will hold on to this tab.
|
| + * @param incognito Whether the tab is incognito.
|
| + * @param windowAndroid The window that this tab should be using.
|
| + * @param url The url to load on creation.
|
| + * @param tabState The {@link TabState} the tab will be recreated from.
|
| + * @param parentTabId The id of the parent tab.
|
| + */
|
| + private DocumentTab(DocumentActivity activity, boolean incognito,
|
| + WindowAndroid windowAndroid, String url, TabState tabState, int parentTabId) {
|
| + super(ActivityDelegate.getTabIdFromIntent(activity.getIntent()), activity,
|
| + incognito, windowAndroid, TabLaunchType.FROM_RESTORE, parentTabId,
|
| + TabCreationState.FROZEN_ON_RESTORE, tabState);
|
| + mActivity = activity;
|
| + initialize(url, null, activity.getTabContentManager(), true);
|
| + }
|
| +
|
| + /**
|
| + * Constructor for tab opened via JS.
|
| + * @param activity The document activity that will hold on to this tab.
|
| + * @param incognito Whether the tab is incognito.
|
| + * @param windowAndroid The window that this tab should be using.
|
| + * @param url The url to load on creation.
|
| + * @param parentTabId The id of the parent tab.
|
| + * @param webContents An optional {@link WebContents} object to use.
|
| + */
|
| + private DocumentTab(DocumentActivity activity, boolean incognito,
|
| + WindowAndroid windowAndroid, String url, int parentTabId, WebContents webContents) {
|
| + super(ActivityDelegate.getTabIdFromIntent(activity.getIntent()), activity,
|
| + incognito, windowAndroid, TabLaunchType.FROM_LONGPRESS_FOREGROUND,
|
| + parentTabId, null, null);
|
| + mActivity = activity;
|
| + initialize(url, webContents, activity.getTabContentManager(), false);
|
| + mCreatedFromWebContents = true;
|
| + }
|
| +
|
| + @Override
|
| + protected void initContentViewCore(WebContents webContents) {
|
| + super.initContentViewCore(webContents);
|
| + getContentViewCore().setFullscreenRequiredForOrientationLock(false);
|
| + }
|
| +
|
| + /**
|
| + * Initializes the tab with native web contents.
|
| + * @param url The url to use for looking up potentially pre-rendered web contents.
|
| + * @param webContents Optionally, a pre-created web contents.
|
| + * @param unfreeze Whether we want to initialize the tab from tab state.
|
| + */
|
| + private void initialize(String url, WebContents webContents,
|
| + TabContentManager tabContentManager, boolean unfreeze) {
|
| + mDesiredIconSizePx = (int) (DESIRED_ICON_SIZE_DP
|
| + * mActivity.getResources().getDisplayMetrics().density);
|
| +
|
| + if (!unfreeze && webContents == null) {
|
| + webContents = WarmupManager.getInstance().hasPrerenderedUrl(url)
|
| + ? WarmupManager.getInstance().takePrerenderedWebContents()
|
| + : ContentViewUtil.createWebContents(isIncognito(), false);
|
| + }
|
| + initialize(webContents, tabContentManager, false);
|
| + if (unfreeze) mDidRestoreState = unfreezeContents();
|
| +
|
| + getView().requestFocus();
|
| + }
|
| +
|
| + @Override
|
| + public void onFaviconAvailable(Bitmap image) {
|
| + super.onFaviconAvailable(image);
|
| + if (image == null) return;
|
| + if (image.getWidth() < mDesiredIconSizePx || image.getHeight() < mDesiredIconSizePx) {
|
| + return;
|
| + }
|
| + RewindableIterator<TabObserver> observers = getTabObservers();
|
| + while (observers.hasNext()) {
|
| + TabObserver observer = observers.next();
|
| + if (observer instanceof DocumentTabObserver) {
|
| + ((DocumentTabObserver) observer).onFaviconReceived(image);
|
| + }
|
| + }
|
| + }
|
| +
|
| + private class DocumentContextMenuItemDelegate extends TabChromeContextMenuItemDelegate {
|
| + @Override
|
| + public boolean isIncognitoSupported() {
|
| + return PrefServiceBridge.getInstance().isIncognitoModeEnabled();
|
| + }
|
| +
|
| + @Override
|
| + public boolean canLoadOriginalImage() {
|
| + return mUsedSpdyProxy && !mUsedSpdyProxyWithPassthrough;
|
| + }
|
| +
|
| + @Override
|
| + public boolean startDownload(String url, boolean isLink) {
|
| + if (isLink && shouldInterceptContextMenuDownload(url)) {
|
| + return false;
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + @Override
|
| + public void onOpenInNewTab(String url, Referrer referrer) {
|
| + PendingDocumentData params = new PendingDocumentData();
|
| + params.referrer = referrer;
|
| + ChromeLauncherActivity.launchDocumentInstance(
|
| + getWindowAndroid().getActivity().get(), isIncognito(),
|
| + ChromeLauncherActivity.LAUNCH_MODE_AFFILIATED, url,
|
| + DocumentMetricIds.STARTED_BY_CONTEXT_MENU,
|
| + PageTransition.AUTO_TOPLEVEL, false, params);
|
| + }
|
| +
|
| + @Override
|
| + public void onOpenInNewIncognitoTab(String url) {
|
| + ChromeLauncherActivity.launchDocumentInstance(
|
| + getWindowAndroid().getActivity().get(), true,
|
| + ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND,
|
| + url, DocumentMetricIds.STARTED_BY_CONTEXT_MENU,
|
| + PageTransition.AUTO_TOPLEVEL, false, null);
|
| + }
|
| +
|
| + @Override
|
| + public void onOpenImageInNewTab(String url, Referrer referrer) {
|
| + boolean useOriginal = isSpdyProxyEnabledForUrl(url);
|
| +
|
| + LoadUrlParams loadUrlParams = new LoadUrlParams(url);
|
| + loadUrlParams.setVerbatimHeaders(useOriginal ? PAGESPEED_PASSTHROUGH_HEADER : null);
|
| + loadUrlParams.setReferrer(referrer);
|
| + mActivity.getTabModelSelector().openNewTab(loadUrlParams,
|
| + TabLaunchType.FROM_LONGPRESS_BACKGROUND, DocumentTab.this, isIncognito());
|
| + }
|
| +
|
| + @Override
|
| + public void onOpenImageUrl(String url, Referrer referrer) {
|
| + LoadUrlParams loadUrlParams = new LoadUrlParams(url);
|
| + loadUrlParams.setTransitionType(PageTransition.AUTO_BOOKMARK);
|
| + loadUrlParams.setReferrer(referrer);
|
| + loadUrl(loadUrlParams);
|
| + }
|
| +
|
| + @Override
|
| + public void onSearchByImageInNewTab() {
|
| + RecordUserAction.record("MobileContextMenuSearchByImage");
|
| + triggerSearchByImage();
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + protected ContextMenuPopulator createContextMenuPopulator() {
|
| + return new ChromeContextMenuPopulator(new DocumentContextMenuItemDelegate());
|
| + }
|
| +
|
| + /**
|
| + * A web contents delegate for handling opening new windows in Document mode.
|
| + */
|
| + public class DocumentTabChromeWebContentsDelegateAndroidImpl
|
| + extends TabChromeWebContentsDelegateAndroidImpl {
|
| + private final LongSparseArray<String> mContentsToUrlMapping = new LongSparseArray<String>();
|
| +
|
| + @Override
|
| + public void webContentsCreated(WebContents sourceWebContents, long openerRenderFrameId,
|
| + String frameName, String targetUrl, WebContents newWebContents) {
|
| + super.webContentsCreated(sourceWebContents, openerRenderFrameId, frameName,
|
| + targetUrl, newWebContents);
|
| + long nativeNewWebContents =
|
| + ContentViewUtil.getNativeWebContentsFromWebContents(newWebContents);
|
| + mContentsToUrlMapping.put(nativeNewWebContents, targetUrl);
|
| + DocumentWebContentsDelegate.getInstance().attachDelegate(newWebContents);
|
| + }
|
| +
|
| + @Override
|
| + public boolean addNewContents(WebContents sourceWebContents, WebContents webContents,
|
| + int disposition, Rect initialPosition, boolean userGesture) {
|
| + if (isClosing()) return false;
|
| + long nativeWebContents =
|
| + ContentViewUtil.getNativeWebContentsFromWebContents(webContents);
|
| + String url = mContentsToUrlMapping.get(nativeWebContents);
|
| + if (url == null) url = "";
|
| + PendingDocumentData data = new PendingDocumentData();
|
| + data.webContents = webContents;
|
| + data.webContentsPaused = true;
|
| + ChromeLauncherActivity.launchDocumentInstance(
|
| + getWindowAndroid().getActivity().get(), isIncognito(),
|
| + ChromeLauncherActivity.LAUNCH_MODE_AFFILIATED, url,
|
| + DocumentMetricIds.STARTED_BY_WINDOW_OPEN,
|
| + PageTransition.AUTO_TOPLEVEL,
|
| + false, data);
|
| +
|
| + return true;
|
| + }
|
| +
|
| + /**
|
| + * TODO(dfalcantara): remove this when DocumentActivity.getTabModelSelector()
|
| + * will return the right TabModelSelector.
|
| + */
|
| + @Override
|
| + protected TabModel getTabModel() {
|
| + return ChromeMobileApplication.getDocumentTabModelSelector().getModel(isIncognito());
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + protected TabChromeWebContentsDelegateAndroid createWebContentsDelegate() {
|
| + return new DocumentTabChromeWebContentsDelegateAndroidImpl();
|
| + }
|
| +
|
| + /**
|
| + * @return Whether or not the tab's state was restored.
|
| + */
|
| + public boolean didRestoreState() {
|
| + return mDidRestoreState;
|
| + }
|
| +
|
| + /**
|
| + * @return Whether this tab was created using web contents passed to it.
|
| + */
|
| + public boolean isCreatedWithWebContents() {
|
| + return mCreatedFromWebContents;
|
| + }
|
| +
|
| + /**
|
| + * Create a DocumentTab.
|
| + * @param activity The activity the tab will be residing in.
|
| + * @param incognito Whether the tab is incognito.
|
| + * @param window The window the activity is using.
|
| + * @param url The url that should be displayed by the tab.
|
| + * @param webContents A {@link WebContents} object.
|
| + * @param tabState State that was previously persisted to disk for the Tab.
|
| + * @return The created {@link DocumentTab}.
|
| + */
|
| + static DocumentTab create(DocumentActivity activity, boolean incognito, WindowAndroid window,
|
| + String url, WebContents webContents, boolean webContentsPaused, TabState tabState) {
|
| + int parentTabId = activity.getIntent().getIntExtra(
|
| + IntentHandler.EXTRA_PARENT_TAB_ID, Tab.INVALID_TAB_ID);
|
| + if (webContents != null) {
|
| + DocumentTab tab = new DocumentTab(
|
| + activity, incognito, window, url, parentTabId, webContents);
|
| + if (webContentsPaused) webContents.resumeLoadingCreatedWebContents();
|
| + return tab;
|
| + }
|
| +
|
| + if (tabState == null) {
|
| + return new DocumentTab(activity, incognito, window, url, parentTabId);
|
| + } else {
|
| + return new DocumentTab(activity, incognito, window, "", tabState, parentTabId);
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public boolean isCoveredByChildActivity() {
|
| + return mIsCoveredByChildActivity;
|
| + }
|
| +
|
| + @Override
|
| + @VisibleForTesting
|
| + public void setCoveredByChildActivity(boolean isCoveredByChildActivity) {
|
| + mIsCoveredByChildActivity = isCoveredByChildActivity;
|
| + RewindableIterator<TabObserver> observers = getTabObservers();
|
| + while (observers.hasNext()) {
|
| + TabObserver observer = observers.next();
|
| + if (observer instanceof DocumentTabObserver) {
|
| + ((DocumentTabObserver) observer).onSetCoveredByChildActivity();
|
| + }
|
| + }
|
| + }
|
| +}
|
|
|