Index: chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeActivity.java |
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeActivity.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1097a84f9360e45441cb7d36f898ef98dde989c6 |
--- /dev/null |
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/ChromeActivity.java |
@@ -0,0 +1,798 @@ |
+// 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; |
+ |
+import android.annotation.SuppressLint; |
+import android.app.Activity; |
+import android.app.SearchManager; |
+import android.content.Context; |
+import android.content.Intent; |
+import android.content.SharedPreferences; |
+import android.graphics.Bitmap; |
+import android.graphics.Rect; |
+import android.os.Build; |
+import android.os.Looper; |
+import android.os.MessageQueue; |
+import android.os.SystemClock; |
+import android.preference.PreferenceManager; |
+import android.provider.Settings; |
+import android.provider.Settings.SettingNotFoundException; |
+import android.util.DisplayMetrics; |
+import android.view.Display; |
+import android.view.Menu; |
+import android.view.MenuItem; |
+import android.view.Surface; |
+import android.view.View; |
+import android.view.Window; |
+import android.view.WindowManager; |
+import android.view.accessibility.AccessibilityManager; |
+import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; |
+import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener; |
+ |
+import com.google.android.apps.chrome.R; |
+ |
+import org.chromium.base.BaseSwitches; |
+import org.chromium.base.CommandLine; |
+import org.chromium.base.metrics.RecordUserAction; |
+import org.chromium.chrome.browser.IntentHandler.IntentHandlerDelegate; |
+import org.chromium.chrome.browser.IntentHandler.TabOpenType; |
+import org.chromium.chrome.browser.compositor.layouts.content.ContentOffsetProvider; |
+import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; |
+import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager; |
+import org.chromium.chrome.browser.device.DeviceClassManager; |
+import org.chromium.chrome.browser.fullscreen.FullscreenManager; |
+import org.chromium.chrome.browser.gsa.ContextReporter; |
+import org.chromium.chrome.browser.gsa.GSAServiceClient; |
+import org.chromium.chrome.browser.gsa.GSAState; |
+import org.chromium.chrome.browser.infobar.InfoBarContainer; |
+import org.chromium.chrome.browser.init.AsyncInitializationActivity; |
+import org.chromium.chrome.browser.metrics.LaunchMetrics; |
+import org.chromium.chrome.browser.metrics.UmaSessionStats; |
+import org.chromium.chrome.browser.nfc.BeamController; |
+import org.chromium.chrome.browser.nfc.BeamProvider; |
+import org.chromium.chrome.browser.omaha.OmahaClient; |
+import org.chromium.chrome.browser.partnercustomizations.PartnerBrowserCustomizations; |
+import org.chromium.chrome.browser.policy.PolicyManager.PolicyChangeListener; |
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager; |
+import org.chromium.chrome.browser.share.ShareHelper; |
+import org.chromium.chrome.browser.sync.ProfileSyncService; |
+import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; |
+import org.chromium.chrome.browser.tabmodel.EmptyTabModel; |
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager; |
+import org.chromium.chrome.browser.tabmodel.TabModel; |
+import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; |
+import org.chromium.chrome.browser.tabmodel.TabModelUtils; |
+import org.chromium.chrome.browser.tabmodel.TabWindowManager; |
+import org.chromium.chrome.browser.util.FeatureUtilities; |
+import org.chromium.content.browser.ContentReadbackHandler; |
+import org.chromium.content.browser.ContentViewCore; |
+import org.chromium.content.common.ContentSwitches; |
+import org.chromium.content_public.browser.readback_types.ReadbackResponse; |
+import org.chromium.ui.base.DeviceFormFactor; |
+import org.chromium.ui.base.WindowAndroid; |
+ |
+import java.lang.reflect.Field; |
+ |
+/** |
+ * The main Chrome activity. This exposes extra methods that relate to the {@link TabModelSelector} |
+ * and lists of tabs. |
+ */ |
+public abstract class ChromeActivity extends AsyncInitializationActivity implements |
+ TabCreatorManager, AccessibilityStateChangeListener, PolicyChangeListener { |
+ |
+ private static final String SNAPSHOT_DATABASE_REMOVED = "snapshot_database_removed"; |
+ private static final String SNAPSHOT_DATABASE_NAME = "snapshots.db"; |
+ |
+ /** Delay in ms after first page load finishes before we initiate deferred startup actions. */ |
+ private static final int DEFERRED_STARTUP_DELAY_MS = 1000; |
+ |
+ /** |
+ * Timeout in ms for reading PartnerBrowserCustomizations provider. |
+ */ |
+ private static final int PARTNER_BROWSER_CUSTOMIZATIONS_TIMEOUT_MS = 10000; |
+ |
+ private TabModelSelector mTabModelSelector; |
+ private TabModelSelectorTabObserver mTabModelSelectorTabObserver; |
+ private ChromeTabCreator mRegularTabCreator; |
+ private ChromeTabCreator mIncognitoTabCreator; |
+ private TabContentManager mTabContentManager; |
+ private UmaSessionStats mUmaSessionStats; |
+ private ContextReporter mContextReporter; |
+ protected GSAServiceClient mGSAServiceClient; |
+ |
+ private int mCurrentOrientation = Surface.ROTATION_0; |
+ private boolean mPartnerBrowserRefreshNeeded = false; |
+ |
+ protected IntentHandler mIntentHandler; |
+ protected boolean mIsTablet = false; |
+ private long mLastUserInteractionTime; |
+ |
+ /** Whether onDeferredStartup() has been run. */ |
+ private boolean mDeferredStartupNotified; |
+ |
+ // The class cannot implement TouchExplorationStateChangeListener, |
+ // because it is only available for Build.VERSION_CODES.KITKAT and later. |
+ // We have to instantiate the TouchExplorationStateChangeListner object in the code. |
+ private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener; |
+ |
+ // Observes when sync becomes ready to create the mContextReporter. |
+ private ProfileSyncService.SyncStateChangedListener mSyncStateChangedListener; |
+ |
+ @SuppressLint("NewApi") |
+ @Override |
+ protected void onDestroy() { |
+ getChromeApplication().removePolicyChangeListener(this); |
+ if (mTabContentManager != null) mTabContentManager.destroy(); |
+ if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.destroy(); |
+ |
+ AccessibilityManager manager = (AccessibilityManager) |
+ getBaseContext().getSystemService(Context.ACCESSIBILITY_SERVICE); |
+ manager.removeAccessibilityStateChangeListener(this); |
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { |
+ manager.removeTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener); |
+ } |
+ |
+ super.onDestroy(); |
+ } |
+ |
+ /** |
+ * {@link TabModelSelector} no longer implements TabModel. Use getTabModelSelector() or |
+ * getCurrentTabModel() depending on your needs. |
+ * @return The {@link TabModelSelector}, possibly null. |
+ */ |
+ public TabModelSelector getTabModelSelector() { |
+ return mTabModelSelector; |
+ } |
+ |
+ /** |
+ * Sets the {@link TabModelSelector} owned by this {@link ChromeActivity}. |
+ * @param tabModelSelector A {@link TabModelSelector} instance. |
+ */ |
+ protected void setTabModelSelector(TabModelSelector tabModelSelector) { |
+ mTabModelSelector = tabModelSelector; |
+ |
+ if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.destroy(); |
+ mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(tabModelSelector) { |
+ @Override |
+ public void onLoadStopped(Tab tab) { |
+ postDeferredStartupIfNeeded(); |
+ showUpdateInfoBarIfNecessary(); |
+ } |
+ |
+ @Override |
+ public void onPageLoadFinished(Tab tab) { |
+ postDeferredStartupIfNeeded(); |
+ showUpdateInfoBarIfNecessary(); |
+ } |
+ |
+ @Override |
+ public void onCrash(Tab tab, boolean sadTabShown) { |
+ postDeferredStartupIfNeeded(); |
+ } |
+ }; |
+ } |
+ |
+ @Override |
+ public ChromeTabCreator getTabCreator(boolean incognito) { |
+ return incognito ? mIncognitoTabCreator : mRegularTabCreator; |
+ } |
+ |
+ /** |
+ * Sets the {@link ChromeTabCreator}s owned by this {@link ChromeActivity}. |
+ * @param regularTabCreator A {@link ChromeTabCreator} instance. |
+ */ |
+ public void setTabCreators(ChromeTabCreator regularTabCreator, |
+ ChromeTabCreator incognitoTabCreator) { |
+ mRegularTabCreator = regularTabCreator; |
+ mIncognitoTabCreator = incognitoTabCreator; |
+ } |
+ |
+ /** |
+ * Convenience method that returns a tab creator for the currently selected {@link TabModel}. |
+ * @return A tab creator for the currently selected {@link TabModel}. |
+ */ |
+ public ChromeTabCreator getCurrentTabCreator() { |
+ return getTabCreator(getTabModelSelector().isIncognitoSelected()); |
+ } |
+ |
+ /** |
+ * Gets the {@link TabContentManager} instance which holds snapshots of the tabs in this model. |
+ * @return The thumbnail cache, possibly null. |
+ */ |
+ public TabContentManager getTabContentManager() { |
+ return mTabContentManager; |
+ } |
+ |
+ /** |
+ * Sets the {@link TabContentManager} owned by this {@link ChromeActivity}. |
+ * @param tabContentManager A {@link TabContentManager} instance. |
+ */ |
+ protected void setTabContentManager(TabContentManager tabContentManager) { |
+ mTabContentManager = tabContentManager; |
+ } |
+ |
+ /** |
+ * Gets the current (inner) TabModel. This is a convenience function for |
+ * getModelSelector().getCurrentModel(). It is *not* equivalent to the former getModel() |
+ * @return Never null, if modelSelector or its field is uninstantiated returns a |
+ * {@link EmptyTabModel} singleton |
+ */ |
+ public TabModel getCurrentTabModel() { |
+ TabModelSelector modelSelector = getTabModelSelector(); |
+ if (modelSelector == null) return EmptyTabModel.getInstance(); |
+ return modelSelector.getCurrentModel(); |
+ } |
+ |
+ /** |
+ * Returns the tab being displayed by this ChromeActivity instance. This allows differentiation |
+ * between ChromeActivity subclasses that swap between multiple tabs (e.g. ChromeTabbedActivity) |
+ * and subclasses that only display one Tab (e.g. FullScreenActivity and DocumentActivity). |
+ * |
+ * The default implementation grabs the tab currently selected by the TabModel, which may be |
+ * null if the Tab does not exist or the system is not initialized. |
+ */ |
+ public Tab getActivityTab() { |
+ return TabModelUtils.getCurrentTab(getCurrentTabModel()); |
+ } |
+ |
+ /** |
+ * @return The current ContentViewCore, or null if the tab does not exist or is not showing a |
+ * ContentViewCore. |
+ */ |
+ public ContentViewCore getCurrentContentViewCore() { |
+ return TabModelUtils.getCurrentContentViewCore(getCurrentTabModel()); |
+ } |
+ |
+ /** |
+ * Gets the full screen manager. |
+ * @return The fullscreen manager, possibly null |
+ */ |
+ public FullscreenManager getFullscreenManager() { |
+ return null; |
+ } |
+ |
+ /** |
+ * @return The content offset provider, may be null. |
+ */ |
+ public ContentOffsetProvider getContentOffsetProvider() { |
+ return null; |
+ } |
+ |
+ /** |
+ * @return The content readback handler, may be null. |
+ */ |
+ public ContentReadbackHandler getContentReadbackHandler() { |
+ return null; |
+ } |
+ |
+ @Override |
+ public void preInflationStartup() { |
+ super.preInflationStartup(); |
+ ApplicationInitialization.enableFullscreenFlags( |
+ getResources(), this, getControlContainerHeightResource()); |
+ mIsTablet = DeviceFormFactor.isTablet(this); |
+ getWindow().setBackgroundDrawableResource(R.color.light_background_color); |
+ } |
+ |
+ @SuppressLint("NewApi") |
+ @Override |
+ public void postInflationStartup() { |
+ super.postInflationStartup(); |
+ // Low end device UI should be allowed only after a fresh install or when the data has |
+ // been cleared. This must happen before anyone calls SysUtils.isLowEndDevice() or |
+ // SysUtils.isLowEndDevice() will always return the wrong value. |
+ if (OmahaClient.isFreshInstallOrDataHasBeenCleared(this)) { |
+ ChromePreferenceManager.getInstance(this).setAllowLowEndDeviceUi(); |
+ } |
+ |
+ if (!ChromePreferenceManager.getInstance(this).getAllowLowEndDeviceUi()) { |
+ CommandLine.getInstance().appendSwitch( |
+ BaseSwitches.DISABLE_LOW_END_DEVICE_MODE); |
+ } |
+ |
+ AccessibilityManager manager = (AccessibilityManager) |
+ getBaseContext().getSystemService(Context.ACCESSIBILITY_SERVICE); |
+ manager.addAccessibilityStateChangeListener(this); |
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { |
+ mTouchExplorationStateChangeListener = new TouchExplorationStateChangeListener() { |
+ @Override |
+ public void onTouchExplorationStateChanged(boolean enabled) { |
+ checkAccessibility(); |
+ } |
+ }; |
+ manager.addTouchExplorationStateChangeListener(mTouchExplorationStateChangeListener); |
+ } |
+ } |
+ |
+ @Override |
+ public void initializeCompositor() { |
+ super.initializeCompositor(); |
+ } |
+ |
+ @Override |
+ public void initializeState() { |
+ super.initializeState(); |
+ IntentHandler.setTestIntentsEnabled( |
+ CommandLine.getInstance().hasSwitch(ContentSwitches.ENABLE_TEST_INTENTS)); |
+ mIntentHandler = new IntentHandler(createIntentHandlerDelegate(), getPackageName()); |
+ } |
+ |
+ @Override |
+ public void finishNativeInitialization() { |
+ // Set up the initial orientation of the device. |
+ checkOrientation(); |
+ findViewById(android.R.id.content).addOnLayoutChangeListener( |
+ new View.OnLayoutChangeListener() { |
+ @Override |
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, |
+ int oldLeft, int oldTop, int oldRight, int oldBottom) { |
+ checkOrientation(); |
+ } |
+ }); |
+ |
+ // Make the activity listen to policy change events |
+ getChromeApplication().addPolicyChangeListener(this); |
+ |
+ super.finishNativeInitialization(); |
+ } |
+ |
+ @Override |
+ public void onStart() { |
+ super.onStart(); |
+ if (mContextReporter != null) mContextReporter.enable(); |
+ |
+ if (mPartnerBrowserRefreshNeeded) { |
+ mPartnerBrowserRefreshNeeded = false; |
+ PartnerBrowserCustomizations.initializeAsync(getApplicationContext(), |
+ PARTNER_BROWSER_CUSTOMIZATIONS_TIMEOUT_MS); |
+ PartnerBrowserCustomizations.setOnInitializeAsyncFinished(new Runnable() { |
+ @Override |
+ public void run() { |
+ if (PartnerBrowserCustomizations.isIncognitoDisabled()) { |
+ terminateIncognitoSession(); |
+ } |
+ } |
+ }); |
+ } |
+ } |
+ |
+ @Override |
+ public void onStop() { |
+ super.onStop(); |
+ if (mContextReporter != null) mContextReporter.disable(); |
+ |
+ // We want to refresh partner browser provider every onStart(). |
+ mPartnerBrowserRefreshNeeded = true; |
+ } |
+ |
+ @Override |
+ public void onStartWithNative() { |
+ super.onStartWithNative(); |
+ getChromeApplication().onStartWithNative(); |
+ Tab tab = getActivityTab(); |
+ if (tab != null) tab.onActivityStart(); |
+ FeatureUtilities.setDocumentModeEnabled(FeatureUtilities.isDocumentMode(this)); |
+ WarmupManager.getInstance().clearWebContentsIfNecessary(); |
+ |
+ if (GSAState.getInstance(this).isGsaAvailable()) { |
+ mGSAServiceClient = new GSAServiceClient(this); |
+ mGSAServiceClient.connect(); |
+ createContextReporterIfNeeded(); |
+ } else { |
+ ContextReporter.reportStatus(ContextReporter.STATUS_GSA_NOT_AVAILABLE); |
+ } |
+ } |
+ |
+ private void createContextReporterIfNeeded() { |
+ if (mContextReporter != null || getActivityTab() == null) return; |
+ |
+ final ProfileSyncService syncService = ProfileSyncService.get(this); |
+ |
+ if (syncService.isSyncingUrlsWithKeystorePassphrase()) { |
+ mContextReporter = ((ChromeMobileApplication) getApplicationContext()).createGsaHelper() |
+ .getContextReporter(this); |
+ |
+ if (mSyncStateChangedListener != null) { |
+ syncService.removeSyncStateChangedListener(mSyncStateChangedListener); |
+ mSyncStateChangedListener = null; |
+ } |
+ |
+ return; |
+ } else { |
+ ContextReporter.reportSyncStatus(syncService); |
+ } |
+ |
+ if (mSyncStateChangedListener == null) { |
+ mSyncStateChangedListener = new ProfileSyncService.SyncStateChangedListener() { |
+ @Override |
+ public void syncStateChanged() { |
+ createContextReporterIfNeeded(); |
+ } |
+ }; |
+ syncService.addSyncStateChangedListener(mSyncStateChangedListener); |
+ } |
+ } |
+ |
+ @Override |
+ public void onResumeWithNative() { |
+ super.onResumeWithNative(); |
+ markSessionResume(); |
+ |
+ if (getActivityTab() != null) { |
+ LaunchMetrics.commitLaunchMetrics(getActivityTab().getWebContents()); |
+ } |
+ } |
+ |
+ @Override |
+ public void onPauseWithNative() { |
+ markSessionEnd(); |
+ super.onPauseWithNative(); |
+ } |
+ |
+ @Override |
+ public void onStopWithNative() { |
+ if (mGSAServiceClient != null) { |
+ mGSAServiceClient.disconnect(); |
+ mGSAServiceClient = null; |
+ if (mSyncStateChangedListener != null) { |
+ ProfileSyncService syncService = ProfileSyncService.get(this); |
+ syncService.removeSyncStateChangedListener(mSyncStateChangedListener); |
+ mSyncStateChangedListener = null; |
+ } |
+ } |
+ |
+ super.onStopWithNative(); |
+ } |
+ |
+ @Override |
+ public void onNewIntentWithNative(Intent intent) { |
+ super.onNewIntentWithNative(intent); |
+ if (mIntentHandler.shouldIgnoreIntent(this, intent)) return; |
+ |
+ mIntentHandler.onNewIntent(intent); |
+ } |
+ |
+ /** |
+ * Called when the orientation of the device changes. The orientation is checked/detected on |
+ * root view layouts. |
+ * @param orientation One of {@link Surface#ROTATION_0} (no rotation), |
+ * {@link Surface#ROTATION_90}, {@link Surface#ROTATION_180}, or |
+ * {@link Surface#ROTATION_270}. |
+ */ |
+ protected void onOrientationChange(int orientation) { |
+ } |
+ |
+ /** |
+ * Called when the accessibility status of this device changes. This might be triggered by |
+ * touch exploration or general accessibility status updates. It is an aggregate of two other |
+ * accessibility update methods. |
+ * @see #onAccessibilityModeChanged(boolean) |
+ * @see #onTouchExplorationStateChanged(boolean) |
+ * @param enabled Whether or not accessibility and touch exploration are currently enabled. |
+ */ |
+ protected void onAccessibilityModeChanged(boolean enabled) { |
+ InfoBarContainer.setIsAllowedToAutoHide(!enabled); |
+ } |
+ |
+ @Override |
+ public boolean onOptionsItemSelected(MenuItem item) { |
+ if (item != null && onMenuOrKeyboardAction(item.getItemId(), true)) { |
+ return true; |
+ } |
+ return super.onOptionsItemSelected(item); |
+ } |
+ |
+ @Override |
+ public void onUserInteraction() { |
+ mLastUserInteractionTime = SystemClock.elapsedRealtime(); |
+ } |
+ |
+ /** |
+ * Handles menu item selection and keyboard shortcuts. |
+ * |
+ * @param id The ID of the selected menu item (defined in main_menu.xml) or |
+ * keyboard shortcut (defined in values.xml). |
+ * @param fromMenu Whether this was triggered from the menu. |
+ * @return Whether the action was handled. |
+ */ |
+ public boolean onMenuOrKeyboardAction(int id, boolean fromMenu) { |
+ return false; |
+ } |
+ |
+ /** |
+ * Triggered when the share menu item is selected. |
+ * This creates and shows a share intent picker dialog or starts a share intent directly. |
+ * |
+ * @param currentTab The {@link Tab} a user is watching. |
+ * @param windowAndroid The {@link WindowAndroid} currentTab is linked to. |
+ * @param shareDirectly Whether it should share directly with the activity that was most |
+ * recently used to share. |
+ * @param isIncognito Whether currentTab is incognito. |
+ */ |
+ public void onShareMenuItemSelected(final Tab currentTab, |
+ final WindowAndroid windowAndroid, final boolean shareDirectly, boolean isIncognito) { |
+ if (currentTab == null) return; |
+ |
+ final Activity mainActivity = this; |
+ ContentReadbackHandler.GetBitmapCallback bitmapCallback = |
+ new ContentReadbackHandler.GetBitmapCallback() { |
+ @Override |
+ public void onFinishGetBitmap(Bitmap bitmap, int reponse) { |
+ ShareHelper.share(shareDirectly, mainActivity, currentTab.getTitle(), |
+ currentTab.getUrl(), bitmap); |
+ if (shareDirectly) { |
+ RecordUserAction.record("MobileMenuDirectShare"); |
+ } else { |
+ RecordUserAction.record("MobileMenuShare"); |
+ } |
+ } |
+ }; |
+ ContentReadbackHandler readbackHandler = getContentReadbackHandler(); |
+ if (isIncognito || readbackHandler == null || windowAndroid == null |
+ || currentTab.getContentViewCore() == null) { |
+ bitmapCallback.onFinishGetBitmap(null, ReadbackResponse.SURFACE_UNAVAILABLE); |
+ } else { |
+ readbackHandler.getContentBitmapAsync(1, new Rect(), currentTab.getContentViewCore(), |
+ Bitmap.Config.ARGB_8888, bitmapCallback); |
+ } |
+ } |
+ |
+ /** |
+ * @return Whether the activity is running in tablet mode. |
+ */ |
+ public boolean isTablet() { |
+ return mIsTablet; |
+ } |
+ |
+ /** |
+ * @return Whether the activity is in overview mode. |
+ */ |
+ public boolean isInOverviewMode() { |
+ return false; |
+ } |
+ |
+ /** |
+ * @return Whether the app menu should be shown. |
+ */ |
+ public boolean shouldShowAppMenu() { |
+ return false; |
+ } |
+ |
+ /** |
+ * Allows Activities that extend ChromeActivity to do additional hiding/showing of menu items. |
+ * @param menu Menu that is going to be shown when the menu button is pressed. |
+ */ |
+ public void prepareMenu(Menu menu) { |
+ } |
+ |
+ /** |
+ * @return timestamp when the last user interaction was made. |
+ */ |
+ public long getLastUserInteractionTime() { |
+ return mLastUserInteractionTime; |
+ } |
+ |
+ protected IntentHandlerDelegate createIntentHandlerDelegate() { |
+ return new IntentHandlerDelegate() { |
+ @Override |
+ public void processWebSearchIntent(String query) { |
+ Intent searchIntent = new Intent(Intent.ACTION_WEB_SEARCH); |
+ searchIntent.putExtra(SearchManager.QUERY, query); |
+ startActivity(searchIntent); |
+ } |
+ |
+ @Override |
+ public void processUrlViewIntent(String url, String headers, TabOpenType tabOpenType, |
+ String externalAppId, int tabIdToBringToFront, Intent intent) { |
+ } |
+ }; |
+ } |
+ |
+ /** |
+ * @return The resource id that contains how large the top controls are. |
+ */ |
+ protected int getControlContainerHeightResource() { |
+ return R.dimen.control_container_height; |
+ } |
+ |
+ private void markSessionResume() { |
+ // Start new session for UMA. |
+ if (mUmaSessionStats == null) { |
+ mUmaSessionStats = new UmaSessionStats(this); |
+ } |
+ |
+ mUmaSessionStats.updateMetricsServiceState(); |
+ // In DocumentMode we need the application-level TabModelSelector instead of per |
+ // activity which only manages a single tab. |
+ if (FeatureUtilities.isDocumentMode(this)) { |
+ mUmaSessionStats.startNewSession( |
+ ChromeMobileApplication.getDocumentTabModelSelector()); |
+ } else { |
+ mUmaSessionStats.startNewSession(getTabModelSelector()); |
+ } |
+ } |
+ |
+ /** |
+ * Mark that the UMA session has ended. |
+ */ |
+ private void markSessionEnd() { |
+ if (mUmaSessionStats == null) { |
+ // If you hit this assert, please update crbug.com/172653 on how you got there. |
+ assert false; |
+ return; |
+ } |
+ // Record session metrics. |
+ mUmaSessionStats.logMultiWindowStats(windowArea(), displayArea(), |
+ TabWindowManager.getInstance().getNumberOfAssignedTabModelSelectors()); |
+ mUmaSessionStats.logAndEndSession(); |
+ } |
+ |
+ private int windowArea() { |
+ Window window = getWindow(); |
+ if (window != null) { |
+ View view = window.getDecorView(); |
+ return view.getWidth() * view.getHeight(); |
+ } |
+ return -1; |
+ } |
+ |
+ private int displayArea() { |
+ if (getResources() != null && getResources().getDisplayMetrics() != null) { |
+ DisplayMetrics metrics = getResources().getDisplayMetrics(); |
+ return metrics.heightPixels * metrics.widthPixels; |
+ } |
+ return -1; |
+ } |
+ |
+ @Override |
+ public final void onAccessibilityStateChanged(boolean enabled) { |
+ checkAccessibility(); |
+ } |
+ |
+ private void checkAccessibility() { |
+ onAccessibilityModeChanged(DeviceClassManager.isAccessibilityModeEnabled(this)); |
+ } |
+ |
+ private void checkOrientation() { |
+ WindowManager wm = getWindowManager(); |
+ if (wm == null) return; |
+ |
+ Display display = wm.getDefaultDisplay(); |
+ if (display == null) return; |
+ |
+ int oldOrientation = mCurrentOrientation; |
+ mCurrentOrientation = display.getRotation(); |
+ |
+ if (oldOrientation != mCurrentOrientation) onOrientationChange(mCurrentOrientation); |
+ } |
+ |
+ /** |
+ * Removes the window background. |
+ */ |
+ protected void removeWindowBackground() { |
+ boolean removeWindowBackground = true; |
+ try { |
+ Field field = Settings.Secure.class.getField( |
+ "ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED"); |
+ field.setAccessible(true); |
+ |
+ if (field.getType() == String.class) { |
+ String accessibilityMagnificationSetting = (String) field.get(null); |
+ // When Accessibility magnification is turned on, setting a null window |
+ // background causes the overlaid android views to stretch when panning. |
+ // (crbug/332994) |
+ if (Settings.Secure.getInt( |
+ getContentResolver(), accessibilityMagnificationSetting) == 1) { |
+ removeWindowBackground = false; |
+ } |
+ } |
+ } catch (SettingNotFoundException e) { |
+ // Window background is removed if an exception occurs. |
+ } catch (NoSuchFieldException e) { |
+ // Window background is removed if an exception occurs. |
+ } catch (IllegalAccessException e) { |
+ // Window background is removed if an exception occurs. |
+ } catch (IllegalArgumentException e) { |
+ // Window background is removed if an exception occurs. |
+ } |
+ if (removeWindowBackground) getWindow().setBackgroundDrawable(null); |
+ } |
+ |
+ /** |
+ * @return A casted version of {@link #getApplication()}. |
+ */ |
+ public ChromeMobileApplication getChromeApplication() { |
+ return (ChromeMobileApplication) getApplication(); |
+ } |
+ |
+ /** |
+ * @return Whether the update infobar may be shown. |
+ */ |
+ public boolean mayShowUpdateInfoBar() { |
+ return true; |
+ } |
+ |
+ /** |
+ * Actions that may be run at some point after startup. Place tasks that are not critical to the |
+ * startup path here. This method will be called automatically and should not be called |
+ * directly by subclasses. Overriding methods should call super.onDeferredStartup(). |
+ */ |
+ protected void onDeferredStartup() { |
+ boolean crashDumpUploadingDisabled = getIntent() != null |
+ && getIntent().hasExtra( |
+ ChromeTabbedActivity.INTENT_EXTRA_DISABLE_CRASH_DUMP_UPLOADING); |
+ DeferredStartupHandler.getInstance() |
+ .onDeferredStartup(getChromeApplication(), crashDumpUploadingDisabled); |
+ |
+ BeamController.registerForBeam(this, new BeamProvider() { |
+ @Override |
+ public String getTabUrlForBeam() { |
+ if (isOverlayVisible()) return null; |
+ if (getActivityTab() == null) return null; |
+ return getActivityTab().getUrl(); |
+ } |
+ }); |
+ |
+ getChromeApplication().getUpdateInfoBarHelper().checkForUpdateOnBackgroundThread(this); |
+ removeSnapshotDatabase(); |
+ } |
+ |
+ private void postDeferredStartupIfNeeded() { |
+ if (!mDeferredStartupNotified) { |
+ // We want to perform deferred startup tasks a short time after the first page |
+ // load completes, but only when the main thread Looper has become idle. |
+ mHandler.postDelayed(new Runnable() { |
+ @Override |
+ public void run() { |
+ if (!mDeferredStartupNotified && !isActivityDestroyed()) { |
+ mDeferredStartupNotified = true; |
+ Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { |
+ @Override |
+ public boolean queueIdle() { |
+ onDeferredStartup(); |
+ return false; // Remove this idle handler. |
+ } |
+ }); |
+ } |
+ } |
+ }, DEFERRED_STARTUP_DELAY_MS); |
+ } |
+ } |
+ |
+ private void showUpdateInfoBarIfNecessary() { |
+ getChromeApplication().getUpdateInfoBarHelper().showUpdateInfobarIfNecessary(this); |
+ } |
+ |
+ /** |
+ * Determines whether the ContentView is currently visible and not hidden by an overlay |
+ * @return true if the ContentView is fully hidden by another view (i.e. the tab stack) |
+ */ |
+ public boolean isOverlayVisible() { |
+ return false; |
+ } |
+ |
+ /** |
+ * Deletes the snapshot database which is no longer used because the feature has been removed |
+ * in Chrome M41. |
+ */ |
+ private void removeSnapshotDatabase() { |
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); |
+ if (!prefs.getBoolean(SNAPSHOT_DATABASE_REMOVED, false)) { |
+ deleteDatabase(SNAPSHOT_DATABASE_NAME); |
+ prefs.edit().putBoolean(SNAPSHOT_DATABASE_REMOVED, true).apply(); |
+ } |
+ } |
+ |
+ @Override |
+ public void terminateIncognitoSession() {} |
+ |
+ /** |
+ * @return The {@code ContextualSearchManager} or {@code null} if none; |
+ */ |
+ public ContextualSearchManager getContextualSearchManager() { |
+ return null; |
+ } |
+} |