| Index: chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
|
| diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..aa4c6cce7d68fe7ba640a8bec8464de17e519902
|
| --- /dev/null
|
| +++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
|
| @@ -0,0 +1,682 @@
|
| +// 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.dom_distiller;
|
| +
|
| +import static org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.AnimatableAnimation.createAnimation;
|
| +
|
| +import android.content.Context;
|
| +
|
| +import org.chromium.base.metrics.RecordUserAction;
|
| +import org.chromium.chrome.browser.ContentViewUtil;
|
| +import org.chromium.chrome.browser.Tab;
|
| +import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
|
| +import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable;
|
| +import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeEventFilter.ScrollDirection;
|
| +import org.chromium.chrome.browser.dom_distiller.ReaderModeButtonView.ReaderModeButtonViewDelegate;
|
| +import org.chromium.chrome.browser.tab.ChromeTab;
|
| +import org.chromium.chrome.browser.util.MathUtils;
|
| +import org.chromium.content.browser.ContentView;
|
| +import org.chromium.content.browser.ContentViewCore;
|
| +import org.chromium.content_public.browser.WebContentsObserver;
|
| +import org.chromium.content_public.common.TopControlsState;
|
| +import org.chromium.ui.base.WindowAndroid;
|
| +
|
| +/**
|
| + * Manages UI effects for reader mode including hiding and showing the
|
| + * reader mode and reader mode preferences toolbar icon and hiding the
|
| + * top controls when a reader mode page has finished loading.
|
| + *
|
| + * TODO(aruslan): combine with ContextualSearchPanel.
|
| + */
|
| +public class ReaderModePanel implements ChromeAnimation.Animatable<ReaderModePanel.Property> {
|
| + // TODO(aruslan): pull this from the FullscreenManager.
|
| + private static final float TOOLBAR_HEIGHT_DP = 56.0f;
|
| +
|
| + private static final float PANEL_HEIGHT_DP = TOOLBAR_HEIGHT_DP;
|
| + private static final float SHADOW_HEIGHT_DP = 4.0f;
|
| + private static final float MINIMAL_BORDER_X_DP = 4.0f;
|
| + private static final float DARKEN_LAYOUTTAB_BRIGHTNESS = 0.3f;
|
| + private static final float MAX_LAYOUTTAB_DISPLACEMENT = 3.0f * TOOLBAR_HEIGHT_DP;
|
| +
|
| + private static final float SNAP_BACK_THRESHOLD = 0.3f;
|
| + private static final long BASE_ANIMATION_DURATION_MS = 500;
|
| +
|
| + /**
|
| + * Panel's host interface.
|
| + */
|
| + public interface ReaderModePanelHost {
|
| + /**
|
| + * @return Whether the reader mode button should be animated.
|
| + */
|
| + boolean allowReaderModeButtonAnimation();
|
| +
|
| + /**
|
| + * @return Reader mode header background color.
|
| + */
|
| + int getReaderModeHeaderBackgroundColor();
|
| +
|
| + /**
|
| + * @return One of ReaderModeManager.POSSIBLE, NOT_POSSIBLE, STARTED constants.
|
| + */
|
| + int getReaderModeStatus();
|
| +
|
| + /**
|
| + * @return An associated tab.
|
| + */
|
| + Tab getTab();
|
| +
|
| + /**
|
| + * @param X X-coordinate in dp
|
| + * @param Y Y-coordinate in dp
|
| + * @return Whether a given coordinates are within the bounds of the "dismiss" button
|
| + */
|
| + public boolean isInsideDismissButton(float x, float y);
|
| + }
|
| +
|
| + /**
|
| + * Layout integration interface.
|
| + */
|
| + public interface ReaderModePanelLayoutDelegate {
|
| + /**
|
| + * Requests a next update to refresh the transforms and changing properties.
|
| + */
|
| + void requestUpdate();
|
| +
|
| + /**
|
| + * Sets the brightness of the LayoutTab to a given value.
|
| + * @param v Brightness
|
| + */
|
| + void setLayoutTabBrightness(float v);
|
| +
|
| + /**
|
| + * Sets the Y offset of the LayoutTab to a given value.
|
| + * @param v Y-offset in dp
|
| + */
|
| + void setLayoutTabY(float v);
|
| + }
|
| +
|
| + /**
|
| + * Properties that can be animated by using a
|
| + * {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable}.
|
| + */
|
| + public enum Property {
|
| + /**
|
| + * Parametric vertical slider from
|
| + * -1.0 (panel is out of screen) to
|
| + * 0.0 (panel is on screen) to
|
| + * 1.0 (panel covers the entire screen)
|
| + */
|
| + SLIDING_T,
|
| + /**
|
| + * Horizontal slider, offset in dp
|
| + */
|
| + X,
|
| + }
|
| +
|
| + private float mSlidingT;
|
| + private float mX;
|
| +
|
| + private ScrollDirection mSwipeDirection; // set in swipeStarted
|
| + private float mInitialPanelDistanceFromBottom; // distance from the bottom at swipeStarted
|
| + private float mInitialX; // X at swipeStarted
|
| +
|
| + /**
|
| + * The animation set.
|
| + */
|
| + private ChromeAnimation<ChromeAnimation.Animatable<?>> mLayoutAnimations;
|
| +
|
| + private boolean mIsReaderModePanelHidden;
|
| + private boolean mIsReaderModePanelDismissed;
|
| + private ContentViewCore mDistilledContentViewCore;
|
| + private WebContentsObserver mDistilledContentObserver;
|
| + private boolean mDidFirstNonEmptyDistilledPaint;
|
| + private ReaderModePanelLayoutDelegate mLayoutDelegate;
|
| +
|
| + private float mLayoutWidth;
|
| + private float mLayoutHeight;
|
| + private boolean mIsToolbarShowing;
|
| + private float mDpToPx;
|
| +
|
| + /**
|
| + * The {@link ReaderModePanelHost} used to get reader mode status and the associated tab.
|
| + */
|
| + private final ReaderModePanelHost mReaderModeHost;
|
| +
|
| + /**
|
| + * Non-animated button support.
|
| + */
|
| + private boolean mAllowAnimatedButton;
|
| + private ReaderModeButtonView mReaderModeButtonView;
|
| +
|
| + public ReaderModePanel(ReaderModePanelHost readerModeHost) {
|
| + mReaderModeHost = readerModeHost;
|
| + mAllowAnimatedButton = mReaderModeHost.allowReaderModeButtonAnimation();
|
| +
|
| + mLayoutWidth = 0.0f;
|
| + mLayoutHeight = 0.0f;
|
| + mDpToPx = 1.0f;
|
| +
|
| + mSlidingT = -1.0f;
|
| + mX = 0.0f;
|
| + }
|
| +
|
| + /**
|
| + * Destroys the panel and associated resources.
|
| + */
|
| + public void onDestroy() {
|
| + mLayoutAnimations = null;
|
| + hideButtonBar();
|
| + }
|
| +
|
| + /**
|
| + * Set the layout delegate.
|
| + * @param layoutDelegate A {@link ReaderModePanelLayoutDelegate} to call.
|
| + */
|
| + public void setLayoutDelegate(ReaderModePanelLayoutDelegate layoutDelegate) {
|
| + mLayoutDelegate = layoutDelegate;
|
| + requestUpdate();
|
| + }
|
| +
|
| + // ChromeAnimation.Animatable<Property>:
|
| +
|
| + private void setSlidingT(float val) {
|
| + mSlidingT = val;
|
| + if (mLayoutDelegate != null) {
|
| + mLayoutDelegate.setLayoutTabBrightness(getTabBrightness());
|
| + mLayoutDelegate.setLayoutTabY(getTabYOffset());
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void setProperty(Property prop, float val) {
|
| + switch (prop) {
|
| + case SLIDING_T:
|
| + setSlidingT(val);
|
| + break;
|
| + case X:
|
| + mX = val;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + private static float clamp(float val, float lower, float higher) {
|
| + return val < lower ? lower : (val > higher ? higher : val);
|
| + }
|
| +
|
| + private static float interp(float factor, float start, float end) {
|
| + return start + clamp(factor, 0.0f, 1.0f) * (end - start);
|
| + }
|
| +
|
| + private float getPanelDistanceFromBottom() {
|
| + if (mSlidingT < 0.0f) return interp(mSlidingT + 1.0f, 0.0f, PANEL_HEIGHT_DP);
|
| + return PANEL_HEIGHT_DP + interp(mSlidingT, 0.0f, getFullscreenHeight());
|
| + }
|
| +
|
| + private float getSlidingTForPanelDistanceFromBottom(float distanceFromBottom) {
|
| + if (distanceFromBottom >= PANEL_HEIGHT_DP) {
|
| + return interp(
|
| + (distanceFromBottom - PANEL_HEIGHT_DP) / getFullscreenHeight(),
|
| + 0.0f, 1.0f);
|
| + }
|
| + return interp(
|
| + (PANEL_HEIGHT_DP - distanceFromBottom) / PANEL_HEIGHT_DP,
|
| + 0.0f, -1.0f);
|
| + }
|
| +
|
| + private float getDistilledContentDistanceFromBottom() {
|
| + if (mSlidingT < 0.0f) return interp(mSlidingT + 1.0f, -PANEL_HEIGHT_DP, 0.0f);
|
| + return interp(mSlidingT, 0.0f, getFullscreenHeight());
|
| + }
|
| +
|
| + private static float snapBackSlidingT(float v) {
|
| + // We snap asymmetrically: 30% is enough to get it opened, but 70% is necessary to dismiss.
|
| + v = (v < -1.0f + SNAP_BACK_THRESHOLD) ? v : (v >= SNAP_BACK_THRESHOLD ? v : 0.0f);
|
| + return Math.signum(v);
|
| + }
|
| +
|
| + private static float snapBackX(float v) {
|
| + // Horizontally we snap symmetrically: more than 70% to each side to dismiss.
|
| + v = (v < -1.0f + SNAP_BACK_THRESHOLD) ? v : (v >= 1.0f - SNAP_BACK_THRESHOLD ? v : 0.0f);
|
| + return Math.signum(v);
|
| + }
|
| +
|
| + // Gesture handling:
|
| +
|
| + /**
|
| + * @param direction Swipe direction to test
|
| + * @return Whether the swipe in a given direction is enabled
|
| + */
|
| + public boolean isSwipeEnabled(ScrollDirection direction) {
|
| + return !isAnimating();
|
| + }
|
| +
|
| + /**
|
| + * Called when the swipe is started.
|
| + * @param direction Swipe direction
|
| + * @param x X-coordinate of the starting point in dp
|
| + * @param y Y-coordinate of the starting point in dp
|
| + */
|
| + public void swipeStarted(ScrollDirection direction, float x, float y) {
|
| + if (isAnimating()) return;
|
| +
|
| + mSwipeDirection = direction;
|
| + mInitialPanelDistanceFromBottom = getPanelDistanceFromBottom();
|
| + mX = getX();
|
| +
|
| + if (mSwipeDirection == ScrollDirection.UP) activatePreviewOfDistilledMode();
|
| +
|
| + requestUpdate();
|
| + }
|
| +
|
| + /**
|
| + * Called when the swipe is continued.
|
| + * @param tx X-offset since the start of the swipe in dp
|
| + * @param ty Y-offset since the start of the swipe in dp
|
| + */
|
| + public void swipeUpdated(float x, float y, float dx, float dy, float tx, float ty) {
|
| + if (isAnimating()) return;
|
| +
|
| + if (mSwipeDirection == ScrollDirection.LEFT || mSwipeDirection == ScrollDirection.RIGHT) {
|
| + setProperty(ReaderModePanel.Property.X, clamp(mInitialX + tx,
|
| + -mLayoutWidth + MINIMAL_BORDER_X_DP, mLayoutWidth - MINIMAL_BORDER_X_DP));
|
| + } else {
|
| + setProperty(ReaderModePanel.Property.SLIDING_T,
|
| + getSlidingTForPanelDistanceFromBottom(mInitialPanelDistanceFromBottom - ty));
|
| + }
|
| + requestUpdate();
|
| + }
|
| +
|
| + /**
|
| + * Called when the swipe is finished.
|
| + */
|
| + public void swipeFinished() {
|
| + if (isAnimating()) return;
|
| +
|
| + final float snappedX = snapBackX(mX / mLayoutWidth) * mLayoutWidth;
|
| + final float snappedSlidingT = snapBackSlidingT(mSlidingT);
|
| + if (snappedX <= -mLayoutWidth || snappedX >= mLayoutWidth) dismissButtonBar();
|
| + if (snappedSlidingT < 0.0f) dismissButtonBar();
|
| +
|
| + animateTo(snappedX, snappedSlidingT, true);
|
| + }
|
| +
|
| + // Panel layout handling:
|
| +
|
| + /**
|
| + * @return Whether the panel should be shown.
|
| + */
|
| + public boolean isShowing() {
|
| + return isPanelWithinScreenBounds() || isAnimating() || mDistilledContentViewCore != null;
|
| + }
|
| +
|
| + /**
|
| + * @return Whether the panel is within screen bounds.
|
| + */
|
| + private boolean isPanelWithinScreenBounds() {
|
| + return mSlidingT > -1.0f;
|
| + }
|
| +
|
| + /**
|
| + * @return The fullscreen height.
|
| + */
|
| + private float getFullscreenHeight() {
|
| + return mLayoutHeight + TOOLBAR_HEIGHT_DP;
|
| + }
|
| +
|
| + public float getFullscreenY(float y) {
|
| + if (mIsToolbarShowing) y += TOOLBAR_HEIGHT_DP * mDpToPx;
|
| + return y;
|
| + }
|
| +
|
| + public float getPanelY() {
|
| + return getFullscreenHeight() - getPanelDistanceFromBottom() - SHADOW_HEIGHT_DP;
|
| + }
|
| +
|
| + public float getDistilledContentY() {
|
| + return getFullscreenHeight() - getDistilledContentDistanceFromBottom() - SHADOW_HEIGHT_DP;
|
| + }
|
| +
|
| + public float getWidth() {
|
| + return mLayoutWidth;
|
| + }
|
| +
|
| + public float getPanelHeight() {
|
| + return getPanelDistanceFromBottom();
|
| + }
|
| +
|
| + public float getMarginTop() {
|
| + return SHADOW_HEIGHT_DP;
|
| + }
|
| +
|
| + public float getDistilledHeight() {
|
| + return getDistilledContentDistanceFromBottom();
|
| + }
|
| +
|
| + public float getX() {
|
| + return mX;
|
| + }
|
| +
|
| + public float getTextOpacity() {
|
| + return interp(mSlidingT, 1.0f, 0.0f);
|
| + }
|
| +
|
| + public float getTabBrightness() {
|
| + return interp(mSlidingT, 1.0f, DARKEN_LAYOUTTAB_BRIGHTNESS);
|
| + }
|
| +
|
| + public float getTabYOffset() {
|
| + return interp(mSlidingT, 0.0f, -MAX_LAYOUTTAB_DISPLACEMENT);
|
| + }
|
| +
|
| + /**
|
| + * @param currentOffset The current top controls offset in dp.
|
| + * @return {@link Float#NaN} if no offset should be used, or a value in dp
|
| + * if the top controls offset should be overridden.
|
| + */
|
| + public float getTopControlsOffset(float currentOffsetDp) {
|
| + if (mSlidingT <= 0.0f) return Float.NaN;
|
| + return MathUtils.clamp(getTabYOffset(), -TOOLBAR_HEIGHT_DP, Math.min(currentOffsetDp, 0f));
|
| + }
|
| +
|
| +
|
| + public ContentViewCore getDistilledContentViewCore() {
|
| + return mDistilledContentViewCore;
|
| + }
|
| +
|
| + public boolean didFirstNonEmptyDistilledPaint() {
|
| + return mDidFirstNonEmptyDistilledPaint;
|
| + }
|
| +
|
| + public int getReaderModeHeaderBackgroundColor() {
|
| + return mReaderModeHost.getReaderModeHeaderBackgroundColor();
|
| + }
|
| +
|
| + /**
|
| + * Called when the size of the view has changed.
|
| + *
|
| + * @param width The new width in dp.
|
| + * @param height The new width in dp.
|
| + * @param isToolbarShowing Whether the Toolbar is showing.
|
| + * @param dpToPx Multipler to convert from dp to pixels.
|
| + */
|
| + public void onSizeChanged(float width, float height, boolean isToolbarShowing, float dpToPx) {
|
| + mLayoutWidth = width;
|
| + mLayoutHeight = height;
|
| + mIsToolbarShowing = isToolbarShowing;
|
| + mDpToPx = dpToPx;
|
| + }
|
| +
|
| + // Layout integration:
|
| +
|
| + /**
|
| + * Requests a new frame to be updated and rendered.
|
| + */
|
| + private void requestUpdate() {
|
| + if (mLayoutDelegate != null) mLayoutDelegate.requestUpdate();
|
| + }
|
| +
|
| + // Animation handling:
|
| +
|
| + /**
|
| + * @return Whether a panel animation is in progress.
|
| + */
|
| + private boolean isAnimating() {
|
| + return mLayoutAnimations != null && !mLayoutAnimations.finished();
|
| + }
|
| +
|
| + /**
|
| + * Animates to a given target value.
|
| + * @param targetX A target value for the X parameter
|
| + * @param targetSlidingT A target value for the SlidingT parameter
|
| + */
|
| + private void animateTo(float targetX, float targetSlidingT, boolean animate) {
|
| + if (targetSlidingT > 0.0f) activatePreviewOfDistilledMode();
|
| +
|
| + if (isAnimating()) {
|
| + mLayoutAnimations.cancel(this, Property.SLIDING_T);
|
| + mLayoutAnimations.cancel(this, Property.X);
|
| + }
|
| + if (mLayoutAnimations == null || mLayoutAnimations.finished()) {
|
| + mLayoutAnimations = new ChromeAnimation<Animatable<?>>();
|
| + }
|
| +
|
| + mLayoutAnimations.add(createAnimation(
|
| + this, Property.SLIDING_T, mSlidingT, targetSlidingT,
|
| + BASE_ANIMATION_DURATION_MS, 0, false,
|
| + ChromeAnimation.getDecelerateInterpolator()));
|
| + mLayoutAnimations.add(createAnimation(
|
| + this, Property.X, mX, targetX,
|
| + BASE_ANIMATION_DURATION_MS, 0, false,
|
| + ChromeAnimation.getDecelerateInterpolator()));
|
| + mLayoutAnimations.start();
|
| +
|
| + if (!animate) mLayoutAnimations.updateAndFinish();
|
| + requestUpdate();
|
| + }
|
| +
|
| + /**
|
| + * Steps the animation forward and updates all the animated values.
|
| + * @param time The current time of the app in ms.
|
| + * @param jumpToEnd Whether to finish the animation.
|
| + * @return Whether the animation was finished.
|
| + */
|
| + public boolean onUpdateAnimation(long time, boolean jumpToEnd) {
|
| + boolean finished = true;
|
| + if (mLayoutAnimations != null) {
|
| + if (jumpToEnd) {
|
| + finished = mLayoutAnimations.finished();
|
| + mLayoutAnimations.updateAndFinish();
|
| + } else {
|
| + finished = mLayoutAnimations.update(time);
|
| + }
|
| +
|
| + if (finished || jumpToEnd) {
|
| + mLayoutAnimations = null;
|
| + onAnimationFinished();
|
| + }
|
| + requestUpdate();
|
| + }
|
| + return finished;
|
| + }
|
| +
|
| + /**
|
| + * Called when layout-specific actions are needed after the animation finishes.
|
| + */
|
| + private void onAnimationFinished() {
|
| + if (mSlidingT >= 1.0f) enterDistilledMode();
|
| + updateBottomButtonBar();
|
| + }
|
| +
|
| + // Gesture handling:
|
| +
|
| + /**
|
| + * @param y The y coordinate in dp.
|
| + * @return Whether the given |y| coordinate is inside the Reader mode area.
|
| + */
|
| + public boolean isYCoordinateInsideReaderModePanel(float y) {
|
| + return y >= getPanelY() || y >= getDistilledContentY();
|
| + }
|
| +
|
| + /**
|
| + * Handles a click in the panel area.
|
| + * @param x X-coordinate in dp
|
| + * @param y Y-coordinate in dp
|
| + */
|
| + public void handleClick(long time, float x, float y) {
|
| + if (mReaderModeHost.isInsideDismissButton(x * mDpToPx + mX, PANEL_HEIGHT_DP / 2)) {
|
| + dismissButtonBar();
|
| + return;
|
| + }
|
| +
|
| + animateTo(mX, 1.0f, true);
|
| + }
|
| +
|
| + private void nonAnimatedUpdateButtomButtonBar() {
|
| + final int status = mReaderModeHost.getReaderModeStatus();
|
| + final Tab tab = mReaderModeHost.getTab();
|
| +
|
| + if (mReaderModeButtonView != null
|
| + && (status != ReaderModeManager.POSSIBLE || mIsReaderModePanelHidden
|
| + || mIsReaderModePanelDismissed)) {
|
| + mReaderModeButtonView.dismiss(true);
|
| + mReaderModeButtonView = null;
|
| + return;
|
| + }
|
| + if (mReaderModeButtonView == null
|
| + && (status == ReaderModeManager.POSSIBLE && !mIsReaderModePanelHidden
|
| + && !mIsReaderModePanelDismissed)) {
|
| + mReaderModeButtonView = ReaderModeButtonView.create(tab.getContentViewCore(),
|
| + new ReaderModeButtonViewDelegate() {
|
| + @Override
|
| + public void onSwipeAway() {
|
| + dismissButtonBar();
|
| + }
|
| +
|
| + @Override
|
| + public void onClick() {
|
| + nonAnimatedEnterDistilledMode();
|
| + }
|
| + });
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Updates the visibility of the reader mode button bar as required.
|
| + */
|
| + public void updateBottomButtonBar() {
|
| + if (!mAllowAnimatedButton) {
|
| + nonAnimatedUpdateButtomButtonBar();
|
| + return;
|
| + }
|
| +
|
| + if (isAnimating()) return;
|
| +
|
| + final int status = mReaderModeHost.getReaderModeStatus();
|
| + if (isPanelWithinScreenBounds()
|
| + && (status != ReaderModeManager.POSSIBLE
|
| + || mIsReaderModePanelHidden || mIsReaderModePanelDismissed)) {
|
| + animateTo(0.0f, -1.0f, true);
|
| + destroyDistilledContentViewCore();
|
| + requestUpdate();
|
| + return;
|
| + }
|
| +
|
| + if (!isPanelWithinScreenBounds()
|
| + && (status == ReaderModeManager.POSSIBLE
|
| + && !mIsReaderModePanelHidden && !mIsReaderModePanelDismissed)) {
|
| + animateTo(0.0f, 0.0f, true);
|
| + requestUpdate();
|
| + return;
|
| + }
|
| + }
|
| +
|
| + private static ContentViewCore createDistillerContentViewCore(
|
| + Context context, WindowAndroid windowAndroid) {
|
| + ContentViewCore cvc = new ContentViewCore(context);
|
| + ContentView cv = new ContentView(context, cvc);
|
| + cvc.initialize(cv, cv, ContentViewUtil.createWebContents(false, true), windowAndroid);
|
| + return cvc;
|
| + }
|
| +
|
| + /**
|
| + * Prepares the distilled mode.
|
| + */
|
| + public void activatePreviewOfDistilledMode() {
|
| + if (mDistilledContentViewCore != null) return;
|
| +
|
| + mDidFirstNonEmptyDistilledPaint = false;
|
| + mDistilledContentViewCore = createDistillerContentViewCore(
|
| + mReaderModeHost.getTab().getContentViewCore().getContext(),
|
| + mReaderModeHost.getTab().getWindowAndroid());
|
| + mDistilledContentObserver = new WebContentsObserver(
|
| + mDistilledContentViewCore.getWebContents()) {
|
| + @Override
|
| + public void didFirstVisuallyNonEmptyPaint() {
|
| + super.didFirstVisuallyNonEmptyPaint();
|
| + mDidFirstNonEmptyDistilledPaint = true;
|
| + }
|
| + };
|
| + mReaderModeHost.getTab().attachOverlayContentViewCore(
|
| + mDistilledContentViewCore, true, false);
|
| + DomDistillerTabUtils.distillAndView(
|
| + mReaderModeHost.getTab().getContentViewCore().getWebContents(),
|
| + mDistilledContentViewCore.getWebContents());
|
| + mDistilledContentViewCore.onShow();
|
| +
|
| + mReaderModeHost.getTab().updateTopControlsState(TopControlsState.BOTH, false);
|
| + }
|
| +
|
| + private void nonAnimatedEnterDistilledMode() {
|
| + RecordUserAction.record("DomDistiller_DistilledPageOpened");
|
| + DomDistillerTabUtils.distillCurrentPageAndView(mReaderModeHost.getTab().getWebContents());
|
| + mReaderModeHost.getTab().updateTopControlsState(TopControlsState.SHOWN, false);
|
| + nonAnimatedUpdateButtomButtonBar();
|
| + }
|
| +
|
| + private void enterDistilledMode() {
|
| + RecordUserAction.record("DomDistiller_DistilledPageOpened");
|
| + mSlidingT = -1.0f;
|
| + requestUpdate();
|
| +
|
| + mReaderModeHost.getTab().updateTopControlsState(TopControlsState.HIDDEN, false);
|
| + DomDistillerTabUtils.distillCurrentPageAndView(mReaderModeHost.getTab().getWebContents());
|
| + destroyDistilledContentViewCore();
|
| + if (mLayoutDelegate != null) {
|
| + mLayoutDelegate.setLayoutTabBrightness(1.0f);
|
| + mLayoutDelegate.setLayoutTabY(0.0f);
|
| + }
|
| +
|
| + updateBottomButtonBar();
|
| + }
|
| +
|
| + private void destroyDistilledContentViewCore() {
|
| + if (mDistilledContentViewCore == null) return;
|
| +
|
| + mDistilledContentObserver.destroy();
|
| + mDistilledContentObserver = null;
|
| + mReaderModeHost.getTab().detachOverlayContentViewCore(mDistilledContentViewCore);
|
| + mDistilledContentViewCore.destroy();
|
| + mDistilledContentViewCore = null;
|
| + }
|
| +
|
| + /**
|
| + * Hides the reader mode button bar if shown.
|
| + */
|
| + public void hideButtonBar() {
|
| + if (mIsReaderModePanelHidden) return;
|
| +
|
| + mIsReaderModePanelHidden = true;
|
| + updateBottomButtonBar();
|
| + }
|
| +
|
| + /**
|
| + * Dismisses the reader mode button bar if shown.
|
| + */
|
| + public void dismissButtonBar() {
|
| + if (mIsReaderModePanelDismissed) return;
|
| +
|
| + mIsReaderModePanelDismissed = true;
|
| + updateBottomButtonBar();
|
| + }
|
| +
|
| + /**
|
| + * Shows the reader mode button bar if necessary.
|
| + */
|
| + public void unhideButtonBar() {
|
| + mIsReaderModePanelHidden = false;
|
| + updateBottomButtonBar();
|
| + }
|
| +
|
| + /**
|
| + * @param tab A {@link Tab}.
|
| + * @return The panel associated with a given Tab.
|
| + */
|
| + public static ReaderModePanel getReaderModePanel(Tab tab) {
|
| + if (!(tab instanceof ChromeTab)) return null;
|
| + ReaderModeManager manager = ((ChromeTab) tab).getReaderModeManager();
|
| + if (manager == null) return null;
|
| + return manager.getReaderModePanel();
|
| + }
|
| +}
|
|
|