Index: chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java |
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e67a89e12a8fe76213f4ea6e67a03b591d8196a6 |
--- /dev/null |
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/CompositorChromeActivity.java |
@@ -0,0 +1,635 @@ |
+// 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.app.Activity; |
+import android.content.Intent; |
+import android.graphics.Bitmap; |
+import android.graphics.Color; |
+import android.os.Bundle; |
+import android.os.Process; |
+import android.os.SystemClock; |
+import android.support.v7.app.AlertDialog; |
+import android.util.Log; |
+import android.view.View; |
+import android.view.ViewGroup; |
+import android.view.ViewStub; |
+import android.view.ViewTreeObserver; |
+import android.view.ViewTreeObserver.OnPreDrawListener; |
+ |
+import com.google.android.apps.chrome.R; |
+ |
+import org.chromium.base.ApiCompatibilityUtils; |
+import org.chromium.base.CommandLine; |
+import org.chromium.base.TraceEvent; |
+import org.chromium.base.VisibleForTesting; |
+import org.chromium.base.metrics.RecordHistogram; |
+import org.chromium.base.metrics.RecordUserAction; |
+import org.chromium.chrome.browser.BookmarksBridge.BookmarkModelObserver; |
+import org.chromium.chrome.browser.appmenu.AppMenuHandler; |
+import org.chromium.chrome.browser.bookmark.ManageBookmarkActivity; |
+import org.chromium.chrome.browser.compositor.CompositorViewHolder; |
+import org.chromium.chrome.browser.compositor.layouts.Layout; |
+import org.chromium.chrome.browser.compositor.layouts.LayoutManager; |
+import org.chromium.chrome.browser.compositor.layouts.LayoutManagerDocument; |
+import org.chromium.chrome.browser.compositor.layouts.SceneChangeObserver; |
+import org.chromium.chrome.browser.compositor.layouts.content.ContentOffsetProvider; |
+import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; |
+import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial; |
+import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager; |
+import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager.ContextualSearchTabPromotionDelegate; |
+import org.chromium.chrome.browser.device.DeviceClassManager; |
+import org.chromium.chrome.browser.dom_distiller.DistilledPagePrefsView; |
+import org.chromium.chrome.browser.dom_distiller.ReaderModeActivityDelegate; |
+import org.chromium.chrome.browser.dom_distiller.ReaderModeManager; |
+import org.chromium.chrome.browser.enhanced_bookmarks.EnhancedBookmarksModel; |
+import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkUtils; |
+import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; |
+import org.chromium.chrome.browser.help.HelpAndFeedback; |
+import org.chromium.chrome.browser.preferences.PrefServiceBridge; |
+import org.chromium.chrome.browser.preferences.PreferencesLauncher; |
+import org.chromium.chrome.browser.printing.TabPrinter; |
+import org.chromium.chrome.browser.snackbar.SnackbarManager; |
+import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable; |
+import org.chromium.chrome.browser.tabmodel.ChromeTabCreator; |
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; |
+import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
+import org.chromium.chrome.browser.util.FeatureUtilities; |
+import org.chromium.chrome.browser.webapps.AddToHomescreenDialog; |
+import org.chromium.chrome.browser.widget.ControlContainer; |
+import org.chromium.components.bookmarks.BookmarkId; |
+import org.chromium.components.bookmarks.BookmarkType; |
+import org.chromium.content.browser.ContentReadbackHandler; |
+import org.chromium.content.browser.ContentReadbackHandler.GetBitmapCallback; |
+import org.chromium.content.browser.ContentViewCore; |
+import org.chromium.content_public.browser.LoadUrlParams; |
+import org.chromium.content_public.browser.readback_types.ReadbackResponse; |
+import org.chromium.printing.PrintManagerDelegateImpl; |
+import org.chromium.printing.PrintingController; |
+import org.chromium.ui.base.DeviceFormFactor; |
+import org.chromium.ui.base.PageTransition; |
+import org.chromium.ui.base.WindowAndroid; |
+ |
+import java.util.Locale; |
+import java.util.concurrent.TimeUnit; |
+ |
+/** |
+ * A {@link ChromeActivity} that builds and manages a {@link CompositorViewHolder} and associated |
+ * classes. |
+ */ |
+public abstract class CompositorChromeActivity extends ChromeActivity |
+ implements ContextualSearchTabPromotionDelegate, SnackbarManageable, SceneChangeObserver { |
+ /** |
+ * No control container to inflate during initialization. |
+ */ |
+ private static final int NO_CONTROL_CONTAINER = -1; |
+ |
+ private static final String TAG = "CompositorChromeActivity"; |
+ |
+ private WindowAndroid mWindowAndroid; |
+ private ChromeFullscreenManager mFullscreenManager; |
+ private CompositorViewHolder mCompositorViewHolder; |
+ private ContextualSearchManager mContextualSearchManager; |
+ private ReaderModeActivityDelegate mReaderModeActivityDelegate; |
+ private SnackbarManager mSnackbarManager; |
+ |
+ // Time in ms that it took took us to inflate the initial layout |
+ private long mInflateInitialLayoutDurationMs; |
+ |
+ private OnPreDrawListener mFirstDrawListener; |
+ |
+ private final Locale mCurrentLocale = Locale.getDefault(); |
+ |
+ @Override |
+ public void postInflationStartup() { |
+ mWindowAndroid = new ChromeWindow(this); |
+ mWindowAndroid.restoreInstanceState(getSavedInstanceState()); |
+ mSnackbarManager = new SnackbarManager(findViewById(android.R.id.content)); |
+ super.postInflationStartup(); |
+ |
+ // Set up the animation placeholder to be the SurfaceView. This disables the |
+ // SurfaceView's 'hole' clipping during animations that are notified to the window. |
+ mWindowAndroid.setAnimationPlaceholderView(mCompositorViewHolder.getSurfaceView()); |
+ |
+ // Inform the WindowAndroid of the keyboard accessory view. |
+ mWindowAndroid.setKeyboardAccessoryView((ViewGroup) findViewById(R.id.keyboard_accessory)); |
+ final View controlContainer = findViewById(R.id.control_container); |
+ if (controlContainer != null) { |
+ mFirstDrawListener = new ViewTreeObserver.OnPreDrawListener() { |
+ @Override |
+ public boolean onPreDraw() { |
+ controlContainer.getViewTreeObserver() |
+ .removeOnPreDrawListener(mFirstDrawListener); |
+ mFirstDrawListener = null; |
+ onFirstDrawComplete(); |
+ return true; |
+ } |
+ }; |
+ controlContainer.getViewTreeObserver().addOnPreDrawListener(mFirstDrawListener); |
+ } |
+ } |
+ |
+ /** |
+ * This function builds the {@link CompositorViewHolder}. Subclasses *must* call |
+ * super.setContentView() before using {@link #getTabModelSelector()} or |
+ * {@link #getCompositorViewHolder()}. |
+ */ |
+ @Override |
+ protected final void setContentView() { |
+ final long begin = SystemClock.elapsedRealtime(); |
+ TraceEvent.begin("onCreate->setContentView()"); |
+ if (WarmupManager.getInstance().hasBuiltViewHierarchy()) { |
+ View placeHolderView = new View(this); |
+ setContentView(placeHolderView); |
+ ViewGroup contentParent = (ViewGroup) placeHolderView.getParent(); |
+ WarmupManager.getInstance().transferViewHierarchyTo(contentParent); |
+ contentParent.removeView(placeHolderView); |
+ } else { |
+ setContentView(R.layout.main); |
+ if (getControlContainerLayoutId() != NO_CONTROL_CONTAINER) { |
+ ViewStub toolbarContainerStub = |
+ ((ViewStub) findViewById(R.id.control_container_stub)); |
+ toolbarContainerStub.setLayoutResource(getControlContainerLayoutId()); |
+ toolbarContainerStub.inflate(); |
+ } |
+ } |
+ TraceEvent.end("onCreate->setContentView()"); |
+ mInflateInitialLayoutDurationMs = SystemClock.elapsedRealtime() - begin; |
+ |
+ // Set the status bar color to black by default. This is an optimization for |
+ // Chrome not to draw under status and navigation bars when we use the default |
+ // black status bar |
+ ApiCompatibilityUtils.setStatusBarColor(getWindow(), Color.BLACK); |
+ |
+ mCompositorViewHolder = (CompositorViewHolder) findViewById(R.id.compositor_view_holder); |
+ mCompositorViewHolder.setRootView(getWindow().getDecorView().getRootView()); |
+ } |
+ |
+ /** |
+ * @return The resource id for the layout to use for {@link ControlContainer}. 0 by default. |
+ */ |
+ protected int getControlContainerLayoutId() { |
+ return NO_CONTROL_CONTAINER; |
+ } |
+ |
+ /** |
+ * @return Whether contextual search is allowed for this activity or not. |
+ */ |
+ protected boolean isContextualSearchAllowed() { |
+ return true; |
+ } |
+ |
+ @Override |
+ public void initializeCompositor() { |
+ TraceEvent.begin("CompositorChromeActivity:CompositorInitialization"); |
+ super.initializeCompositor(); |
+ |
+ setTabContentManager(new TabContentManager(this, getContentOffsetProvider(), |
+ DeviceClassManager.enableSnapshots())); |
+ mCompositorViewHolder.onNativeLibraryReady(mWindowAndroid, getTabContentManager()); |
+ |
+ if (isContextualSearchAllowed() && ContextualSearchFieldTrial.isEnabled(this) |
+ && !DeviceFormFactor.isTablet(this)) { |
+ mContextualSearchManager = new ContextualSearchManager(this, mWindowAndroid, this); |
+ } |
+ |
+ if (ReaderModeManager.isEnabled(this)) { |
+ mReaderModeActivityDelegate = new ReaderModeActivityDelegate(this); |
+ } |
+ |
+ TraceEvent.end("CompositorChromeActivity:CompositorInitialization"); |
+ } |
+ |
+ @Override |
+ public void onStartWithNative() { |
+ super.onStartWithNative(); |
+ mCompositorViewHolder.resetFlags(); |
+ } |
+ |
+ @Override |
+ protected void onDeferredStartup() { |
+ super.onDeferredStartup(); |
+ RecordHistogram.recordTimesHistogram("MobileStartup.ToolbarInflationTime", |
+ mInflateInitialLayoutDurationMs, TimeUnit.MILLISECONDS); |
+ } |
+ |
+ @Override |
+ public void onStart() { |
+ super.onStart(); |
+ if (mCompositorViewHolder != null) mCompositorViewHolder.onStart(); |
+ } |
+ |
+ @Override |
+ public void onStop() { |
+ super.onStop(); |
+ if (mCompositorViewHolder != null) mCompositorViewHolder.onStop(); |
+ } |
+ |
+ @Override |
+ public void onPause() { |
+ super.onPause(); |
+ if (mSnackbarManager != null) mSnackbarManager.dismissSnackbar(false); |
+ } |
+ |
+ @Override |
+ public long getOnCreateTimestampMs() { |
+ return super.getOnCreateTimestampMs(); |
+ } |
+ |
+ /** |
+ * This cannot be overridden in order to preserve destruction order. Override |
+ * {@link #onDestroyInternal()} instead to perform clean up tasks. |
+ */ |
+ @Override |
+ protected final void onDestroy() { |
+ if (mReaderModeActivityDelegate != null) mReaderModeActivityDelegate.destroy(); |
+ if (mContextualSearchManager != null) mContextualSearchManager.destroy(); |
+ if (mCompositorViewHolder != null) { |
+ if (mCompositorViewHolder.getLayoutManager() != null) { |
+ mCompositorViewHolder.getLayoutManager().removeSceneChangeObserver(this); |
+ } |
+ mCompositorViewHolder.shutDown(); |
+ } |
+ onDestroyInternal(); |
+ |
+ TabModelSelector selector = getTabModelSelector(); |
+ if (selector != null) selector.destroy(); |
+ |
+ if (mWindowAndroid != null) mWindowAndroid.destroy(); |
+ if (!Locale.getDefault().equals(mCurrentLocale)) { |
+ // This is a hack to relaunch renderer processes. Killing the main process also kills |
+ // its dependent (renderer) processes, and Android's activity manager service seems to |
+ // still relaunch the activity even when process dies in onDestroy(). |
+ // This shouldn't be moved to ChromeActivity since it may cause a crash if |
+ // you kill the process from EmbedContentViewActivity since Preferences looks up |
+ // ChildAccountManager#hasChildAccount() when it is not set. |
+ // TODO(changwan): Implement a more generic and safe relaunch mechanism such as |
+ // killing dependent processes on onDestroy and launching them at onCreate(). |
+ Log.w(TAG, "Forcefully killing process..."); |
+ Process.killProcess(Process.myPid()); |
+ } |
+ super.onDestroy(); |
+ } |
+ |
+ /** |
+ * Override this to perform destruction tasks. Note that by the time this is called, the |
+ * {@link CompositorViewHolder} will be destroyed, but the {@link WindowAndroid} and |
+ * {@link TabModelSelector} will not. |
+ * <p> |
+ * After returning from this, the {@link TabModelSelector} will be destroyed followed |
+ * by the {@link WindowAndroid}. |
+ */ |
+ protected void onDestroyInternal() { |
+ } |
+ |
+ /** |
+ * This will handle passing {@link Intent} results back to the {@link WindowAndroid}. It will |
+ * return whether or not the {@link WindowAndroid} has consumed the event or not. |
+ */ |
+ @Override |
+ public boolean onActivityResultWithNative(int requestCode, int resultCode, Intent intent) { |
+ if (super.onActivityResultWithNative(requestCode, resultCode, intent)) return true; |
+ return mWindowAndroid.onActivityResult(requestCode, resultCode, intent); |
+ } |
+ |
+ @Override |
+ protected void onSaveInstanceState(Bundle outState) { |
+ super.onSaveInstanceState(outState); |
+ mWindowAndroid.saveInstanceState(outState); |
+ } |
+ |
+ /** |
+ * @return The unified manager for all snackbar related operations. |
+ */ |
+ @Override |
+ public SnackbarManager getSnackbarManager() { |
+ return mSnackbarManager; |
+ } |
+ |
+ /** |
+ * Add the specified tab to bookmarks or allows to edit the bookmark if the specified tab is |
+ * already bookmarked. If a new bookmark is added, a snackbar will be shown. |
+ * @param tabToBookmark The tab that needs to be bookmarked. |
+ */ |
+ public void addOrEditBookmark(final Tab tabToBookmark) { |
+ if (tabToBookmark == null || tabToBookmark.isFrozen()) { |
+ return; |
+ } |
+ |
+ // Managed bookmarks can't be edited. If the current URL is only bookmarked by managed |
+ // bookmarks then fall back on adding a new bookmark instead. |
+ final long bookmarkId = tabToBookmark.getUserBookmarkId(); |
+ |
+ if (EnhancedBookmarkUtils.isEnhancedBookmarkEnabled(tabToBookmark.getProfile())) { |
+ final EnhancedBookmarksModel bookmarkModel = new EnhancedBookmarksModel(); |
+ |
+ BookmarkModelObserver modelObserver = new BookmarkModelObserver() { |
+ @Override |
+ public void bookmarkModelChanged() {} |
+ |
+ @Override |
+ public void bookmarkModelLoaded() { |
+ if (bookmarkId == ChromeBrowserProviderClient.INVALID_BOOKMARK_ID) { |
+ EnhancedBookmarkUtils.addBookmarkAndShowSnackbar(bookmarkModel, |
+ tabToBookmark, getSnackbarManager(), CompositorChromeActivity.this); |
+ } else { |
+ EnhancedBookmarkUtils.startDetailActivity(CompositorChromeActivity.this, |
+ new BookmarkId(bookmarkId, BookmarkType.NORMAL)); |
+ } |
+ bookmarkModel.removeModelObserver(this); |
+ } |
+ }; |
+ |
+ if (bookmarkModel.isBookmarkModelLoaded()) { |
+ modelObserver.bookmarkModelLoaded(); |
+ } else { |
+ bookmarkModel.addModelObserver(modelObserver); |
+ } |
+ } else { |
+ Intent intent = new Intent(this, ManageBookmarkActivity.class); |
+ // Managed bookmarks can't be edited. Fallback on adding a new bookmark if the current |
+ // URL is bookmarked by a managed bookmark. |
+ |
+ if (bookmarkId == ChromeBrowserProviderClient.INVALID_BOOKMARK_ID) { |
+ intent.putExtra(ManageBookmarkActivity.BOOKMARK_INTENT_IS_FOLDER, false); |
+ intent.putExtra(ManageBookmarkActivity.BOOKMARK_INTENT_TITLE, |
+ tabToBookmark.getTitle()); |
+ intent.putExtra(ManageBookmarkActivity.BOOKMARK_INTENT_URL, tabToBookmark.getUrl()); |
+ } else { |
+ intent.putExtra(ManageBookmarkActivity.BOOKMARK_INTENT_IS_FOLDER, false); |
+ intent.putExtra(ManageBookmarkActivity.BOOKMARK_INTENT_ID, bookmarkId); |
+ } |
+ startActivity(intent); |
+ } |
+ } |
+ |
+ /** |
+ * @return A {@link WindowAndroid} instance. |
+ */ |
+ public WindowAndroid getWindowAndroid() { |
+ return mWindowAndroid; |
+ } |
+ |
+ /** |
+ * @return A {@link CompositorViewHolder} instance. |
+ */ |
+ public CompositorViewHolder getCompositorViewHolder() { |
+ return mCompositorViewHolder; |
+ } |
+ |
+ @Override |
+ public ChromeFullscreenManager getFullscreenManager() { |
+ return mFullscreenManager; |
+ } |
+ |
+ @Override |
+ public ContentOffsetProvider getContentOffsetProvider() { |
+ return mCompositorViewHolder.getContentOffsetProvider(); |
+ } |
+ |
+ @Override |
+ public ContentReadbackHandler getContentReadbackHandler() { |
+ return mCompositorViewHolder.getContentReadbackHandler(); |
+ } |
+ |
+ /** |
+ * Starts asynchronously taking the compositor activity screenshot. |
+ * @param getBitmapCallback The callback to call once the screenshot is taken, or when failed. |
+ */ |
+ public void startTakingCompositorActivityScreenshot(GetBitmapCallback getBitmapCallback) { |
+ ContentReadbackHandler readbackHandler = getContentReadbackHandler(); |
+ if (readbackHandler == null || getWindowAndroid() == null) { |
+ getBitmapCallback.onFinishGetBitmap(null, ReadbackResponse.SURFACE_UNAVAILABLE); |
+ } else { |
+ readbackHandler.getCompositorBitmapAsync(getWindowAndroid(), getBitmapCallback); |
+ } |
+ } |
+ |
+ @Override |
+ public ContextualSearchManager getContextualSearchManager() { |
+ return mContextualSearchManager; |
+ } |
+ |
+ /** |
+ * @return A {@link ReaderModeActivityDelegate} instance or {@code null} if reader mode is |
+ * not enabled. |
+ */ |
+ public ReaderModeActivityDelegate getReaderModeActivityDelegate() { |
+ return mReaderModeActivityDelegate; |
+ } |
+ |
+ /** |
+ * Create a full-screen manager to be used by this activity. |
+ * @param controlContainer The control container that will be controlled by the full-screen |
+ * manager. |
+ * @return A {@link ChromeFullscreenManager} instance that's been created. |
+ */ |
+ protected ChromeFullscreenManager createFullscreenManager(View controlContainer) { |
+ return new ChromeFullscreenManager(this, controlContainer, getTabModelSelector(), |
+ getControlContainerHeightResource(), true); |
+ } |
+ |
+ /** |
+ * Initializes the {@link CompositorViewHolder} with the relevant content it needs to properly |
+ * show content on the screen. |
+ * @param layoutManager A {@link LayoutManagerDocument} instance. This class is |
+ * responsible for driving all high level screen content and |
+ * determines which {@link Layout} is shown when. |
+ * @param urlBar The {@link View} representing the URL bar (must be |
+ * focusable) or {@code null} if none exists. |
+ * @param contentContainer A {@link ViewGroup} that can have content attached by |
+ * {@link Layout}s. |
+ * @param controlContainer A {@link ControlContainer} instance to draw. |
+ */ |
+ protected void initializeCompositorContent( |
+ LayoutManagerDocument layoutManager, View urlBar, ViewGroup contentContainer, |
+ ControlContainer controlContainer) { |
+ CommandLine commandLine = CommandLine.getInstance(); |
+ boolean enableFullscreen = !commandLine.hasSwitch(ChromeSwitches.DISABLE_FULLSCREEN); |
+ |
+ if (enableFullscreen && controlContainer != null) { |
+ mFullscreenManager = createFullscreenManager((View) controlContainer); |
+ } |
+ |
+ if (mContextualSearchManager != null) { |
+ mContextualSearchManager.initialize(contentContainer); |
+ mContextualSearchManager.setSearchContentViewDelegate(layoutManager); |
+ } |
+ |
+ if (mReaderModeActivityDelegate != null) { |
+ mReaderModeActivityDelegate.initialize(contentContainer); |
+ mReaderModeActivityDelegate.setDynamicResourceLoader( |
+ mCompositorViewHolder.getDynamicResourceLoader()); |
+ mReaderModeActivityDelegate.getReaderModeControl(); |
+ } |
+ |
+ layoutManager.addSceneChangeObserver(this); |
+ mCompositorViewHolder.setLayoutManager(layoutManager); |
+ mCompositorViewHolder.setFocusable(false); |
+ mCompositorViewHolder.setControlContainer(controlContainer); |
+ mCompositorViewHolder.setFullscreenHandler(mFullscreenManager); |
+ mCompositorViewHolder.setUrlBar(urlBar); |
+ mCompositorViewHolder.onFinishNativeInitialization(getTabModelSelector(), this, |
+ getTabContentManager(), contentContainer, mContextualSearchManager); |
+ |
+ if (controlContainer != null |
+ && DeviceClassManager.enableToolbarSwipe(FeatureUtilities.isDocumentMode(this))) { |
+ controlContainer.setSwipeHandler( |
+ getCompositorViewHolder().getLayoutManager().getTopSwipeHandler()); |
+ } |
+ } |
+ |
+ /** |
+ * Called when the back button is pressed. |
+ * @return Whether or not the back button was handled. |
+ */ |
+ protected abstract boolean handleBackPressed(); |
+ |
+ @Override |
+ public void onOrientationChange(int orientation) { |
+ if (mContextualSearchManager != null) { |
+ mContextualSearchManager.onOrientationChange(); |
+ } |
+ } |
+ |
+ @Override |
+ public final void onBackPressed() { |
+ if (mCompositorViewHolder != null) { |
+ LayoutManager layoutManager = mCompositorViewHolder.getLayoutManager(); |
+ boolean layoutConsumed = layoutManager != null && layoutManager.onBackPressed(); |
+ if (layoutConsumed || mContextualSearchManager != null |
+ && mContextualSearchManager.onBackPressed()) { |
+ RecordUserAction.record("SystemBack"); |
+ return; |
+ } |
+ } |
+ if (!isSelectActionBarShowing() && handleBackPressed()) { |
+ return; |
+ } |
+ // This will close the select action bar if it is showing, otherwise close the activity. |
+ super.onBackPressed(); |
+ } |
+ |
+ private boolean isSelectActionBarShowing() { |
+ Tab tab = getActivityTab(); |
+ if (tab == null) return false; |
+ ContentViewCore contentViewCore = tab.getContentViewCore(); |
+ if (contentViewCore == null) return false; |
+ return contentViewCore.isSelectActionBarShowing(); |
+ } |
+ |
+ @Override |
+ public boolean createContextualSearchTab(ContentViewCore searchContentViewCore) { |
+ Tab currentTab = getActivityTab(); |
+ if (currentTab == null) return false; |
+ |
+ ChromeTabCreator tabCreator = getTabCreator(currentTab.isIncognito()); |
+ if (tabCreator == null) return false; |
+ |
+ tabCreator.createTabWithWebContents(searchContentViewCore.getWebContents(), |
+ currentTab.getId(), TabLaunchType.FROM_LONGPRESS_FOREGROUND); |
+ return true; |
+ } |
+ |
+ @VisibleForTesting |
+ public AppMenuHandler getAppMenuHandler() { |
+ return null; |
+ } |
+ |
+ @Override |
+ public boolean shouldShowAppMenu() { |
+ // Do not show the menu if Contextual Search Panel is opened. |
+ if (mContextualSearchManager != null && mContextualSearchManager.isSearchPanelOpened()) { |
+ return false; |
+ } |
+ |
+ return true; |
+ } |
+ |
+ @Override |
+ public boolean onMenuOrKeyboardAction(int id, boolean fromMenu) { |
+ if (id == R.id.preferences_id) { |
+ PreferencesLauncher.launchSettingsPage(this, null); |
+ RecordUserAction.record("MobileMenuSettings"); |
+ } |
+ |
+ // All the code below assumes currentTab is not null, so return early if it is null. |
+ final Tab currentTab = getActivityTab(); |
+ if (currentTab == null) { |
+ return false; |
+ } else if (id == R.id.forward_menu_id) { |
+ if (currentTab.canGoForward()) { |
+ currentTab.goForward(); |
+ RecordUserAction.record("MobileMenuForward"); |
+ RecordUserAction.record("MobileTabClobbered"); |
+ } |
+ } else if (id == R.id.bookmark_this_page_id) { |
+ addOrEditBookmark(currentTab); |
+ RecordUserAction.record("MobileMenuAddToBookmarks"); |
+ } else if (id == R.id.reload_menu_id) { |
+ if (currentTab.isLoading()) { |
+ currentTab.stopLoading(); |
+ } else { |
+ currentTab.reload(); |
+ RecordUserAction.record("MobileToolbarReload"); |
+ } |
+ } else if (id == R.id.info_menu_id) { |
+ WebsiteSettingsPopup.show(this, currentTab.getProfile(), currentTab.getWebContents()); |
+ } else if (id == R.id.open_history_menu_id) { |
+ currentTab.loadUrl( |
+ new LoadUrlParams(UrlConstants.HISTORY_URL, PageTransition.AUTO_TOPLEVEL)); |
+ } else if (id == R.id.share_menu_id || id == R.id.direct_share_menu_id) { |
+ onShareMenuItemSelected(currentTab, getWindowAndroid(), |
+ id == R.id.direct_share_menu_id, getCurrentTabModel().isIncognito()); |
+ } else if (id == R.id.print_id) { |
+ PrintingController printingController = getChromeApplication().getPrintingController(); |
+ if (printingController != null && !printingController.isBusy() |
+ && PrefServiceBridge.getInstance().isPrintingEnabled()) { |
+ printingController.startPrint(new TabPrinter(currentTab), |
+ new PrintManagerDelegateImpl(this)); |
+ RecordUserAction.record("MobileMenuPrint"); |
+ } |
+ } else if (id == R.id.add_to_homescreen_id) { |
+ AddToHomescreenDialog.show(this, currentTab); |
+ RecordUserAction.record("MobileMenuAddToHomescreen"); |
+ } else if (id == R.id.request_desktop_site_id) { |
+ final boolean reloadOnChange = !currentTab.isNativePage(); |
+ final boolean usingDesktopUserAgent = currentTab.getUseDesktopUserAgent(); |
+ currentTab.setUseDesktopUserAgent(!usingDesktopUserAgent, reloadOnChange); |
+ RecordUserAction.record("MobileMenuRequestDesktopSite"); |
+ } else if (id == R.id.reader_mode_prefs_id) { |
+ if (currentTab.getWebContents() != null) { |
+ RecordUserAction.record("DomDistiller_DistilledPagePrefsOpened"); |
+ AlertDialog.Builder builder = |
+ new AlertDialog.Builder(this, R.style.AlertDialogTheme); |
+ builder.setView(DistilledPagePrefsView.create(this)); |
+ builder.show(); |
+ } |
+ } else if (id == R.id.help_id) { |
+ // Since reading back the compositor is asynchronous, we need to do the readback |
+ // before starting the GoogleHelp. |
+ final String helpContextId = HelpAndFeedback.getHelpContextIdFromUrl( |
+ currentTab.getUrl(), getCurrentTabModel().isIncognito()); |
+ final Activity mainActivity = this; |
+ startTakingCompositorActivityScreenshot(new GetBitmapCallback() { |
+ @Override |
+ public void onFinishGetBitmap(Bitmap bitmap, int response) { |
+ HelpAndFeedback.getInstance(mainActivity).show( |
+ mainActivity, helpContextId, bitmap, currentTab.getUrl()); |
+ RecordUserAction.record("MobileMenuFeedback"); |
+ } |
+ }); |
+ } else { |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
+ @Override |
+ public void onTabSelectionHinted(int tabId) { } |
+ |
+ @Override |
+ public void onSceneChange(Layout layout) { } |
+} |