OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser.document; |
| 6 |
| 7 import android.graphics.Bitmap; |
| 8 import android.graphics.Rect; |
| 9 import android.util.LongSparseArray; |
| 10 |
| 11 import org.chromium.base.ObserverList.RewindableIterator; |
| 12 import org.chromium.base.VisibleForTesting; |
| 13 import org.chromium.base.metrics.RecordUserAction; |
| 14 import org.chromium.chrome.browser.ChromeMobileApplication; |
| 15 import org.chromium.chrome.browser.ContentViewUtil; |
| 16 import org.chromium.chrome.browser.EmptyTabObserver; |
| 17 import org.chromium.chrome.browser.IntentHandler; |
| 18 import org.chromium.chrome.browser.Tab; |
| 19 import org.chromium.chrome.browser.TabObserver; |
| 20 import org.chromium.chrome.browser.TabState; |
| 21 import org.chromium.chrome.browser.TabUma.TabCreationState; |
| 22 import org.chromium.chrome.browser.WarmupManager; |
| 23 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; |
| 24 import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator; |
| 25 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator; |
| 26 import org.chromium.chrome.browser.preferences.PrefServiceBridge; |
| 27 import org.chromium.chrome.browser.tab.ChromeTab; |
| 28 import org.chromium.chrome.browser.tabmodel.TabModel; |
| 29 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; |
| 30 import org.chromium.chrome.browser.tabmodel.document.ActivityDelegate; |
| 31 import org.chromium.content_public.browser.LoadUrlParams; |
| 32 import org.chromium.content_public.browser.WebContents; |
| 33 import org.chromium.content_public.common.Referrer; |
| 34 import org.chromium.ui.base.PageTransition; |
| 35 import org.chromium.ui.base.WindowAndroid; |
| 36 |
| 37 /** |
| 38 * A Tab child class with Chrome documents specific functionality. |
| 39 */ |
| 40 public class DocumentTab extends ChromeTab { |
| 41 private static final int DESIRED_ICON_SIZE_DP = 32; |
| 42 |
| 43 /** |
| 44 * Observer class with extra calls specific to Chrome Documents |
| 45 */ |
| 46 public static class DocumentTabObserver extends EmptyTabObserver { |
| 47 /** |
| 48 * Called when a Favicon is received for the current document. |
| 49 * @param image The favicon image that was received. |
| 50 */ |
| 51 protected void onFaviconReceived(Bitmap image) { } |
| 52 |
| 53 /** |
| 54 * Called when a tab is set to be covered or uncovered by child activity
. |
| 55 */ |
| 56 protected void onSetCoveredByChildActivity() { } |
| 57 } |
| 58 |
| 59 private int mDesiredIconSizePx; |
| 60 private boolean mDidRestoreState; |
| 61 |
| 62 // Whether this document tab was constructed from passed-in web contents poi
nter. |
| 63 private boolean mCreatedFromWebContents; |
| 64 |
| 65 private final DocumentActivity mActivity; |
| 66 |
| 67 // Whether this tab is covered by its child activity. |
| 68 private boolean mIsCoveredByChildActivity; |
| 69 |
| 70 /** |
| 71 * Standard constructor for the document tab. |
| 72 * @param activity The document activity that will hold on to this tab. |
| 73 * @param incognito Whether the tab is incognito. |
| 74 * @param windowAndroid The window that this tab should be using. |
| 75 * @param url The url to load on creation. |
| 76 * @param parentTabId The id of the parent tab. |
| 77 */ |
| 78 private DocumentTab(DocumentActivity activity, boolean incognito, |
| 79 WindowAndroid windowAndroid, String url, int parentTabId) { |
| 80 super(ActivityDelegate.getTabIdFromIntent(activity.getIntent()), activit
y, |
| 81 incognito, windowAndroid, TabLaunchType.FROM_EXTERNAL_APP, paren
tTabId, null, null); |
| 82 mActivity = activity; |
| 83 initialize(url, null, activity.getTabContentManager(), false); |
| 84 } |
| 85 |
| 86 /** |
| 87 * Constructor for document tab from a frozen state. |
| 88 * @param activity The document activity that will hold on to this tab. |
| 89 * @param incognito Whether the tab is incognito. |
| 90 * @param windowAndroid The window that this tab should be using. |
| 91 * @param url The url to load on creation. |
| 92 * @param tabState The {@link TabState} the tab will be recreated from. |
| 93 * @param parentTabId The id of the parent tab. |
| 94 */ |
| 95 private DocumentTab(DocumentActivity activity, boolean incognito, |
| 96 WindowAndroid windowAndroid, String url, TabState tabState, int pare
ntTabId) { |
| 97 super(ActivityDelegate.getTabIdFromIntent(activity.getIntent()), activit
y, |
| 98 incognito, windowAndroid, TabLaunchType.FROM_RESTORE, parentTabI
d, |
| 99 TabCreationState.FROZEN_ON_RESTORE, tabState); |
| 100 mActivity = activity; |
| 101 initialize(url, null, activity.getTabContentManager(), true); |
| 102 } |
| 103 |
| 104 /** |
| 105 * Constructor for tab opened via JS. |
| 106 * @param activity The document activity that will hold on to this tab. |
| 107 * @param incognito Whether the tab is incognito. |
| 108 * @param windowAndroid The window that this tab should be using. |
| 109 * @param url The url to load on creation. |
| 110 * @param parentTabId The id of the parent tab. |
| 111 * @param webContents An optional {@link WebContents} object to use. |
| 112 */ |
| 113 private DocumentTab(DocumentActivity activity, boolean incognito, |
| 114 WindowAndroid windowAndroid, String url, int parentTabId, WebContent
s webContents) { |
| 115 super(ActivityDelegate.getTabIdFromIntent(activity.getIntent()), activit
y, |
| 116 incognito, windowAndroid, TabLaunchType.FROM_LONGPRESS_FOREGROUN
D, |
| 117 parentTabId, null, null); |
| 118 mActivity = activity; |
| 119 initialize(url, webContents, activity.getTabContentManager(), false); |
| 120 mCreatedFromWebContents = true; |
| 121 } |
| 122 |
| 123 @Override |
| 124 protected void initContentViewCore(WebContents webContents) { |
| 125 super.initContentViewCore(webContents); |
| 126 getContentViewCore().setFullscreenRequiredForOrientationLock(false); |
| 127 } |
| 128 |
| 129 /** |
| 130 * Initializes the tab with native web contents. |
| 131 * @param url The url to use for looking up potentially pre-rendered web con
tents. |
| 132 * @param webContents Optionally, a pre-created web contents. |
| 133 * @param unfreeze Whether we want to initialize the tab from tab state. |
| 134 */ |
| 135 private void initialize(String url, WebContents webContents, |
| 136 TabContentManager tabContentManager, boolean unfreeze) { |
| 137 mDesiredIconSizePx = (int) (DESIRED_ICON_SIZE_DP |
| 138 * mActivity.getResources().getDisplayMetrics().density); |
| 139 |
| 140 if (!unfreeze && webContents == null) { |
| 141 webContents = WarmupManager.getInstance().hasPrerenderedUrl(url) |
| 142 ? WarmupManager.getInstance().takePrerenderedWebContents() |
| 143 : ContentViewUtil.createWebContents(isIncognito(), false); |
| 144 } |
| 145 initialize(webContents, tabContentManager, false); |
| 146 if (unfreeze) mDidRestoreState = unfreezeContents(); |
| 147 |
| 148 getView().requestFocus(); |
| 149 } |
| 150 |
| 151 @Override |
| 152 public void onFaviconAvailable(Bitmap image) { |
| 153 super.onFaviconAvailable(image); |
| 154 if (image == null) return; |
| 155 if (image.getWidth() < mDesiredIconSizePx || image.getHeight() < mDesire
dIconSizePx) { |
| 156 return; |
| 157 } |
| 158 RewindableIterator<TabObserver> observers = getTabObservers(); |
| 159 while (observers.hasNext()) { |
| 160 TabObserver observer = observers.next(); |
| 161 if (observer instanceof DocumentTabObserver) { |
| 162 ((DocumentTabObserver) observer).onFaviconReceived(image); |
| 163 } |
| 164 } |
| 165 } |
| 166 |
| 167 private class DocumentContextMenuItemDelegate extends TabChromeContextMenuIt
emDelegate { |
| 168 @Override |
| 169 public boolean isIncognitoSupported() { |
| 170 return PrefServiceBridge.getInstance().isIncognitoModeEnabled(); |
| 171 } |
| 172 |
| 173 @Override |
| 174 public boolean canLoadOriginalImage() { |
| 175 return mUsedSpdyProxy && !mUsedSpdyProxyWithPassthrough; |
| 176 } |
| 177 |
| 178 @Override |
| 179 public boolean startDownload(String url, boolean isLink) { |
| 180 if (isLink && shouldInterceptContextMenuDownload(url)) { |
| 181 return false; |
| 182 } |
| 183 return true; |
| 184 } |
| 185 |
| 186 @Override |
| 187 public void onOpenInNewTab(String url, Referrer referrer) { |
| 188 PendingDocumentData params = new PendingDocumentData(); |
| 189 params.referrer = referrer; |
| 190 ChromeLauncherActivity.launchDocumentInstance( |
| 191 getWindowAndroid().getActivity().get(), isIncognito(), |
| 192 ChromeLauncherActivity.LAUNCH_MODE_AFFILIATED, url, |
| 193 DocumentMetricIds.STARTED_BY_CONTEXT_MENU, |
| 194 PageTransition.AUTO_TOPLEVEL, false, params); |
| 195 } |
| 196 |
| 197 @Override |
| 198 public void onOpenInNewIncognitoTab(String url) { |
| 199 ChromeLauncherActivity.launchDocumentInstance( |
| 200 getWindowAndroid().getActivity().get(), true, |
| 201 ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND, |
| 202 url, DocumentMetricIds.STARTED_BY_CONTEXT_MENU, |
| 203 PageTransition.AUTO_TOPLEVEL, false, null); |
| 204 } |
| 205 |
| 206 @Override |
| 207 public void onOpenImageInNewTab(String url, Referrer referrer) { |
| 208 boolean useOriginal = isSpdyProxyEnabledForUrl(url); |
| 209 |
| 210 LoadUrlParams loadUrlParams = new LoadUrlParams(url); |
| 211 loadUrlParams.setVerbatimHeaders(useOriginal ? PAGESPEED_PASSTHROUGH
_HEADER : null); |
| 212 loadUrlParams.setReferrer(referrer); |
| 213 mActivity.getTabModelSelector().openNewTab(loadUrlParams, |
| 214 TabLaunchType.FROM_LONGPRESS_BACKGROUND, DocumentTab.this, i
sIncognito()); |
| 215 } |
| 216 |
| 217 @Override |
| 218 public void onOpenImageUrl(String url, Referrer referrer) { |
| 219 LoadUrlParams loadUrlParams = new LoadUrlParams(url); |
| 220 loadUrlParams.setTransitionType(PageTransition.AUTO_BOOKMARK); |
| 221 loadUrlParams.setReferrer(referrer); |
| 222 loadUrl(loadUrlParams); |
| 223 } |
| 224 |
| 225 @Override |
| 226 public void onSearchByImageInNewTab() { |
| 227 RecordUserAction.record("MobileContextMenuSearchByImage"); |
| 228 triggerSearchByImage(); |
| 229 } |
| 230 } |
| 231 |
| 232 @Override |
| 233 protected ContextMenuPopulator createContextMenuPopulator() { |
| 234 return new ChromeContextMenuPopulator(new DocumentContextMenuItemDelegat
e()); |
| 235 } |
| 236 |
| 237 /** |
| 238 * A web contents delegate for handling opening new windows in Document mode
. |
| 239 */ |
| 240 public class DocumentTabChromeWebContentsDelegateAndroidImpl |
| 241 extends TabChromeWebContentsDelegateAndroidImpl { |
| 242 private final LongSparseArray<String> mContentsToUrlMapping = new LongSp
arseArray<String>(); |
| 243 |
| 244 @Override |
| 245 public void webContentsCreated(WebContents sourceWebContents, long opene
rRenderFrameId, |
| 246 String frameName, String targetUrl, WebContents newWebContents)
{ |
| 247 super.webContentsCreated(sourceWebContents, openerRenderFrameId, fra
meName, |
| 248 targetUrl, newWebContents); |
| 249 long nativeNewWebContents = |
| 250 ContentViewUtil.getNativeWebContentsFromWebContents(newWebCo
ntents); |
| 251 mContentsToUrlMapping.put(nativeNewWebContents, targetUrl); |
| 252 DocumentWebContentsDelegate.getInstance().attachDelegate(newWebConte
nts); |
| 253 } |
| 254 |
| 255 @Override |
| 256 public boolean addNewContents(WebContents sourceWebContents, WebContents
webContents, |
| 257 int disposition, Rect initialPosition, boolean userGesture) { |
| 258 if (isClosing()) return false; |
| 259 long nativeWebContents = |
| 260 ContentViewUtil.getNativeWebContentsFromWebContents(webConte
nts); |
| 261 String url = mContentsToUrlMapping.get(nativeWebContents); |
| 262 if (url == null) url = ""; |
| 263 PendingDocumentData data = new PendingDocumentData(); |
| 264 data.webContents = webContents; |
| 265 data.webContentsPaused = true; |
| 266 ChromeLauncherActivity.launchDocumentInstance( |
| 267 getWindowAndroid().getActivity().get(), isIncognito(), |
| 268 ChromeLauncherActivity.LAUNCH_MODE_AFFILIATED, url, |
| 269 DocumentMetricIds.STARTED_BY_WINDOW_OPEN, |
| 270 PageTransition.AUTO_TOPLEVEL, |
| 271 false, data); |
| 272 |
| 273 return true; |
| 274 } |
| 275 |
| 276 /** |
| 277 * TODO(dfalcantara): remove this when DocumentActivity.getTabModelSelec
tor() |
| 278 * will return the right TabModelSelector. |
| 279 */ |
| 280 @Override |
| 281 protected TabModel getTabModel() { |
| 282 return ChromeMobileApplication.getDocumentTabModelSelector().getMode
l(isIncognito()); |
| 283 } |
| 284 } |
| 285 |
| 286 @Override |
| 287 protected TabChromeWebContentsDelegateAndroid createWebContentsDelegate() { |
| 288 return new DocumentTabChromeWebContentsDelegateAndroidImpl(); |
| 289 } |
| 290 |
| 291 /** |
| 292 * @return Whether or not the tab's state was restored. |
| 293 */ |
| 294 public boolean didRestoreState() { |
| 295 return mDidRestoreState; |
| 296 } |
| 297 |
| 298 /** |
| 299 * @return Whether this tab was created using web contents passed to it. |
| 300 */ |
| 301 public boolean isCreatedWithWebContents() { |
| 302 return mCreatedFromWebContents; |
| 303 } |
| 304 |
| 305 /** |
| 306 * Create a DocumentTab. |
| 307 * @param activity The activity the tab will be residing in. |
| 308 * @param incognito Whether the tab is incognito. |
| 309 * @param window The window the activity is using. |
| 310 * @param url The url that should be displayed by the tab. |
| 311 * @param webContents A {@link WebContents} object. |
| 312 * @param tabState State that was previously persisted to disk for the Tab. |
| 313 * @return The created {@link DocumentTab}. |
| 314 */ |
| 315 static DocumentTab create(DocumentActivity activity, boolean incognito, Wind
owAndroid window, |
| 316 String url, WebContents webContents, boolean webContentsPaused, TabS
tate tabState) { |
| 317 int parentTabId = activity.getIntent().getIntExtra( |
| 318 IntentHandler.EXTRA_PARENT_TAB_ID, Tab.INVALID_TAB_ID); |
| 319 if (webContents != null) { |
| 320 DocumentTab tab = new DocumentTab( |
| 321 activity, incognito, window, url, parentTabId, webContents); |
| 322 if (webContentsPaused) webContents.resumeLoadingCreatedWebContents()
; |
| 323 return tab; |
| 324 } |
| 325 |
| 326 if (tabState == null) { |
| 327 return new DocumentTab(activity, incognito, window, url, parentTabId
); |
| 328 } else { |
| 329 return new DocumentTab(activity, incognito, window, "", tabState, pa
rentTabId); |
| 330 } |
| 331 } |
| 332 |
| 333 @Override |
| 334 public boolean isCoveredByChildActivity() { |
| 335 return mIsCoveredByChildActivity; |
| 336 } |
| 337 |
| 338 @Override |
| 339 @VisibleForTesting |
| 340 public void setCoveredByChildActivity(boolean isCoveredByChildActivity) { |
| 341 mIsCoveredByChildActivity = isCoveredByChildActivity; |
| 342 RewindableIterator<TabObserver> observers = getTabObservers(); |
| 343 while (observers.hasNext()) { |
| 344 TabObserver observer = observers.next(); |
| 345 if (observer instanceof DocumentTabObserver) { |
| 346 ((DocumentTabObserver) observer).onSetCoveredByChildActivity(); |
| 347 } |
| 348 } |
| 349 } |
| 350 } |
OLD | NEW |