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; |
| 6 |
| 7 import android.annotation.SuppressLint; |
| 8 import android.app.Activity; |
| 9 import android.app.SearchManager; |
| 10 import android.content.Context; |
| 11 import android.content.Intent; |
| 12 import android.content.SharedPreferences; |
| 13 import android.graphics.Bitmap; |
| 14 import android.graphics.Rect; |
| 15 import android.os.Build; |
| 16 import android.os.Looper; |
| 17 import android.os.MessageQueue; |
| 18 import android.os.SystemClock; |
| 19 import android.preference.PreferenceManager; |
| 20 import android.provider.Settings; |
| 21 import android.provider.Settings.SettingNotFoundException; |
| 22 import android.util.DisplayMetrics; |
| 23 import android.view.Display; |
| 24 import android.view.Menu; |
| 25 import android.view.MenuItem; |
| 26 import android.view.Surface; |
| 27 import android.view.View; |
| 28 import android.view.Window; |
| 29 import android.view.WindowManager; |
| 30 import android.view.accessibility.AccessibilityManager; |
| 31 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeL
istener; |
| 32 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChan
geListener; |
| 33 |
| 34 import com.google.android.apps.chrome.R; |
| 35 |
| 36 import org.chromium.base.BaseSwitches; |
| 37 import org.chromium.base.CommandLine; |
| 38 import org.chromium.base.metrics.RecordUserAction; |
| 39 import org.chromium.chrome.browser.IntentHandler.IntentHandlerDelegate; |
| 40 import org.chromium.chrome.browser.IntentHandler.TabOpenType; |
| 41 import org.chromium.chrome.browser.compositor.layouts.content.ContentOffsetProvi
der; |
| 42 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; |
| 43 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager; |
| 44 import org.chromium.chrome.browser.device.DeviceClassManager; |
| 45 import org.chromium.chrome.browser.fullscreen.FullscreenManager; |
| 46 import org.chromium.chrome.browser.gsa.ContextReporter; |
| 47 import org.chromium.chrome.browser.gsa.GSAServiceClient; |
| 48 import org.chromium.chrome.browser.gsa.GSAState; |
| 49 import org.chromium.chrome.browser.infobar.InfoBarContainer; |
| 50 import org.chromium.chrome.browser.init.AsyncInitializationActivity; |
| 51 import org.chromium.chrome.browser.metrics.LaunchMetrics; |
| 52 import org.chromium.chrome.browser.metrics.UmaSessionStats; |
| 53 import org.chromium.chrome.browser.nfc.BeamController; |
| 54 import org.chromium.chrome.browser.nfc.BeamProvider; |
| 55 import org.chromium.chrome.browser.omaha.OmahaClient; |
| 56 import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomiza
tions; |
| 57 import org.chromium.chrome.browser.policy.PolicyManager.PolicyChangeListener; |
| 58 import org.chromium.chrome.browser.preferences.ChromePreferenceManager; |
| 59 import org.chromium.chrome.browser.share.ShareHelper; |
| 60 import org.chromium.chrome.browser.sync.ProfileSyncService; |
| 61 import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; |
| 62 import org.chromium.chrome.browser.tabmodel.EmptyTabModel; |
| 63 import org.chromium.chrome.browser.tabmodel.TabCreatorManager; |
| 64 import org.chromium.chrome.browser.tabmodel.TabModel; |
| 65 import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
| 66 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; |
| 67 import org.chromium.chrome.browser.tabmodel.TabModelUtils; |
| 68 import org.chromium.chrome.browser.tabmodel.TabWindowManager; |
| 69 import org.chromium.chrome.browser.util.FeatureUtilities; |
| 70 import org.chromium.content.browser.ContentReadbackHandler; |
| 71 import org.chromium.content.browser.ContentViewCore; |
| 72 import org.chromium.content.common.ContentSwitches; |
| 73 import org.chromium.content_public.browser.readback_types.ReadbackResponse; |
| 74 import org.chromium.ui.base.DeviceFormFactor; |
| 75 import org.chromium.ui.base.WindowAndroid; |
| 76 |
| 77 import java.lang.reflect.Field; |
| 78 |
| 79 /** |
| 80 * The main Chrome activity. This exposes extra methods that relate to the {@li
nk TabModelSelector} |
| 81 * and lists of tabs. |
| 82 */ |
| 83 public abstract class ChromeActivity extends AsyncInitializationActivity impleme
nts |
| 84 TabCreatorManager, AccessibilityStateChangeListener, PolicyChangeListene
r { |
| 85 |
| 86 private static final String SNAPSHOT_DATABASE_REMOVED = "snapshot_database_r
emoved"; |
| 87 private static final String SNAPSHOT_DATABASE_NAME = "snapshots.db"; |
| 88 |
| 89 /** Delay in ms after first page load finishes before we initiate deferred s
tartup actions. */ |
| 90 private static final int DEFERRED_STARTUP_DELAY_MS = 1000; |
| 91 |
| 92 /** |
| 93 * Timeout in ms for reading PartnerBrowserCustomizations provider. |
| 94 */ |
| 95 private static final int PARTNER_BROWSER_CUSTOMIZATIONS_TIMEOUT_MS = 10000; |
| 96 |
| 97 private TabModelSelector mTabModelSelector; |
| 98 private TabModelSelectorTabObserver mTabModelSelectorTabObserver; |
| 99 private ChromeTabCreator mRegularTabCreator; |
| 100 private ChromeTabCreator mIncognitoTabCreator; |
| 101 private TabContentManager mTabContentManager; |
| 102 private UmaSessionStats mUmaSessionStats; |
| 103 private ContextReporter mContextReporter; |
| 104 protected GSAServiceClient mGSAServiceClient; |
| 105 |
| 106 private int mCurrentOrientation = Surface.ROTATION_0; |
| 107 private boolean mPartnerBrowserRefreshNeeded = false; |
| 108 |
| 109 protected IntentHandler mIntentHandler; |
| 110 protected boolean mIsTablet = false; |
| 111 private long mLastUserInteractionTime; |
| 112 |
| 113 /** Whether onDeferredStartup() has been run. */ |
| 114 private boolean mDeferredStartupNotified; |
| 115 |
| 116 // The class cannot implement TouchExplorationStateChangeListener, |
| 117 // because it is only available for Build.VERSION_CODES.KITKAT and later. |
| 118 // We have to instantiate the TouchExplorationStateChangeListner object in t
he code. |
| 119 private TouchExplorationStateChangeListener mTouchExplorationStateChangeList
ener; |
| 120 |
| 121 // Observes when sync becomes ready to create the mContextReporter. |
| 122 private ProfileSyncService.SyncStateChangedListener mSyncStateChangedListene
r; |
| 123 |
| 124 @SuppressLint("NewApi") |
| 125 @Override |
| 126 protected void onDestroy() { |
| 127 getChromeApplication().removePolicyChangeListener(this); |
| 128 if (mTabContentManager != null) mTabContentManager.destroy(); |
| 129 if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.d
estroy(); |
| 130 |
| 131 AccessibilityManager manager = (AccessibilityManager) |
| 132 getBaseContext().getSystemService(Context.ACCESSIBILITY_SERVICE)
; |
| 133 manager.removeAccessibilityStateChangeListener(this); |
| 134 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { |
| 135 manager.removeTouchExplorationStateChangeListener(mTouchExplorationS
tateChangeListener); |
| 136 } |
| 137 |
| 138 super.onDestroy(); |
| 139 } |
| 140 |
| 141 /** |
| 142 * {@link TabModelSelector} no longer implements TabModel. Use getTabModelS
elector() or |
| 143 * getCurrentTabModel() depending on your needs. |
| 144 * @return The {@link TabModelSelector}, possibly null. |
| 145 */ |
| 146 public TabModelSelector getTabModelSelector() { |
| 147 return mTabModelSelector; |
| 148 } |
| 149 |
| 150 /** |
| 151 * Sets the {@link TabModelSelector} owned by this {@link ChromeActivity}. |
| 152 * @param tabModelSelector A {@link TabModelSelector} instance. |
| 153 */ |
| 154 protected void setTabModelSelector(TabModelSelector tabModelSelector) { |
| 155 mTabModelSelector = tabModelSelector; |
| 156 |
| 157 if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.d
estroy(); |
| 158 mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(tabModelS
elector) { |
| 159 @Override |
| 160 public void onLoadStopped(Tab tab) { |
| 161 postDeferredStartupIfNeeded(); |
| 162 showUpdateInfoBarIfNecessary(); |
| 163 } |
| 164 |
| 165 @Override |
| 166 public void onPageLoadFinished(Tab tab) { |
| 167 postDeferredStartupIfNeeded(); |
| 168 showUpdateInfoBarIfNecessary(); |
| 169 } |
| 170 |
| 171 @Override |
| 172 public void onCrash(Tab tab, boolean sadTabShown) { |
| 173 postDeferredStartupIfNeeded(); |
| 174 } |
| 175 }; |
| 176 } |
| 177 |
| 178 @Override |
| 179 public ChromeTabCreator getTabCreator(boolean incognito) { |
| 180 return incognito ? mIncognitoTabCreator : mRegularTabCreator; |
| 181 } |
| 182 |
| 183 /** |
| 184 * Sets the {@link ChromeTabCreator}s owned by this {@link ChromeActivity}. |
| 185 * @param regularTabCreator A {@link ChromeTabCreator} instance. |
| 186 */ |
| 187 public void setTabCreators(ChromeTabCreator regularTabCreator, |
| 188 ChromeTabCreator incognitoTabCreator) { |
| 189 mRegularTabCreator = regularTabCreator; |
| 190 mIncognitoTabCreator = incognitoTabCreator; |
| 191 } |
| 192 |
| 193 /** |
| 194 * Convenience method that returns a tab creator for the currently selected
{@link TabModel}. |
| 195 * @return A tab creator for the currently selected {@link TabModel}. |
| 196 */ |
| 197 public ChromeTabCreator getCurrentTabCreator() { |
| 198 return getTabCreator(getTabModelSelector().isIncognitoSelected()); |
| 199 } |
| 200 |
| 201 /** |
| 202 * Gets the {@link TabContentManager} instance which holds snapshots of the
tabs in this model. |
| 203 * @return The thumbnail cache, possibly null. |
| 204 */ |
| 205 public TabContentManager getTabContentManager() { |
| 206 return mTabContentManager; |
| 207 } |
| 208 |
| 209 /** |
| 210 * Sets the {@link TabContentManager} owned by this {@link ChromeActivity}. |
| 211 * @param tabContentManager A {@link TabContentManager} instance. |
| 212 */ |
| 213 protected void setTabContentManager(TabContentManager tabContentManager) { |
| 214 mTabContentManager = tabContentManager; |
| 215 } |
| 216 |
| 217 /** |
| 218 * Gets the current (inner) TabModel. This is a convenience function for |
| 219 * getModelSelector().getCurrentModel(). It is *not* equivalent to the form
er getModel() |
| 220 * @return Never null, if modelSelector or its field is uninstantiated retur
ns a |
| 221 * {@link EmptyTabModel} singleton |
| 222 */ |
| 223 public TabModel getCurrentTabModel() { |
| 224 TabModelSelector modelSelector = getTabModelSelector(); |
| 225 if (modelSelector == null) return EmptyTabModel.getInstance(); |
| 226 return modelSelector.getCurrentModel(); |
| 227 } |
| 228 |
| 229 /** |
| 230 * Returns the tab being displayed by this ChromeActivity instance. This all
ows differentiation |
| 231 * between ChromeActivity subclasses that swap between multiple tabs (e.g. C
hromeTabbedActivity) |
| 232 * and subclasses that only display one Tab (e.g. FullScreenActivity and Doc
umentActivity). |
| 233 * |
| 234 * The default implementation grabs the tab currently selected by the TabMod
el, which may be |
| 235 * null if the Tab does not exist or the system is not initialized. |
| 236 */ |
| 237 public Tab getActivityTab() { |
| 238 return TabModelUtils.getCurrentTab(getCurrentTabModel()); |
| 239 } |
| 240 |
| 241 /** |
| 242 * @return The current ContentViewCore, or null if the tab does not exist or
is not showing a |
| 243 * ContentViewCore. |
| 244 */ |
| 245 public ContentViewCore getCurrentContentViewCore() { |
| 246 return TabModelUtils.getCurrentContentViewCore(getCurrentTabModel()); |
| 247 } |
| 248 |
| 249 /** |
| 250 * Gets the full screen manager. |
| 251 * @return The fullscreen manager, possibly null |
| 252 */ |
| 253 public FullscreenManager getFullscreenManager() { |
| 254 return null; |
| 255 } |
| 256 |
| 257 /** |
| 258 * @return The content offset provider, may be null. |
| 259 */ |
| 260 public ContentOffsetProvider getContentOffsetProvider() { |
| 261 return null; |
| 262 } |
| 263 |
| 264 /** |
| 265 * @return The content readback handler, may be null. |
| 266 */ |
| 267 public ContentReadbackHandler getContentReadbackHandler() { |
| 268 return null; |
| 269 } |
| 270 |
| 271 @Override |
| 272 public void preInflationStartup() { |
| 273 super.preInflationStartup(); |
| 274 ApplicationInitialization.enableFullscreenFlags( |
| 275 getResources(), this, getControlContainerHeightResource()); |
| 276 mIsTablet = DeviceFormFactor.isTablet(this); |
| 277 getWindow().setBackgroundDrawableResource(R.color.light_background_color
); |
| 278 } |
| 279 |
| 280 @SuppressLint("NewApi") |
| 281 @Override |
| 282 public void postInflationStartup() { |
| 283 super.postInflationStartup(); |
| 284 // Low end device UI should be allowed only after a fresh install or whe
n the data has |
| 285 // been cleared. This must happen before anyone calls SysUtils.isLowEndD
evice() or |
| 286 // SysUtils.isLowEndDevice() will always return the wrong value. |
| 287 if (OmahaClient.isFreshInstallOrDataHasBeenCleared(this)) { |
| 288 ChromePreferenceManager.getInstance(this).setAllowLowEndDeviceUi(); |
| 289 } |
| 290 |
| 291 if (!ChromePreferenceManager.getInstance(this).getAllowLowEndDeviceUi())
{ |
| 292 CommandLine.getInstance().appendSwitch( |
| 293 BaseSwitches.DISABLE_LOW_END_DEVICE_MODE); |
| 294 } |
| 295 |
| 296 AccessibilityManager manager = (AccessibilityManager) |
| 297 getBaseContext().getSystemService(Context.ACCESSIBILITY_SERVICE)
; |
| 298 manager.addAccessibilityStateChangeListener(this); |
| 299 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { |
| 300 mTouchExplorationStateChangeListener = new TouchExplorationStateChan
geListener() { |
| 301 @Override |
| 302 public void onTouchExplorationStateChanged(boolean enabled) { |
| 303 checkAccessibility(); |
| 304 } |
| 305 }; |
| 306 manager.addTouchExplorationStateChangeListener(mTouchExplorationStat
eChangeListener); |
| 307 } |
| 308 } |
| 309 |
| 310 @Override |
| 311 public void initializeCompositor() { |
| 312 super.initializeCompositor(); |
| 313 } |
| 314 |
| 315 @Override |
| 316 public void initializeState() { |
| 317 super.initializeState(); |
| 318 IntentHandler.setTestIntentsEnabled( |
| 319 CommandLine.getInstance().hasSwitch(ContentSwitches.ENABLE_TEST_
INTENTS)); |
| 320 mIntentHandler = new IntentHandler(createIntentHandlerDelegate(), getPac
kageName()); |
| 321 } |
| 322 |
| 323 @Override |
| 324 public void finishNativeInitialization() { |
| 325 // Set up the initial orientation of the device. |
| 326 checkOrientation(); |
| 327 findViewById(android.R.id.content).addOnLayoutChangeListener( |
| 328 new View.OnLayoutChangeListener() { |
| 329 @Override |
| 330 public void onLayoutChange(View v, int left, int top, int ri
ght, int bottom, |
| 331 int oldLeft, int oldTop, int oldRight, int oldBottom
) { |
| 332 checkOrientation(); |
| 333 } |
| 334 }); |
| 335 |
| 336 // Make the activity listen to policy change events |
| 337 getChromeApplication().addPolicyChangeListener(this); |
| 338 |
| 339 super.finishNativeInitialization(); |
| 340 } |
| 341 |
| 342 @Override |
| 343 public void onStart() { |
| 344 super.onStart(); |
| 345 if (mContextReporter != null) mContextReporter.enable(); |
| 346 |
| 347 if (mPartnerBrowserRefreshNeeded) { |
| 348 mPartnerBrowserRefreshNeeded = false; |
| 349 PartnerBrowserCustomizations.initializeAsync(getApplicationContext()
, |
| 350 PARTNER_BROWSER_CUSTOMIZATIONS_TIMEOUT_MS); |
| 351 PartnerBrowserCustomizations.setOnInitializeAsyncFinished(new Runnab
le() { |
| 352 @Override |
| 353 public void run() { |
| 354 if (PartnerBrowserCustomizations.isIncognitoDisabled()) { |
| 355 terminateIncognitoSession(); |
| 356 } |
| 357 } |
| 358 }); |
| 359 } |
| 360 } |
| 361 |
| 362 @Override |
| 363 public void onStop() { |
| 364 super.onStop(); |
| 365 if (mContextReporter != null) mContextReporter.disable(); |
| 366 |
| 367 // We want to refresh partner browser provider every onStart(). |
| 368 mPartnerBrowserRefreshNeeded = true; |
| 369 } |
| 370 |
| 371 @Override |
| 372 public void onStartWithNative() { |
| 373 super.onStartWithNative(); |
| 374 getChromeApplication().onStartWithNative(); |
| 375 Tab tab = getActivityTab(); |
| 376 if (tab != null) tab.onActivityStart(); |
| 377 FeatureUtilities.setDocumentModeEnabled(FeatureUtilities.isDocumentMode(
this)); |
| 378 WarmupManager.getInstance().clearWebContentsIfNecessary(); |
| 379 |
| 380 if (GSAState.getInstance(this).isGsaAvailable()) { |
| 381 mGSAServiceClient = new GSAServiceClient(this); |
| 382 mGSAServiceClient.connect(); |
| 383 createContextReporterIfNeeded(); |
| 384 } else { |
| 385 ContextReporter.reportStatus(ContextReporter.STATUS_GSA_NOT_AVAILABL
E); |
| 386 } |
| 387 } |
| 388 |
| 389 private void createContextReporterIfNeeded() { |
| 390 if (mContextReporter != null || getActivityTab() == null) return; |
| 391 |
| 392 final ProfileSyncService syncService = ProfileSyncService.get(this); |
| 393 |
| 394 if (syncService.isSyncingUrlsWithKeystorePassphrase()) { |
| 395 mContextReporter = ((ChromeMobileApplication) getApplicationContext(
)).createGsaHelper() |
| 396 .getContextReporter(this); |
| 397 |
| 398 if (mSyncStateChangedListener != null) { |
| 399 syncService.removeSyncStateChangedListener(mSyncStateChangedList
ener); |
| 400 mSyncStateChangedListener = null; |
| 401 } |
| 402 |
| 403 return; |
| 404 } else { |
| 405 ContextReporter.reportSyncStatus(syncService); |
| 406 } |
| 407 |
| 408 if (mSyncStateChangedListener == null) { |
| 409 mSyncStateChangedListener = new ProfileSyncService.SyncStateChangedL
istener() { |
| 410 @Override |
| 411 public void syncStateChanged() { |
| 412 createContextReporterIfNeeded(); |
| 413 } |
| 414 }; |
| 415 syncService.addSyncStateChangedListener(mSyncStateChangedListener); |
| 416 } |
| 417 } |
| 418 |
| 419 @Override |
| 420 public void onResumeWithNative() { |
| 421 super.onResumeWithNative(); |
| 422 markSessionResume(); |
| 423 |
| 424 if (getActivityTab() != null) { |
| 425 LaunchMetrics.commitLaunchMetrics(getActivityTab().getWebContents())
; |
| 426 } |
| 427 } |
| 428 |
| 429 @Override |
| 430 public void onPauseWithNative() { |
| 431 markSessionEnd(); |
| 432 super.onPauseWithNative(); |
| 433 } |
| 434 |
| 435 @Override |
| 436 public void onStopWithNative() { |
| 437 if (mGSAServiceClient != null) { |
| 438 mGSAServiceClient.disconnect(); |
| 439 mGSAServiceClient = null; |
| 440 if (mSyncStateChangedListener != null) { |
| 441 ProfileSyncService syncService = ProfileSyncService.get(this); |
| 442 syncService.removeSyncStateChangedListener(mSyncStateChangedList
ener); |
| 443 mSyncStateChangedListener = null; |
| 444 } |
| 445 } |
| 446 |
| 447 super.onStopWithNative(); |
| 448 } |
| 449 |
| 450 @Override |
| 451 public void onNewIntentWithNative(Intent intent) { |
| 452 super.onNewIntentWithNative(intent); |
| 453 if (mIntentHandler.shouldIgnoreIntent(this, intent)) return; |
| 454 |
| 455 mIntentHandler.onNewIntent(intent); |
| 456 } |
| 457 |
| 458 /** |
| 459 * Called when the orientation of the device changes. The orientation is ch
ecked/detected on |
| 460 * root view layouts. |
| 461 * @param orientation One of {@link Surface#ROTATION_0} (no rotation), |
| 462 * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_1
80}, or |
| 463 * {@link Surface#ROTATION_270}. |
| 464 */ |
| 465 protected void onOrientationChange(int orientation) { |
| 466 } |
| 467 |
| 468 /** |
| 469 * Called when the accessibility status of this device changes. This might
be triggered by |
| 470 * touch exploration or general accessibility status updates. It is an aggr
egate of two other |
| 471 * accessibility update methods. |
| 472 * @see #onAccessibilityModeChanged(boolean) |
| 473 * @see #onTouchExplorationStateChanged(boolean) |
| 474 * @param enabled Whether or not accessibility and touch exploration are cur
rently enabled. |
| 475 */ |
| 476 protected void onAccessibilityModeChanged(boolean enabled) { |
| 477 InfoBarContainer.setIsAllowedToAutoHide(!enabled); |
| 478 } |
| 479 |
| 480 @Override |
| 481 public boolean onOptionsItemSelected(MenuItem item) { |
| 482 if (item != null && onMenuOrKeyboardAction(item.getItemId(), true)) { |
| 483 return true; |
| 484 } |
| 485 return super.onOptionsItemSelected(item); |
| 486 } |
| 487 |
| 488 @Override |
| 489 public void onUserInteraction() { |
| 490 mLastUserInteractionTime = SystemClock.elapsedRealtime(); |
| 491 } |
| 492 |
| 493 /** |
| 494 * Handles menu item selection and keyboard shortcuts. |
| 495 * |
| 496 * @param id The ID of the selected menu item (defined in main_menu.xml) or |
| 497 * keyboard shortcut (defined in values.xml). |
| 498 * @param fromMenu Whether this was triggered from the menu. |
| 499 * @return Whether the action was handled. |
| 500 */ |
| 501 public boolean onMenuOrKeyboardAction(int id, boolean fromMenu) { |
| 502 return false; |
| 503 } |
| 504 |
| 505 /** |
| 506 * Triggered when the share menu item is selected. |
| 507 * This creates and shows a share intent picker dialog or starts a share int
ent directly. |
| 508 * |
| 509 * @param currentTab The {@link Tab} a user is watching. |
| 510 * @param windowAndroid The {@link WindowAndroid} currentTab is linked to. |
| 511 * @param shareDirectly Whether it should share directly with the activity t
hat was most |
| 512 * recently used to share. |
| 513 * @param isIncognito Whether currentTab is incognito. |
| 514 */ |
| 515 public void onShareMenuItemSelected(final Tab currentTab, |
| 516 final WindowAndroid windowAndroid, final boolean shareDirectly, bool
ean isIncognito) { |
| 517 if (currentTab == null) return; |
| 518 |
| 519 final Activity mainActivity = this; |
| 520 ContentReadbackHandler.GetBitmapCallback bitmapCallback = |
| 521 new ContentReadbackHandler.GetBitmapCallback() { |
| 522 @Override |
| 523 public void onFinishGetBitmap(Bitmap bitmap, int reponse) { |
| 524 ShareHelper.share(shareDirectly, mainActivity, currentTa
b.getTitle(), |
| 525 currentTab.getUrl(), bitmap); |
| 526 if (shareDirectly) { |
| 527 RecordUserAction.record("MobileMenuDirectShare"); |
| 528 } else { |
| 529 RecordUserAction.record("MobileMenuShare"); |
| 530 } |
| 531 } |
| 532 }; |
| 533 ContentReadbackHandler readbackHandler = getContentReadbackHandler(); |
| 534 if (isIncognito || readbackHandler == null || windowAndroid == null |
| 535 || currentTab.getContentViewCore() == null) { |
| 536 bitmapCallback.onFinishGetBitmap(null, ReadbackResponse.SURFACE_UNAV
AILABLE); |
| 537 } else { |
| 538 readbackHandler.getContentBitmapAsync(1, new Rect(), currentTab.getC
ontentViewCore(), |
| 539 Bitmap.Config.ARGB_8888, bitmapCallback); |
| 540 } |
| 541 } |
| 542 |
| 543 /** |
| 544 * @return Whether the activity is running in tablet mode. |
| 545 */ |
| 546 public boolean isTablet() { |
| 547 return mIsTablet; |
| 548 } |
| 549 |
| 550 /** |
| 551 * @return Whether the activity is in overview mode. |
| 552 */ |
| 553 public boolean isInOverviewMode() { |
| 554 return false; |
| 555 } |
| 556 |
| 557 /** |
| 558 * @return Whether the app menu should be shown. |
| 559 */ |
| 560 public boolean shouldShowAppMenu() { |
| 561 return false; |
| 562 } |
| 563 |
| 564 /** |
| 565 * Allows Activities that extend ChromeActivity to do additional hiding/show
ing of menu items. |
| 566 * @param menu Menu that is going to be shown when the menu button is presse
d. |
| 567 */ |
| 568 public void prepareMenu(Menu menu) { |
| 569 } |
| 570 |
| 571 /** |
| 572 * @return timestamp when the last user interaction was made. |
| 573 */ |
| 574 public long getLastUserInteractionTime() { |
| 575 return mLastUserInteractionTime; |
| 576 } |
| 577 |
| 578 protected IntentHandlerDelegate createIntentHandlerDelegate() { |
| 579 return new IntentHandlerDelegate() { |
| 580 @Override |
| 581 public void processWebSearchIntent(String query) { |
| 582 Intent searchIntent = new Intent(Intent.ACTION_WEB_SEARCH); |
| 583 searchIntent.putExtra(SearchManager.QUERY, query); |
| 584 startActivity(searchIntent); |
| 585 } |
| 586 |
| 587 @Override |
| 588 public void processUrlViewIntent(String url, String headers, TabOpen
Type tabOpenType, |
| 589 String externalAppId, int tabIdToBringToFront, Intent intent
) { |
| 590 } |
| 591 }; |
| 592 } |
| 593 |
| 594 /** |
| 595 * @return The resource id that contains how large the top controls are. |
| 596 */ |
| 597 protected int getControlContainerHeightResource() { |
| 598 return R.dimen.control_container_height; |
| 599 } |
| 600 |
| 601 private void markSessionResume() { |
| 602 // Start new session for UMA. |
| 603 if (mUmaSessionStats == null) { |
| 604 mUmaSessionStats = new UmaSessionStats(this); |
| 605 } |
| 606 |
| 607 mUmaSessionStats.updateMetricsServiceState(); |
| 608 // In DocumentMode we need the application-level TabModelSelector instea
d of per |
| 609 // activity which only manages a single tab. |
| 610 if (FeatureUtilities.isDocumentMode(this)) { |
| 611 mUmaSessionStats.startNewSession( |
| 612 ChromeMobileApplication.getDocumentTabModelSelector()); |
| 613 } else { |
| 614 mUmaSessionStats.startNewSession(getTabModelSelector()); |
| 615 } |
| 616 } |
| 617 |
| 618 /** |
| 619 * Mark that the UMA session has ended. |
| 620 */ |
| 621 private void markSessionEnd() { |
| 622 if (mUmaSessionStats == null) { |
| 623 // If you hit this assert, please update crbug.com/172653 on how you
got there. |
| 624 assert false; |
| 625 return; |
| 626 } |
| 627 // Record session metrics. |
| 628 mUmaSessionStats.logMultiWindowStats(windowArea(), displayArea(), |
| 629 TabWindowManager.getInstance().getNumberOfAssignedTabModelSelect
ors()); |
| 630 mUmaSessionStats.logAndEndSession(); |
| 631 } |
| 632 |
| 633 private int windowArea() { |
| 634 Window window = getWindow(); |
| 635 if (window != null) { |
| 636 View view = window.getDecorView(); |
| 637 return view.getWidth() * view.getHeight(); |
| 638 } |
| 639 return -1; |
| 640 } |
| 641 |
| 642 private int displayArea() { |
| 643 if (getResources() != null && getResources().getDisplayMetrics() != null
) { |
| 644 DisplayMetrics metrics = getResources().getDisplayMetrics(); |
| 645 return metrics.heightPixels * metrics.widthPixels; |
| 646 } |
| 647 return -1; |
| 648 } |
| 649 |
| 650 @Override |
| 651 public final void onAccessibilityStateChanged(boolean enabled) { |
| 652 checkAccessibility(); |
| 653 } |
| 654 |
| 655 private void checkAccessibility() { |
| 656 onAccessibilityModeChanged(DeviceClassManager.isAccessibilityModeEnabled
(this)); |
| 657 } |
| 658 |
| 659 private void checkOrientation() { |
| 660 WindowManager wm = getWindowManager(); |
| 661 if (wm == null) return; |
| 662 |
| 663 Display display = wm.getDefaultDisplay(); |
| 664 if (display == null) return; |
| 665 |
| 666 int oldOrientation = mCurrentOrientation; |
| 667 mCurrentOrientation = display.getRotation(); |
| 668 |
| 669 if (oldOrientation != mCurrentOrientation) onOrientationChange(mCurrentO
rientation); |
| 670 } |
| 671 |
| 672 /** |
| 673 * Removes the window background. |
| 674 */ |
| 675 protected void removeWindowBackground() { |
| 676 boolean removeWindowBackground = true; |
| 677 try { |
| 678 Field field = Settings.Secure.class.getField( |
| 679 "ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED"); |
| 680 field.setAccessible(true); |
| 681 |
| 682 if (field.getType() == String.class) { |
| 683 String accessibilityMagnificationSetting = (String) field.get(nu
ll); |
| 684 // When Accessibility magnification is turned on, setting a null
window |
| 685 // background causes the overlaid android views to stretch when
panning. |
| 686 // (crbug/332994) |
| 687 if (Settings.Secure.getInt( |
| 688 getContentResolver(), accessibilityMagnificationSetting)
== 1) { |
| 689 removeWindowBackground = false; |
| 690 } |
| 691 } |
| 692 } catch (SettingNotFoundException e) { |
| 693 // Window background is removed if an exception occurs. |
| 694 } catch (NoSuchFieldException e) { |
| 695 // Window background is removed if an exception occurs. |
| 696 } catch (IllegalAccessException e) { |
| 697 // Window background is removed if an exception occurs. |
| 698 } catch (IllegalArgumentException e) { |
| 699 // Window background is removed if an exception occurs. |
| 700 } |
| 701 if (removeWindowBackground) getWindow().setBackgroundDrawable(null); |
| 702 } |
| 703 |
| 704 /** |
| 705 * @return A casted version of {@link #getApplication()}. |
| 706 */ |
| 707 public ChromeMobileApplication getChromeApplication() { |
| 708 return (ChromeMobileApplication) getApplication(); |
| 709 } |
| 710 |
| 711 /** |
| 712 * @return Whether the update infobar may be shown. |
| 713 */ |
| 714 public boolean mayShowUpdateInfoBar() { |
| 715 return true; |
| 716 } |
| 717 |
| 718 /** |
| 719 * Actions that may be run at some point after startup. Place tasks that are
not critical to the |
| 720 * startup path here. This method will be called automatically and should n
ot be called |
| 721 * directly by subclasses. Overriding methods should call super.onDeferredS
tartup(). |
| 722 */ |
| 723 protected void onDeferredStartup() { |
| 724 boolean crashDumpUploadingDisabled = getIntent() != null |
| 725 && getIntent().hasExtra( |
| 726 ChromeTabbedActivity.INTENT_EXTRA_DISABLE_CRASH_DUMP_UPL
OADING); |
| 727 DeferredStartupHandler.getInstance() |
| 728 .onDeferredStartup(getChromeApplication(), crashDumpUploadingDis
abled); |
| 729 |
| 730 BeamController.registerForBeam(this, new BeamProvider() { |
| 731 @Override |
| 732 public String getTabUrlForBeam() { |
| 733 if (isOverlayVisible()) return null; |
| 734 if (getActivityTab() == null) return null; |
| 735 return getActivityTab().getUrl(); |
| 736 } |
| 737 }); |
| 738 |
| 739 getChromeApplication().getUpdateInfoBarHelper().checkForUpdateOnBackgrou
ndThread(this); |
| 740 removeSnapshotDatabase(); |
| 741 } |
| 742 |
| 743 private void postDeferredStartupIfNeeded() { |
| 744 if (!mDeferredStartupNotified) { |
| 745 // We want to perform deferred startup tasks a short time after the
first page |
| 746 // load completes, but only when the main thread Looper has become i
dle. |
| 747 mHandler.postDelayed(new Runnable() { |
| 748 @Override |
| 749 public void run() { |
| 750 if (!mDeferredStartupNotified && !isActivityDestroyed()) { |
| 751 mDeferredStartupNotified = true; |
| 752 Looper.myQueue().addIdleHandler(new MessageQueue.IdleHan
dler() { |
| 753 @Override |
| 754 public boolean queueIdle() { |
| 755 onDeferredStartup(); |
| 756 return false; // Remove this idle handler. |
| 757 } |
| 758 }); |
| 759 } |
| 760 } |
| 761 }, DEFERRED_STARTUP_DELAY_MS); |
| 762 } |
| 763 } |
| 764 |
| 765 private void showUpdateInfoBarIfNecessary() { |
| 766 getChromeApplication().getUpdateInfoBarHelper().showUpdateInfobarIfNeces
sary(this); |
| 767 } |
| 768 |
| 769 /** |
| 770 * Determines whether the ContentView is currently visible and not hidden by
an overlay |
| 771 * @return true if the ContentView is fully hidden by another view (i.e. the
tab stack) |
| 772 */ |
| 773 public boolean isOverlayVisible() { |
| 774 return false; |
| 775 } |
| 776 |
| 777 /** |
| 778 * Deletes the snapshot database which is no longer used because the feature
has been removed |
| 779 * in Chrome M41. |
| 780 */ |
| 781 private void removeSnapshotDatabase() { |
| 782 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
this); |
| 783 if (!prefs.getBoolean(SNAPSHOT_DATABASE_REMOVED, false)) { |
| 784 deleteDatabase(SNAPSHOT_DATABASE_NAME); |
| 785 prefs.edit().putBoolean(SNAPSHOT_DATABASE_REMOVED, true).apply(); |
| 786 } |
| 787 } |
| 788 |
| 789 @Override |
| 790 public void terminateIncognitoSession() {} |
| 791 |
| 792 /** |
| 793 * @return The {@code ContextualSearchManager} or {@code null} if none; |
| 794 */ |
| 795 public ContextualSearchManager getContextualSearchManager() { |
| 796 return null; |
| 797 } |
| 798 } |
OLD | NEW |