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.annotation.TargetApi; |
| 8 import android.app.Activity; |
| 9 import android.content.Intent; |
| 10 import android.content.res.Configuration; |
| 11 import android.graphics.Bitmap; |
| 12 import android.graphics.Color; |
| 13 import android.net.Uri; |
| 14 import android.os.Build; |
| 15 import android.text.TextUtils; |
| 16 import android.util.Log; |
| 17 import android.view.KeyEvent; |
| 18 import android.view.Menu; |
| 19 import android.view.View; |
| 20 import android.view.ViewGroup; |
| 21 import android.view.Window; |
| 22 |
| 23 import com.google.android.apps.chrome.R; |
| 24 |
| 25 import org.chromium.base.ActivityState; |
| 26 import org.chromium.base.ApplicationStatus; |
| 27 import org.chromium.base.SysUtils; |
| 28 import org.chromium.base.VisibleForTesting; |
| 29 import org.chromium.base.library_loader.LibraryLoader; |
| 30 import org.chromium.base.metrics.RecordUserAction; |
| 31 import org.chromium.chrome.browser.ChromeMobileApplication; |
| 32 import org.chromium.chrome.browser.CompositorChromeActivity; |
| 33 import org.chromium.chrome.browser.IntentHandler; |
| 34 import org.chromium.chrome.browser.KeyboardShortcuts; |
| 35 import org.chromium.chrome.browser.Tab; |
| 36 import org.chromium.chrome.browser.TabState; |
| 37 import org.chromium.chrome.browser.UrlConstants; |
| 38 import org.chromium.chrome.browser.UrlUtilities; |
| 39 import org.chromium.chrome.browser.appmenu.AppMenuHandler; |
| 40 import org.chromium.chrome.browser.appmenu.AppMenuObserver; |
| 41 import org.chromium.chrome.browser.appmenu.ChromeAppMenuPropertiesDelegate; |
| 42 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerDocument; |
| 43 import org.chromium.chrome.browser.document.DocumentTab.DocumentTabObserver; |
| 44 import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkUtils; |
| 45 import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor; |
| 46 import org.chromium.chrome.browser.firstrun.FirstRunStatus; |
| 47 import org.chromium.chrome.browser.metrics.UmaUtils; |
| 48 import org.chromium.chrome.browser.ntp.DocumentNewTabPage; |
| 49 import org.chromium.chrome.browser.ntp.NewTabPage; |
| 50 import org.chromium.chrome.browser.preferences.ChromePreferenceManager; |
| 51 import org.chromium.chrome.browser.preferences.PrefServiceBridge; |
| 52 import org.chromium.chrome.browser.preferences.bandwidth.BandwidthReductionPrefe
rences; |
| 53 import org.chromium.chrome.browser.preferences.bandwidth.DataReductionPromoScree
n; |
| 54 import org.chromium.chrome.browser.signin.SigninPromoScreen; |
| 55 import org.chromium.chrome.browser.ssl.ConnectionSecurityHelperSecurityLevel; |
| 56 import org.chromium.chrome.browser.tabmodel.SingleTabModelSelector; |
| 57 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; |
| 58 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; |
| 59 import org.chromium.chrome.browser.tabmodel.document.ActivityDelegate; |
| 60 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel; |
| 61 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModel.Initializa
tionObserver; |
| 62 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModelImpl; |
| 63 import org.chromium.chrome.browser.tabmodel.document.DocumentTabModelSelector; |
| 64 import org.chromium.chrome.browser.toolbar.ToolbarControlContainer; |
| 65 import org.chromium.chrome.browser.toolbar.ToolbarHelper; |
| 66 import org.chromium.chrome.browser.util.FeatureUtilities; |
| 67 import org.chromium.chrome.browser.util.IntentUtils; |
| 68 import org.chromium.chrome.browser.widget.ControlContainer; |
| 69 import org.chromium.chrome.browser.widget.RoundedIconGenerator; |
| 70 import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager; |
| 71 import org.chromium.components.service_tab_launcher.ServiceTabLauncher; |
| 72 import org.chromium.content.browser.ContentVideoView; |
| 73 import org.chromium.content.browser.ContentViewCore; |
| 74 import org.chromium.content_public.browser.LoadUrlParams; |
| 75 import org.chromium.content_public.browser.NavigationEntry; |
| 76 import org.chromium.content_public.browser.navigation_controller.LoadURLType; |
| 77 import org.chromium.content_public.common.Referrer; |
| 78 import org.chromium.ui.base.PageTransition; |
| 79 |
| 80 /** |
| 81 * This is the main activity for Chrome while running in document mode. Each ac
tivity |
| 82 * instance represents a single web page at a time while providing Chrome functi
onality. |
| 83 * |
| 84 * <p> |
| 85 * Tab switching is handled via the system wide Android task management system. |
| 86 */ |
| 87 @TargetApi(Build.VERSION_CODES.LOLLIPOP) |
| 88 public class DocumentActivity extends CompositorChromeActivity { |
| 89 protected static final String KEY_INITIAL_URL = "DocumentActivity.KEY_INITIA
L_URL"; |
| 90 |
| 91 private static final String TAG = "DocumentActivity"; |
| 92 |
| 93 private static final int APP_ICON_MIN_SIZE_DP = 32; |
| 94 private static final int APP_ICON_SIZE_DP = 64; |
| 95 private static final int APP_ICON_CORNER_RADIUS_DP = 3; |
| 96 private static final int APP_ICON_TEXT_SIZE_DP = 30; |
| 97 private static final int APP_ICON_DEFAULT_BACKGROUND_COLOR = Color.rgb(50, 5
0, 50); |
| 98 |
| 99 // Animation exit duration defined in chrome/android/java/res/anim/menu_exit
.xml as 150ms, |
| 100 // plus add another 20ms for a re-layout. |
| 101 private static final int MENU_EXIT_ANIMATION_WAIT_MS = 170; |
| 102 |
| 103 private DocumentTabModel mTabModel; |
| 104 private InitializationObserver mTabInitializationObserver; |
| 105 |
| 106 private Bitmap mIcon; |
| 107 // Indicates whether mIcon was generated by RoundedIconGenerator. |
| 108 private boolean mIsUsingGeneratedIcon; |
| 109 |
| 110 private Integer mThemeColor; |
| 111 private int mDefaultThemeColor; |
| 112 |
| 113 private DocumentTab mDocumentTab; |
| 114 private ToolbarHelper mToolbarHelper; |
| 115 |
| 116 private ChromeAppMenuPropertiesDelegate mChromeAppMenuPropertiesDelegate; |
| 117 private AppMenuHandler mAppMenuHandler; |
| 118 private RoundedIconGenerator mDocumentAppIconGenerator; |
| 119 private FindToolbarManager mFindToolbarManager; |
| 120 private boolean mRecordedStartupUma; |
| 121 |
| 122 // Whether the page has started loading in this (browser) process once alrea
dy. Must only be |
| 123 // used from the UI thread. |
| 124 private static boolean sIsFirstPageLoadStart = true; |
| 125 |
| 126 /** Whether the DocumentTab has already been added to the TabModel. */ |
| 127 private boolean mNeedsToBeAddedToTabModel; |
| 128 |
| 129 @Override |
| 130 protected boolean isStartedUpCorrectly(Intent intent) { |
| 131 int tabId = ActivityDelegate.getTabIdFromIntent(getIntent()); |
| 132 boolean isDocumentMode = FeatureUtilities.isDocumentMode(this); |
| 133 boolean isStartedUpCorrectly = tabId != Tab.INVALID_TAB_ID && isDocument
Mode; |
| 134 if (!isStartedUpCorrectly) { |
| 135 Log.e(TAG, "Discarding Intent: Tab = " + tabId + ", Document mode =
" + isDocumentMode); |
| 136 } |
| 137 return isStartedUpCorrectly; |
| 138 } |
| 139 |
| 140 @Override |
| 141 public void preInflationStartup() { |
| 142 // Decide whether to record startup UMA histograms. This is done early
in the main |
| 143 // Activity.onCreate() to avoid recording navigation delays when they re
quire user input to |
| 144 // proceed. See more details in ChromeTabbedActivity.preInflationStartup
(). |
| 145 if (!LibraryLoader.isInitialized()) { |
| 146 UmaUtils.setRunningApplicationStart(true); |
| 147 } |
| 148 |
| 149 DocumentTabModelSelector.setPrioritizedTabId( |
| 150 ActivityDelegate.getTabIdFromIntent(getIntent())); |
| 151 |
| 152 mTabModel = ChromeMobileApplication.getDocumentTabModelSelector().getMod
el(isIncognito()); |
| 153 mTabModel.startTabStateLoad(); |
| 154 updateLastTabId(); |
| 155 |
| 156 SingleTabModelSelector selector = new SingleTabModelSelector(this, isInc
ognito(), false) { |
| 157 @Override |
| 158 public Tab openNewTab(LoadUrlParams loadUrlParams, TabLaunchType typ
e, Tab parent, |
| 159 boolean incognito) { |
| 160 PendingDocumentData params = null; |
| 161 if (loadUrlParams.getPostData() != null |
| 162 || loadUrlParams.getVerbatimHeaders() != null |
| 163 || loadUrlParams.getReferrer() != null) { |
| 164 params = new PendingDocumentData(); |
| 165 params.postData = loadUrlParams.getPostData(); |
| 166 params.extraHeaders = loadUrlParams.getVerbatimHeaders(); |
| 167 params.referrer = loadUrlParams.getReferrer(); |
| 168 } |
| 169 |
| 170 int launchMode = type == TabLaunchType.FROM_LONGPRESS_BACKGROUND |
| 171 ? ChromeLauncherActivity.LAUNCH_MODE_AFFILIATED |
| 172 : ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND; |
| 173 Activity parentActivity = |
| 174 parent == null ? null : parent.getWindowAndroid().getAct
ivity().get(); |
| 175 ChromeLauncherActivity.launchDocumentInstance(parentActivity, in
cognito, |
| 176 launchMode, loadUrlParams.getUrl(), |
| 177 DocumentMetricIds.STARTED_BY_WINDOW_OPEN, |
| 178 loadUrlParams.getTransitionType(), false, params); |
| 179 return null; |
| 180 } |
| 181 }; |
| 182 setTabModelSelector(selector); |
| 183 |
| 184 super.preInflationStartup(); |
| 185 |
| 186 supportRequestWindowFeature(Window.FEATURE_ACTION_MODE_OVERLAY); |
| 187 } |
| 188 |
| 189 @Override |
| 190 protected int getControlContainerLayoutId() { |
| 191 return R.layout.control_container; |
| 192 } |
| 193 |
| 194 @Override |
| 195 public void postInflationStartup() { |
| 196 super.postInflationStartup(); |
| 197 |
| 198 ToolbarControlContainer controlContainer = |
| 199 ((ToolbarControlContainer) findViewById(R.id.control_container))
; |
| 200 mChromeAppMenuPropertiesDelegate = new ChromeAppMenuPropertiesDelegate(t
his); |
| 201 mAppMenuHandler = new AppMenuHandler(this, mChromeAppMenuPropertiesDeleg
ate, |
| 202 R.menu.main_menu); |
| 203 mToolbarHelper = new ToolbarHelper(this, controlContainer, mAppMenuHandl
er, |
| 204 mChromeAppMenuPropertiesDelegate, getCompositorViewHolder().getI
nvalidator()); |
| 205 |
| 206 final int tabId = ActivityDelegate.getTabIdFromIntent(getIntent()); |
| 207 mTabInitializationObserver = new InitializationObserver(mTabModel) { |
| 208 @Override |
| 209 public boolean isSatisfied(int currentState) { |
| 210 return currentState >= DocumentTabModelImpl.STATE_LOAD_TAB_S
TATE_BG_END |
| 211 || mTabModel.isTabStateReady(tabId); |
| 212 } |
| 213 |
| 214 @Override |
| 215 public boolean isCanceled() { |
| 216 return isDestroyed() || isFinishing(); |
| 217 } |
| 218 |
| 219 @Override |
| 220 public void runImmediately() { |
| 221 initializeUI(); |
| 222 } |
| 223 }; |
| 224 } |
| 225 |
| 226 @Override |
| 227 @VisibleForTesting |
| 228 public AppMenuHandler getAppMenuHandler() { |
| 229 return mAppMenuHandler; |
| 230 } |
| 231 |
| 232 @Override |
| 233 public void prepareMenu(Menu menu) { |
| 234 if (isNewTabPage() && !isIncognito()) { |
| 235 menu.findItem(R.id.new_tab_menu_id).setVisible(false); |
| 236 } |
| 237 } |
| 238 |
| 239 @Override |
| 240 public void finishNativeInitialization() { |
| 241 ChromePreferenceManager preferenceManager = |
| 242 ChromePreferenceManager.getInstance(this); |
| 243 if (isNewTabPage() && FirstRunStatus.getFirstRunFlowComplete(this)) { |
| 244 // Only show promos on second NTP. |
| 245 if (preferenceManager.getPromosSkippedOnFirstStart()) { |
| 246 // Data reduction promo should be temporarily suppressed if the
sign in promo is |
| 247 // shown to avoid nagging users too much. |
| 248 if (!SigninPromoScreen.launchSigninPromoIfNeeded(this)) { |
| 249 DataReductionPromoScreen.launchDataReductionPromo(this); |
| 250 } |
| 251 } else { |
| 252 preferenceManager.setPromosSkippedOnFirstStart(true); |
| 253 } |
| 254 } |
| 255 |
| 256 FirstRunSignInProcessor.start(this); |
| 257 |
| 258 if (!preferenceManager.hasAttemptedMigrationOnUpgrade()) { |
| 259 InitializationObserver observer = new InitializationObserver( |
| 260 ChromeMobileApplication.getDocumentTabModelSelector().getMod
el(false)) { |
| 261 @Override |
| 262 protected void runImmediately() { |
| 263 DocumentMigrationHelper.migrateTabsToDocumentForUpgrade(Docu
mentActivity.this, |
| 264 DocumentMigrationHelper.FINALIZE_MODE_NO_ACTION); |
| 265 } |
| 266 |
| 267 @Override |
| 268 public boolean isSatisfied(int currentState) { |
| 269 return currentState == DocumentTabModelImpl.STATE_FULLY_LOAD
ED; |
| 270 } |
| 271 |
| 272 @Override |
| 273 public boolean isCanceled() { |
| 274 return false; |
| 275 } |
| 276 }; |
| 277 |
| 278 observer.runWhenReady(); |
| 279 } |
| 280 |
| 281 getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS, |
| 282 Window.PROGRESS_VISIBILITY_OFF); |
| 283 |
| 284 // Initialize the native-side TabModels so that the Profile is available
when necessary. |
| 285 ChromeMobileApplication.getDocumentTabModelSelector().onNativeLibraryRea
dy(); |
| 286 mTabInitializationObserver.runWhenReady(); |
| 287 |
| 288 if (mNeedsToBeAddedToTabModel) { |
| 289 mNeedsToBeAddedToTabModel = false; |
| 290 mTabModel.addTab(getIntent(), mDocumentTab); |
| 291 getTabModelSelector().setTab(mDocumentTab); |
| 292 } |
| 293 |
| 294 super.finishNativeInitialization(); |
| 295 } |
| 296 |
| 297 @Override |
| 298 protected void onDeferredStartup() { |
| 299 super.onDeferredStartup(); |
| 300 mToolbarHelper.onDeferredStartup(); |
| 301 } |
| 302 |
| 303 @Override |
| 304 public boolean hasDoneFirstDraw() { |
| 305 return mToolbarHelper.hasDoneFirstDraw(); |
| 306 } |
| 307 |
| 308 /** |
| 309 * @return The ID of the Tab. |
| 310 */ |
| 311 protected final int determineTabId() { |
| 312 int tabId = ActivityDelegate.getTabIdFromIntent(getIntent()); |
| 313 if (tabId == Tab.INVALID_TAB_ID && mDocumentTab != null) tabId = mDocume
ntTab.getId(); |
| 314 return tabId; |
| 315 } |
| 316 |
| 317 /** |
| 318 * Determine the last known URL that this Document was displaying when it wa
s stopped. |
| 319 * @return URL that the user was last known to have seen, or null if one cou
ldn't be found. |
| 320 */ |
| 321 private String determineLastKnownUrl() { |
| 322 int tabId = determineTabId(); |
| 323 String url = mTabModel.getCurrentUrlForDocument(tabId); |
| 324 if (TextUtils.isEmpty(url)) url = determineInitialUrl(tabId); |
| 325 return url; |
| 326 } |
| 327 |
| 328 /** |
| 329 * Determine the URL that this Document was initially opened for. It can be
stashed in multiple |
| 330 * locations because IncognitoDocumentActivities are disallowed from passing
URLs in the Intent. |
| 331 * @param tabId ID of the Tab owned by this Activity. |
| 332 * @return Initial URL, or null if it couldn't be determined. |
| 333 */ |
| 334 protected String determineInitialUrl(int tabId) { |
| 335 String initialUrl = null; |
| 336 |
| 337 // Check if the TabModel has it. |
| 338 if (mTabModel != null) { |
| 339 initialUrl = mTabModel.getInitialUrlForDocument(tabId); |
| 340 } |
| 341 |
| 342 // Check if the URL was passed through the Intent. |
| 343 if (TextUtils.isEmpty(initialUrl) && getIntent() != null) { |
| 344 initialUrl = IntentHandler.getUrlFromIntent(getIntent()); |
| 345 } |
| 346 |
| 347 // Check the Tab's history. |
| 348 if (TextUtils.isEmpty(initialUrl) && mDocumentTab != null |
| 349 && mDocumentTab.getWebContents() != null) { |
| 350 NavigationEntry entry = |
| 351 mDocumentTab.getWebContents().getNavigationController().getE
ntryAtIndex(0); |
| 352 if (entry != null) initialUrl = entry.getOriginalUrl(); |
| 353 } |
| 354 |
| 355 return initialUrl; |
| 356 } |
| 357 |
| 358 @Override |
| 359 public CharSequence onCreateDescription() { |
| 360 return mDocumentTab != null ? mDocumentTab.getTitle() : ""; |
| 361 } |
| 362 |
| 363 @Override |
| 364 public final DocumentTab getActivityTab() { |
| 365 return mDocumentTab; |
| 366 } |
| 367 |
| 368 @Override |
| 369 public void onStartWithNative() { |
| 370 super.onStartWithNative(); |
| 371 handleDocumentUma(); |
| 372 ChromeLauncherActivity.sendExceptionCount(); |
| 373 } |
| 374 |
| 375 private void handleDocumentUma() { |
| 376 if (mRecordedStartupUma) { |
| 377 DocumentUma.recordStartedBy( |
| 378 DocumentMetricIds.STARTED_BY_ACTIVITY_BROUGHT_TO_FOREGROUND)
; |
| 379 } else { |
| 380 mRecordedStartupUma = true; |
| 381 |
| 382 if (getSavedInstanceState() == null) { |
| 383 DocumentUma.recordStartedBy(getPackageName(), getIntent()); |
| 384 } else { |
| 385 DocumentUma.recordStartedBy(DocumentMetricIds.STARTED_BY_ACTIVIT
Y_RESTARTED); |
| 386 } |
| 387 } |
| 388 DocumentUma.recordInDocumentMode(true); |
| 389 } |
| 390 |
| 391 @Override |
| 392 public void onPause() { |
| 393 // If finishing, release all the active media players as we don't know w
hen onStop() |
| 394 // will get called. |
| 395 super.onPause(); |
| 396 if (isFinishing() && mDocumentTab != null && mDocumentTab.getWebContents
() != null) { |
| 397 mDocumentTab.getWebContents().releaseMediaPlayers(); |
| 398 } |
| 399 } |
| 400 |
| 401 @Override |
| 402 public void onWindowFocusChanged(boolean hasWindowFocus) { |
| 403 if (hasWindowFocus) updateLastTabId(); |
| 404 } |
| 405 |
| 406 @Override |
| 407 public void onResume() { |
| 408 super.onResume(); |
| 409 |
| 410 if (getIntent() != null) { |
| 411 DocumentUtils.finishOtherTasksWithTabID( |
| 412 ActivityDelegate.getTabIdFromIntent(getIntent()), getTaskId(
)); |
| 413 } |
| 414 } |
| 415 |
| 416 @Override |
| 417 public void onResumeWithNative() { |
| 418 super.onResumeWithNative(); |
| 419 |
| 420 if (mDocumentTab != null) { |
| 421 PendingDocumentData pendingData = ChromeMobileApplication.getDocumen
tTabModelSelector() |
| 422 .removePendingDocumentData(ActivityDelegate.getTabIdFromInte
nt(getIntent())); |
| 423 if (pendingData != null && pendingData.url != null) { |
| 424 loadLastKnownUrl(pendingData); |
| 425 } |
| 426 mDocumentTab.show(TabSelectionType.FROM_USER); |
| 427 } |
| 428 } |
| 429 |
| 430 @Override |
| 431 protected void onDestroyInternal() { |
| 432 if (mToolbarHelper != null) mToolbarHelper.destroy(); |
| 433 |
| 434 super.onDestroyInternal(); |
| 435 } |
| 436 |
| 437 @Override |
| 438 public void onStopWithNative() { |
| 439 if (mDocumentTab != null) { |
| 440 mDocumentTab.setShouldPreserve(!IntentUtils.safeGetBooleanExtra(getI
ntent(), |
| 441 IntentHandler.EXTRA_APPEND_TASK, false)); |
| 442 mTabModel.updateEntry(getIntent(), mDocumentTab); |
| 443 } |
| 444 if (mAppMenuHandler != null) mAppMenuHandler.hideAppMenu(); |
| 445 super.onStopWithNative(); |
| 446 } |
| 447 |
| 448 @Override |
| 449 public SingleTabModelSelector getTabModelSelector() { |
| 450 return (SingleTabModelSelector) super.getTabModelSelector(); |
| 451 } |
| 452 |
| 453 @Override |
| 454 public void onConfigurationChanged(Configuration newConfig) { |
| 455 if (mAppMenuHandler != null) mAppMenuHandler.hideAppMenu(); |
| 456 super.onConfigurationChanged(newConfig); |
| 457 } |
| 458 |
| 459 @Override |
| 460 public void onOrientationChange(int orientation) { |
| 461 super.onOrientationChange(orientation); |
| 462 mToolbarHelper.onOrientationChange(); |
| 463 } |
| 464 |
| 465 @Override |
| 466 protected void onAccessibilityModeChanged(boolean enabled) { |
| 467 super.onAccessibilityModeChanged(enabled); |
| 468 mToolbarHelper.onAccessibilityStatusChanged(enabled); |
| 469 } |
| 470 |
| 471 private void loadLastKnownUrl(PendingDocumentData pendingData) { |
| 472 Intent intent = getIntent(); |
| 473 if (pendingData != null && pendingData.originalIntent != null) { |
| 474 intent = pendingData.originalIntent; |
| 475 } |
| 476 boolean isIntentChromeOrFirstParty = IntentHandler.isIntentChromeOrFirst
Party(intent, |
| 477 getApplicationContext()); |
| 478 int transitionType = intent == null ? PageTransition.LINK |
| 479 : IntentUtils.safeGetIntExtra(intent, IntentHandler.EXTRA_PAGE_T
RANSITION_TYPE, |
| 480 PageTransition.LINK); |
| 481 if ((transitionType != PageTransition.TYPED) |
| 482 && (transitionType != PageTransition.LINK) |
| 483 && !isIntentChromeOrFirstParty) { |
| 484 // Only 1st party authenticated applications can set the transition
type to be |
| 485 // anything other than TYPED for security reasons. |
| 486 transitionType = PageTransition.LINK; |
| 487 } |
| 488 |
| 489 if (transitionType == PageTransition.LINK) { |
| 490 transitionType |= PageTransition.FROM_API; |
| 491 } |
| 492 |
| 493 String url = (pendingData != null && pendingData.url != null) ? pendingD
ata.url : |
| 494 determineLastKnownUrl(); |
| 495 |
| 496 LoadUrlParams loadUrlParams = new LoadUrlParams(url, transitionType); |
| 497 if (getIntent() != null) { |
| 498 loadUrlParams.setIntentReceivedTimestamp(getOnCreateTimestampUptimeM
s()); |
| 499 } |
| 500 |
| 501 Uri referrerExtra = null; |
| 502 if (isIntentChromeOrFirstParty |
| 503 && IntentUtils.safeGetParcelableExtra(intent, Intent.EXTRA_REFER
RER) != null) { |
| 504 referrerExtra = (Uri) IntentUtils.safeGetParcelableExtra(intent, Int
ent.EXTRA_REFERRER); |
| 505 loadUrlParams.setReferrer(new Referrer( |
| 506 referrerExtra.toString(), 1 /* WebReferrerPolicyDefault */))
; |
| 507 } |
| 508 |
| 509 if (pendingData != null) { |
| 510 if (pendingData.postData != null) { |
| 511 loadUrlParams.setPostData(pendingData.postData); |
| 512 loadUrlParams.setLoadType(LoadURLType.BROWSER_INITIATED_HTTP_POS
T); |
| 513 } |
| 514 loadUrlParams.setVerbatimHeaders(pendingData.extraHeaders); |
| 515 loadUrlParams.setReferrer(pendingData.referrer); |
| 516 mDocumentTab.getTabRedirectHandler().updateIntent(pendingData.origin
alIntent); |
| 517 } else { |
| 518 if (getIntent() != null) { |
| 519 try { |
| 520 intent = IntentUtils.safeGetParcelableExtra(getIntent(), |
| 521 IntentHandler.EXTRA_ORIGINAL_INTENT); |
| 522 } catch (Throwable t) { |
| 523 // Ignore exception. |
| 524 } |
| 525 } |
| 526 mDocumentTab.getTabRedirectHandler().updateIntent(intent); |
| 527 } |
| 528 |
| 529 mDocumentTab.loadUrl(loadUrlParams); |
| 530 if (pendingData != null && pendingData.requestId > 0) { |
| 531 ServiceTabLauncher.onWebContentsForRequestAvailable( |
| 532 pendingData.requestId, mDocumentTab.getWebContents()); |
| 533 } |
| 534 |
| 535 if (getIntent() != null && IntentUtils.safeGetBooleanExtra(getIntent(), |
| 536 IntentHandler.EXTRA_USE_DESKTOP_USER_AGENT, false)) { |
| 537 // The desktop user agent can't be carried over without the Tab alre
ady having a URL, |
| 538 // so we're forced to set the user agent and then reload the page. |
| 539 mDocumentTab.setUseDesktopUserAgent(true, true); |
| 540 } |
| 541 } |
| 542 |
| 543 @Override |
| 544 public void terminateIncognitoSession() { |
| 545 ChromeMobileApplication.getDocumentTabModelSelector().getModel(true).clo
seAllTabs(); |
| 546 } |
| 547 |
| 548 private void initializeUI() { |
| 549 mDefaultThemeColor = isIncognito() |
| 550 ? getResources().getColor(R.color.incognito_primary_color) |
| 551 : getResources().getColor(R.color.default_primary_color); |
| 552 PendingDocumentData pendingData = ChromeMobileApplication.getDocumentTab
ModelSelector() |
| 553 .removePendingDocumentData(ActivityDelegate.getTabIdFromIntent(g
etIntent())); |
| 554 int tabId = determineTabId(); |
| 555 TabState tabState = mTabModel.getTabStateForDocument(tabId); |
| 556 mDocumentTab = DocumentTab.create(DocumentActivity.this, isIncognito(), |
| 557 getWindowAndroid(), determineLastKnownUrl(), |
| 558 pendingData != null ? pendingData.webContents : null, |
| 559 pendingData != null ? pendingData.webContentsPaused : false, tab
State); |
| 560 if (mTabModel.isNativeInitialized()) { |
| 561 mTabModel.addTab(getIntent(), mDocumentTab); |
| 562 } else { |
| 563 mNeedsToBeAddedToTabModel = true; |
| 564 } |
| 565 |
| 566 mAppMenuHandler.addObserver(new AppMenuObserver() { |
| 567 @Override |
| 568 public void onMenuVisibilityChanged(boolean isVisible) { |
| 569 if (!isVisible) { |
| 570 mChromeAppMenuPropertiesDelegate.onMenuDismissed(); |
| 571 } |
| 572 } |
| 573 }); |
| 574 |
| 575 getTabModelSelector().setTab(mDocumentTab); |
| 576 |
| 577 if (!mDocumentTab.didRestoreState() || (pendingData != null && pendingDa
ta.url != null)) { |
| 578 if (!mDocumentTab.isCreatedWithWebContents()) { |
| 579 // Don't load tabs in the background on low end devices. We will
call |
| 580 // loadLastKnownUrl() in onResumeWithNative() next time activity
is resumed. |
| 581 int launchMode = IntentUtils.safeGetIntExtra(getIntent(), |
| 582 ChromeLauncherActivity.EXTRA_LAUNCH_MODE, |
| 583 ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND); |
| 584 if (SysUtils.isLowEndDevice() |
| 585 && launchMode == ChromeLauncherActivity.LAUNCH_MODE_AFFI
LIATED |
| 586 && pendingData != null) { |
| 587 // onResumeWithNative() wants pendingData.url to be non-null |
| 588 if (pendingData.url == null) { |
| 589 pendingData.url = determineLastKnownUrl(); |
| 590 } |
| 591 ChromeMobileApplication.getDocumentTabModelSelector().addPen
dingDocumentData( |
| 592 ActivityDelegate.getTabIdFromIntent(getIntent()), pe
ndingData); |
| 593 // Use the URL as the document title until tab is loaded |
| 594 updateTaskDescription(pendingData.url, null); |
| 595 } else { |
| 596 loadLastKnownUrl(pendingData); |
| 597 } |
| 598 } |
| 599 mDocumentTab.setShouldPreserve(IntentUtils.safeGetBooleanExtra(getIn
tent(), |
| 600 IntentHandler.EXTRA_PRESERVE_TASK, false)); |
| 601 } |
| 602 |
| 603 ToolbarControlContainer controlContainer = |
| 604 (ToolbarControlContainer) findViewById(R.id.control_container); |
| 605 LayoutManagerDocument layoutDriver = new LayoutManagerDocument(getCompos
itorViewHolder()); |
| 606 initializeCompositorContent(layoutDriver, findViewById(R.id.url_bar), |
| 607 (ViewGroup) findViewById(android.R.id.content), controlContainer
); |
| 608 |
| 609 mFindToolbarManager = new FindToolbarManager(this, getTabModelSelector()
, |
| 610 mToolbarHelper.getContextualMenuBar() |
| 611 .getCustomSelectionActionModeCallback()); |
| 612 controlContainer.setFindToolbarManager(mFindToolbarManager); |
| 613 if (getContextualSearchManager() != null) { |
| 614 getContextualSearchManager().setFindToolbarManager(mFindToolbarManag
er); |
| 615 } |
| 616 |
| 617 mToolbarHelper.initializeControls( |
| 618 mFindToolbarManager, null, layoutDriver, null, null, null, null)
; |
| 619 |
| 620 mDocumentTab.setFullscreenManager(getFullscreenManager()); |
| 621 |
| 622 mDocumentTab.addObserver(new DocumentTabObserver() { |
| 623 @Override |
| 624 public void onPageLoadStarted(Tab tab) { |
| 625 // Discard startup navigation measurements when the user interfe
red and started the |
| 626 // 2nd navigation (in activity lifetime) in parallel. |
| 627 if (!sIsFirstPageLoadStart) { |
| 628 UmaUtils.setRunningApplicationStart(false); |
| 629 } else { |
| 630 sIsFirstPageLoadStart = false; |
| 631 } |
| 632 } |
| 633 |
| 634 @Override |
| 635 public void onWebContentsSwapped(Tab tab, boolean didStartLoad, bool
ean didFinishLoad) { |
| 636 if (!didStartLoad) return; |
| 637 mThemeColor = tab.getWebContents().getThemeColor(mDefaultThemeCo
lor); |
| 638 mIcon = null; |
| 639 updateTaskDescription(); |
| 640 } |
| 641 |
| 642 @Override |
| 643 protected void onFaviconReceived(Bitmap image) { |
| 644 super.onFaviconReceived(image); |
| 645 int newHeight = image.getHeight(); |
| 646 int newWidth = image.getWidth(); |
| 647 int minSize = |
| 648 (int) getResources().getDisplayMetrics().density * APP_I
CON_MIN_SIZE_DP; |
| 649 if (newHeight < minSize || newWidth < minSize) return; |
| 650 if (mIcon != null && !mIsUsingGeneratedIcon && mIcon.getWidth()
>= newWidth |
| 651 && mIcon.getHeight() >= newHeight) { |
| 652 return; |
| 653 } |
| 654 mIcon = image; |
| 655 mIsUsingGeneratedIcon = false; |
| 656 updateTaskDescription(); |
| 657 } |
| 658 |
| 659 @Override |
| 660 public void onUrlUpdated(Tab tab) { |
| 661 assert mDocumentTab == tab; |
| 662 |
| 663 updateTaskDescription(); |
| 664 mTabModel.updateEntry(getIntent(), mDocumentTab); |
| 665 } |
| 666 |
| 667 @Override |
| 668 public void onTitleUpdated(Tab tab) { |
| 669 super.onTitleUpdated(tab); |
| 670 updateTaskDescription(); |
| 671 } |
| 672 |
| 673 @Override |
| 674 public void onSSLStateUpdated(Tab tab) { |
| 675 int securityLevel = tab.getSecurityLevel(); |
| 676 if (securityLevel == ConnectionSecurityHelperSecurityLevel.SECUR
ITY_ERROR |
| 677 || securityLevel == ConnectionSecurityHelperSecurityLeve
l.SECURITY_WARNING |
| 678 || securityLevel |
| 679 == ConnectionSecurityHelperSecurityLevel.SECURITY_POL
ICY_WARNING) { |
| 680 resetThemeColorAndIcon(); |
| 681 } |
| 682 } |
| 683 |
| 684 @Override |
| 685 public void onDidNavigateMainFrame(Tab tab, String url, String baseU
rl, |
| 686 boolean isNavigationToDifferentPage, boolean isFragmentNavig
ation, |
| 687 int statusCode) { |
| 688 if (!isNavigationToDifferentPage) return; |
| 689 mIcon = null; |
| 690 } |
| 691 |
| 692 @Override |
| 693 public void onLoadStopped(Tab tab) { |
| 694 assert mDocumentTab == tab; |
| 695 |
| 696 updateTaskDescription(); |
| 697 mTabModel.updateEntry(getIntent(), mDocumentTab); |
| 698 } |
| 699 |
| 700 @Override |
| 701 public void onDidChangeThemeColor(int color) { |
| 702 if (color == Color.TRANSPARENT) color = mDefaultThemeColor; |
| 703 |
| 704 // Ignore any transparency value. |
| 705 color |= 0xFF000000; |
| 706 |
| 707 mThemeColor = Integer.valueOf(color); |
| 708 updateTaskDescription(); |
| 709 } |
| 710 |
| 711 @Override |
| 712 public void onDidAttachInterstitialPage(Tab tab) { |
| 713 resetThemeColorAndIcon(); |
| 714 } |
| 715 |
| 716 @Override |
| 717 public void onDidDetachInterstitialPage(Tab tab) { |
| 718 mThemeColor = tab.getWebContents().getThemeColor(mDefaultThemeCo
lor); |
| 719 mIcon = null; |
| 720 updateTaskDescription(); |
| 721 } |
| 722 |
| 723 @Override |
| 724 public void onCrash(Tab tab, boolean sadTabShown) { |
| 725 int currentState = ApplicationStatus.getStateForActivity(Documen
tActivity.this); |
| 726 if (currentState != ActivityState.STOPPED) return; |
| 727 |
| 728 if (!isTaskRoot() || IntentUtils.safeGetBooleanExtra(getIntent()
, |
| 729 IntentHandler.EXTRA_APPEND_TASK, false)) { |
| 730 return; |
| 731 } |
| 732 |
| 733 // Finishing backgrounded Activities whose renderers have crashe
d allows us to |
| 734 // destroy them and return resources sooner than if we wait for
Android to destroy |
| 735 // the Activities themselves. Problematically, this also remove
s |
| 736 // IncognitoDocumentActivity instances from Android's Recents me
nu and auto-closes |
| 737 // the tab. Instead, take a hit and keep the Activities alive -
- Android will |
| 738 // eventually destroy the Activities, anyway (crbug.com/450292). |
| 739 if (!isIncognito()) finish(); |
| 740 } |
| 741 |
| 742 @Override |
| 743 public void onSetCoveredByChildActivity() { |
| 744 mTabModel.updateEntry(getIntent(), mDocumentTab); |
| 745 } |
| 746 }); |
| 747 |
| 748 removeWindowBackground(); |
| 749 |
| 750 if (mDocumentTab != null) { |
| 751 BandwidthReductionPreferences.launchDataReductionSSLInfoBar( |
| 752 DocumentActivity.this, mDocumentTab.getWebContents()); |
| 753 } |
| 754 } |
| 755 |
| 756 private void resetThemeColorAndIcon() { |
| 757 mThemeColor = null; |
| 758 mIcon = null; |
| 759 updateTaskDescription(); |
| 760 } |
| 761 |
| 762 private void updateLastTabId() { |
| 763 ChromeMobileApplication.getDocumentTabModelSelector().selectModel(isInco
gnito()); |
| 764 int tabId = mDocumentTab == null |
| 765 ? ActivityDelegate.getTabIdFromIntent(getIntent()) : mDocumentT
ab.getId(); |
| 766 mTabModel.setLastShownId(tabId); |
| 767 } |
| 768 |
| 769 @Override |
| 770 public boolean handleBackPressed() { |
| 771 if (mDocumentTab == null) return false; |
| 772 |
| 773 View view = ContentVideoView.getContentVideoView(); |
| 774 if (view != null && view.getContext() == this) { |
| 775 ContentVideoView.getContentVideoView().exitFullscreen(false); |
| 776 return true; |
| 777 } |
| 778 |
| 779 if (getFullscreenManager().getPersistentFullscreenMode()) { |
| 780 getFullscreenManager().setPersistentFullscreenMode(false); |
| 781 return true; |
| 782 } |
| 783 |
| 784 if (mDocumentTab.canGoBack()) { |
| 785 mDocumentTab.goBack(); |
| 786 } else if (!mDocumentTab.shouldPreserve()) { |
| 787 finishAndRemoveTask(); |
| 788 } else { |
| 789 moveTaskToBack(true); |
| 790 } |
| 791 return true; |
| 792 } |
| 793 |
| 794 @Override |
| 795 public boolean createContextualSearchTab(ContentViewCore searchContentViewCo
re) { |
| 796 NavigationEntry entry = |
| 797 searchContentViewCore.getWebContents().getNavigationController()
.getPendingEntry(); |
| 798 String url = entry != null |
| 799 ? entry.getUrl() : searchContentViewCore.getWebContents().getUrl
(); |
| 800 PendingDocumentData documentData = new PendingDocumentData(); |
| 801 ChromeLauncherActivity.launchDocumentInstance(this, false, |
| 802 ChromeLauncherActivity.LAUNCH_MODE_FOREGROUND, url, |
| 803 DocumentMetricIds.STARTED_BY_CONTEXTUAL_SEARCH, |
| 804 PageTransition.LINK, false, documentData); |
| 805 return false; |
| 806 } |
| 807 |
| 808 @Override |
| 809 public boolean onMenuOrKeyboardAction(int id, boolean fromMenu) { |
| 810 if (id == R.id.new_tab_menu_id) { |
| 811 mHandler.postDelayed(new Runnable() { |
| 812 @Override |
| 813 public void run() { |
| 814 launchNtp(false); |
| 815 } |
| 816 }, MENU_EXIT_ANIMATION_WAIT_MS); |
| 817 RecordUserAction.record("MobileMenuNewTab"); |
| 818 RecordUserAction.record("MobileNewTabOpened"); |
| 819 } else if (id == R.id.new_incognito_tab_menu_id) { |
| 820 // This action must be recorded before opening the incognito tab sin
ce UMA actions |
| 821 // are dropped when an incognito tab is open. |
| 822 RecordUserAction.record("MobileMenuNewIncognitoTab"); |
| 823 RecordUserAction.record("MobileNewTabOpened"); |
| 824 mHandler.postDelayed(new Runnable() { |
| 825 @Override |
| 826 public void run() { |
| 827 launchNtp(true); |
| 828 } |
| 829 }, MENU_EXIT_ANIMATION_WAIT_MS); |
| 830 } else if (id == R.id.all_bookmarks_menu_id) { |
| 831 if (!EnhancedBookmarkUtils.showEnhancedBookmarkIfEnabled(this)) { |
| 832 DocumentNewTabPage.launchBookmarksDialog(this, mDocumentTab, get
TabModelSelector()); |
| 833 } |
| 834 RecordUserAction.record("MobileMenuAllBookmarks"); |
| 835 } else if (id == R.id.recent_tabs_menu_id) { |
| 836 DocumentNewTabPage.launchRecentTabsDialog(this, mDocumentTab, false)
; |
| 837 RecordUserAction.record("MobileMenuOpenTabs"); |
| 838 } else if (id == R.id.find_in_page_id) { |
| 839 mFindToolbarManager.showToolbar(); |
| 840 if (fromMenu) { |
| 841 RecordUserAction.record("MobileMenuFindInPage"); |
| 842 } else { |
| 843 RecordUserAction.record("MobileShortcutFindInPage"); |
| 844 } |
| 845 } else if (id == R.id.show_menu) { |
| 846 if (mToolbarHelper.isInitialized()) { |
| 847 mAppMenuHandler.showAppMenu(mToolbarHelper.getMenuAnchor(), true
, |
| 848 false); |
| 849 } |
| 850 } else if (id == R.id.focus_url_bar) { |
| 851 if (mToolbarHelper.isInitialized()) mToolbarHelper.setUrlBarFocus(tr
ue); |
| 852 } else { |
| 853 return super.onMenuOrKeyboardAction(id, fromMenu); |
| 854 } |
| 855 return true; |
| 856 } |
| 857 |
| 858 @Override |
| 859 public boolean dispatchKeyEvent(KeyEvent event) { |
| 860 Boolean result = KeyboardShortcuts.dispatchKeyEvent(event, this, |
| 861 mToolbarHelper.isInitialized()); |
| 862 return result != null ? result : super.dispatchKeyEvent(event); |
| 863 } |
| 864 |
| 865 @Override |
| 866 public boolean onKeyDown(int keyCode, KeyEvent event) { |
| 867 if (!mToolbarHelper.isInitialized()) return false; |
| 868 return KeyboardShortcuts.onKeyDown(event, this, true, false) |
| 869 || super.onKeyDown(keyCode, event); |
| 870 } |
| 871 |
| 872 @Override |
| 873 public boolean shouldShowAppMenu() { |
| 874 if (mDocumentTab == null || !mToolbarHelper.isInitialized()) { |
| 875 return false; |
| 876 } |
| 877 |
| 878 return super.shouldShowAppMenu(); |
| 879 } |
| 880 |
| 881 private void updateTaskDescription() { |
| 882 if (mDocumentTab == null) { |
| 883 updateTaskDescription(null, null); |
| 884 return; |
| 885 } |
| 886 |
| 887 if (isNewTabPage() && !isIncognito()) { |
| 888 // NTP needs a new color in recents, but uses the default applicatio
n title and icon; |
| 889 updateTaskDescription(null, null); |
| 890 return; |
| 891 } |
| 892 |
| 893 String label = mDocumentTab.getTitle(); |
| 894 String domain = UrlUtilities.getDomainAndRegistry(mDocumentTab.getUrl(),
false); |
| 895 if (TextUtils.isEmpty(label)) { |
| 896 label = domain; |
| 897 } |
| 898 if (mIcon == null && TextUtils.isEmpty(label)) { |
| 899 updateTaskDescription(null, null); |
| 900 return; |
| 901 } |
| 902 |
| 903 if (isIncognito()) { |
| 904 mIcon = null; |
| 905 } else if (mIcon == null) { |
| 906 if (mDocumentAppIconGenerator == null) { |
| 907 mDocumentAppIconGenerator = new RoundedIconGenerator(this, |
| 908 APP_ICON_SIZE_DP, APP_ICON_SIZE_DP, |
| 909 APP_ICON_CORNER_RADIUS_DP, APP_ICON_DEFAULT_BACKGROUND_C
OLOR, |
| 910 APP_ICON_TEXT_SIZE_DP); |
| 911 } |
| 912 mIcon = mDocumentAppIconGenerator.generateIconForUrl(mDocumentTab.ge
tUrl()); |
| 913 mIsUsingGeneratedIcon = true; |
| 914 } |
| 915 |
| 916 updateTaskDescription(label, mIcon); |
| 917 } |
| 918 |
| 919 protected int getThemeColor() { |
| 920 if (isIncognito()) { |
| 921 return mDefaultThemeColor; |
| 922 } else { |
| 923 return mThemeColor != null ? mThemeColor.intValue() : mDefaultThemeC
olor; |
| 924 } |
| 925 } |
| 926 |
| 927 private boolean shouldUseDefaultStatusBarColor() { |
| 928 return isIncognito() || mThemeColor == null || mThemeColor == mDefaultTh
emeColor; |
| 929 } |
| 930 |
| 931 protected void updateTaskDescription(String label, Bitmap icon) { |
| 932 int color = getThemeColor(); |
| 933 DocumentUtils.updateTaskDescription(this, label, icon, color, |
| 934 shouldUseDefaultStatusBarColor()); |
| 935 mToolbarHelper.setThemeColor(color); |
| 936 |
| 937 ControlContainer controlContainer = |
| 938 (ControlContainer) findViewById(R.id.control_container); |
| 939 controlContainer.getToolbarResourceAdapter().invalidate(null); |
| 940 } |
| 941 |
| 942 /** |
| 943 * @return Whether the {@link DocumentTab} this activity uses is incognito. |
| 944 */ |
| 945 protected boolean isIncognito() { |
| 946 return false; |
| 947 } |
| 948 |
| 949 /** |
| 950 * @return Whether this activity contains a tab that is showing the new tab
page. |
| 951 */ |
| 952 boolean isNewTabPage() { |
| 953 String url; |
| 954 if (mDocumentTab == null) { |
| 955 // If the Tab hasn't been created yet, then we're really early in in
itialization. |
| 956 // Use a combination of the original URL from the Intent and whether
or not the Tab is |
| 957 // retargetable to know whether or not the user navigated away from
the NTP. |
| 958 // If the Entry doesn't exist, then the DocumentActivity never got a
chance to add |
| 959 // itself to the TabList and is likely to be retargetable. |
| 960 int tabId = ActivityDelegate.getTabIdFromIntent(getIntent()); |
| 961 url = IntentHandler.getUrlFromIntent(getIntent()); |
| 962 if (mTabModel.hasEntryForTabId(tabId) && !mTabModel.isRetargetable(t
abId)) return false; |
| 963 } else { |
| 964 url = mDocumentTab.getUrl(); |
| 965 } |
| 966 return NewTabPage.isNTPUrl(url); |
| 967 } |
| 968 |
| 969 /** |
| 970 * Determines whether the given class can be classified as a DocumentActivit
y (this includes |
| 971 * both regular document activity and incognito document activity). |
| 972 * @param className The class name to inspect. |
| 973 * @return Whether the className is that of a document activity. |
| 974 */ |
| 975 public static boolean isDocumentActivity(String className) { |
| 976 return TextUtils.equals(className, IncognitoDocumentActivity.class.getNa
me()) |
| 977 || TextUtils.equals(className, DocumentActivity.class.getName())
; |
| 978 } |
| 979 |
| 980 /** |
| 981 * Launch a new DocumentActivity showing the new tab page. |
| 982 * @param incognito Whether the new NTP should be in incognito mode. |
| 983 */ |
| 984 private void launchNtp(boolean incognito) { |
| 985 if (incognito && !PrefServiceBridge.getInstance().isIncognitoModeEnabled
()) return; |
| 986 ChromeLauncherActivity.launchDocumentInstance(this, incognito, |
| 987 ChromeLauncherActivity.LAUNCH_MODE_RETARGET, UrlConstants.NTP_UR
L, |
| 988 DocumentMetricIds.STARTED_BY_OPTIONS_MENU, PageTransition.AUTO_T
OPLEVEL, false, |
| 989 null); |
| 990 } |
| 991 } |
OLD | NEW |