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(); |
+ } |
+} |