| 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) { }
 | 
| +}
 | 
| 
 |