Bug 1335895 - part 27: Update DynamicToolbarAnimator to work as a proxy to the AndroidDynamicToolbarAnimator r=jchen,kats draft
authorRandall Barker <rbarker@mozilla.com>
Thu, 23 Mar 2017 10:31:09 -0700
changeset 563861 1243de5eadefee679d9e486013db58d925894e59
parent 563860 e27a5b32ccaf3edcda41b37a4f91df22d95043b5
child 563862 f31990683e60100901b78a0180266467c970f8fe
push id54439
push userbmo:rbarker@mozilla.com
push dateMon, 17 Apr 2017 22:56:51 +0000
reviewersjchen, kats
bugs1335895
milestone55.0a1
Bug 1335895 - part 27: Update DynamicToolbarAnimator to work as a proxy to the AndroidDynamicToolbarAnimator r=jchen,kats MozReview-Commit-ID: EAAAZG2QHSw
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/DynamicToolbarAnimator.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/DynamicToolbarAnimator.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/DynamicToolbarAnimator.java
@@ -1,593 +1,185 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.gfx;
 
-import org.mozilla.gecko.PrefsHelper;
-import org.mozilla.gecko.util.FloatUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
+import android.graphics.Bitmap;
 import android.graphics.PointF;
-import android.support.v4.view.ViewCompat;
 import android.util.Log;
 import android.view.MotionEvent;
-import android.view.animation.LinearInterpolator;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Set;
 
 public class DynamicToolbarAnimator {
     private static final String LOGTAG = "GeckoDynamicToolbarAnimator";
-    private static final String PREF_SCROLL_TOOLBAR_THRESHOLD = "browser.ui.scroll-toolbar-threshold";
 
     public static enum PinReason {
-        RELAYOUT,
-        ACTION_MODE,
-        FULL_SCREEN,
-        CARET_DRAG,
-        PAGE_LOADING
+        DISABLED(0),
+        RELAYOUT(1),
+        ACTION_MODE(2),
+        FULL_SCREEN(3),
+        CARET_DRAG(4),
+        PAGE_LOADING(5);
+
+        public final int mValue;
+        PinReason(final int value) {
+            mValue = value;
+        }
+    }
+
+    public interface MetricsListener {
+        public void onMetricsChanged(ImmutableViewportMetrics viewport);
+    }
+
+    public interface ToolbarChromeProxy {
+        public Bitmap getBitmapOfToolbarChrome();
+        public boolean isToolbarChromeVisible();
+        public void toggleToolbarChrome(boolean aShow);
     }
 
     private final Set<PinReason> pinFlags = Collections.synchronizedSet(EnumSet.noneOf(PinReason.class));
 
-    // The duration of the animation in ns
-    private static final long ANIMATION_DURATION = 150000000;
-
     private final GeckoLayerClient mTarget;
-    private final List<LayerView.DynamicToolbarListener> mListeners;
-
-    /* The translation to be applied to the toolbar UI view. This is the
-     * distance from the default/initial location (at the top of the screen,
-     * visible to the user) to where we want it to be. This variable should
-     * always be between 0 (toolbar fully visible) and the height of the toolbar
-     * (toolbar fully hidden), inclusive.
-     */
-    private float mToolbarTranslation;
-
-    /* The translation to be applied to the LayerView. This is the distance from
-     * the default/initial location (just below the toolbar, with the bottom
-     * extending past the bottom of the screen) to where we want it to be.
-     * This variable should always be between 0 and the height of the toolbar,
-     * inclusive.
-     */
-    private float mLayerViewTranslation;
-
-    /* This stores the maximum translation that can be applied to the toolbar
-     * and layerview when scrolling. This is populated with the height of the
-     * toolbar. */
-    private float mMaxTranslation;
-
-    /* This interpolator is used for the above mentioned animation */
-    private LinearInterpolator mInterpolator;
-
-    /* This is the proportion of the viewport rect that needs to be travelled
-     * while scrolling before the translation will start taking effect.
-     */
-    private float SCROLL_TOOLBAR_THRESHOLD = 0.20f;
-    /* The ID of the prefs listener for the scroll-toolbar threshold */
-    private final PrefsHelper.PrefHandler mPrefObserver;
-
-    /* While we are resizing the viewport to account for the toolbar, the Java
-     * code and painted layer metrics in the compositor have different notions
-     * of the CSS viewport height. The Java value is stored in the
-     * GeckoLayerClient's viewport metrics, and the Gecko one is stored here.
-     * This allows us to adjust fixed-pos items correctly.
-     * You must synchronize on mTarget.getLock() to read/write this. */
-    private Integer mHeightDuringResize;
-
-    /* This tracks if we should trigger a "snap" on the next composite. A "snap"
-     * is when we simultaneously move the LayerView and change the scroll offset
-     * in the compositor so that everything looks the same on the screen but
-     * has really been shifted.
-     * You must synchronize on |this| to read/write this. */
-    private boolean mSnapRequired = false;
-
-    /* The task that handles showing/hiding toolbar */
-    private DynamicToolbarAnimationTask mAnimationTask;
-
-    /* The start point of a drag, used for scroll-based dynamic toolbar
-     * behaviour. */
-    private PointF mTouchStart;
-    private float mLastTouch;
-
-    /* Set to true when root content is being scrolled */
-    private boolean mScrollingRootContent;
+    private LayerView.Compositor mCompositor;
+    private final List<MetricsListener> mListeners;
+    private ToolbarChromeProxy mToolbarChromeProxy;
+    private int mMaxToolbarHeight;
+    private boolean mCompositorControllerOpen;
 
     public DynamicToolbarAnimator(GeckoLayerClient aTarget) {
         mTarget = aTarget;
-        mListeners = new ArrayList<LayerView.DynamicToolbarListener>();
-
-        mInterpolator = new LinearInterpolator();
-
-        // Listen to the dynamic toolbar pref
-        mPrefObserver = new PrefsHelper.PrefHandlerBase() {
-            @Override
-            public void prefValue(String pref, int value) {
-                SCROLL_TOOLBAR_THRESHOLD = value / 100.0f;
-            }
-        };
-        PrefsHelper.addObserver(new String[] { PREF_SCROLL_TOOLBAR_THRESHOLD }, mPrefObserver);
+        mListeners = new ArrayList<MetricsListener>();
     }
 
-    public void destroy() {
-        PrefsHelper.removeObserver(mPrefObserver);
-    }
-
-    public void addTranslationListener(LayerView.DynamicToolbarListener aListener) {
+    public void addMetricsListener(MetricsListener aListener) {
         mListeners.add(aListener);
     }
 
-    public void removeTranslationListener(LayerView.DynamicToolbarListener aListener) {
+    public void removeMetricsListener(MetricsListener aListener) {
         mListeners.remove(aListener);
     }
 
-    private void fireListeners() {
-        for (LayerView.DynamicToolbarListener listener : mListeners) {
-            listener.onTranslationChanged(mToolbarTranslation, mLayerViewTranslation);
+    public void setToolbarChromeProxy(ToolbarChromeProxy aToolbarChromeProxy) {
+        mToolbarChromeProxy = aToolbarChromeProxy;
+    }
+
+    /* package-private */ void onToggleChrome(boolean aShow) {
+        if (mToolbarChromeProxy != null) {
+            mToolbarChromeProxy.toggleToolbarChrome(aShow);
         }
     }
 
-    void onPanZoomStopped() {
-        for (LayerView.DynamicToolbarListener listener : mListeners) {
-            listener.onPanZoomStopped();
-        }
-    }
-
-    void onMetricsChanged(ImmutableViewportMetrics aMetrics) {
-        for (LayerView.DynamicToolbarListener listener : mListeners) {
+    /* package-private */ void onMetricsChanged(ImmutableViewportMetrics aMetrics) {
+        for (MetricsListener listener : mListeners) {
             listener.onMetricsChanged(aMetrics);
         }
     }
 
-    public void setMaxTranslation(float maxTranslation) {
+    public void setMaxToolbarHeight(int maxToolbarHeight) {
         ThreadUtils.assertOnUiThread();
-        if (maxTranslation < 0) {
-            Log.e(LOGTAG, "Got a negative max-translation value: " + maxTranslation + "; clamping to zero");
-            mMaxTranslation = 0;
-        } else {
-            mMaxTranslation = maxTranslation;
+        mMaxToolbarHeight = maxToolbarHeight;
+        if (mCompositor != null) {
+            mCompositor.setMaxToolbarHeight(mMaxToolbarHeight);
         }
     }
 
-    public float getMaxTranslation() {
-        return mMaxTranslation;
-    }
-
-    public float getToolbarTranslation() {
-        return mToolbarTranslation;
+    public int getCurrentToolbarHeight() {
+        if ((mToolbarChromeProxy != null) && mToolbarChromeProxy.isToolbarChromeVisible()) {
+            return mMaxToolbarHeight;
+        }
+        return 0;
     }
 
     /**
      * If true, scroll changes will not affect translation.
      */
     public boolean isPinned() {
         return !pinFlags.isEmpty();
     }
 
     public boolean isPinnedBy(PinReason reason) {
         return pinFlags.contains(reason);
     }
 
     public void setPinned(boolean pinned, PinReason reason) {
+        if ((mCompositor != null) && (pinned != pinFlags.contains(reason))) {
+             mCompositor.setPinned(pinned, reason.mValue);
+        }
+
         if (pinned) {
             pinFlags.add(reason);
         } else {
             pinFlags.remove(reason);
         }
     }
 
     public void showToolbar(boolean immediately) {
-        animateToolbar(true, immediately);
+        if (mCompositor != null) {
+            mCompositor.sendToolbarAnimatorMessage(immediately ?
+                LayerView.REQUEST_SHOW_TOOLBAR_IMMEDIATELY : LayerView.REQUEST_SHOW_TOOLBAR_ANIMATED);
+        }
     }
 
     public void hideToolbar(boolean immediately) {
-        animateToolbar(false, immediately);
-    }
-
-    public void setScrollingRootContent(boolean isRootContent) {
-        mScrollingRootContent = isRootContent;
-    }
-
-    private void animateToolbar(final boolean showToolbar, boolean immediately) {
-        ThreadUtils.assertOnUiThread();
-
-        if (mAnimationTask != null) {
-            mTarget.getView().removeRenderTask(mAnimationTask);
-            mAnimationTask = null;
-        }
-
-        float desiredTranslation = (showToolbar ? 0 : mMaxTranslation);
-        Log.v(LOGTAG, "Requested " + (immediately ? "immediate " : "") + "toolbar animation to translation " + desiredTranslation);
-        if (FloatUtils.fuzzyEquals(mToolbarTranslation, desiredTranslation)) {
-            // If we're already pretty much in the desired position, don't bother
-            // with a full animation; do an immediate jump
-            immediately = true;
-            Log.v(LOGTAG, "Changing animation to immediate jump");
-        }
-
-        if (showToolbar && immediately) {
-            // Special case for showing the toolbar immediately: some of the call
-            // sites expect this to happen synchronously, so let's do that. This
-            // is safe because if we are showing the toolbar from a hidden state
-            // there is no chance of showing garbage
-            mToolbarTranslation = desiredTranslation;
-            fireListeners();
-            // And then proceed with the normal flow (some of which will be
-            // a no-op now)...
-        }
-
-        if (!showToolbar) {
-            // If we are hiding the toolbar, we need to move the LayerView first,
-            // so that we don't end up showing garbage under the toolbar when
-            // it is hidden. In the case that we are showing the toolbar, we
-            // move the LayerView after the toolbar is shown - the
-            // DynamicToolbarAnimationTask calls that upon completion.
-            shiftLayerView(desiredTranslation);
-        }
-
-        mAnimationTask = new DynamicToolbarAnimationTask(desiredTranslation, immediately, showToolbar);
-        mTarget.getView().postRenderTask(mAnimationTask);
-    }
-
-    private synchronized void shiftLayerView(float desiredTranslation) {
-        float layerViewTranslationNeeded = desiredTranslation - mLayerViewTranslation;
-        mLayerViewTranslation = desiredTranslation;
-        synchronized (mTarget.getLock()) {
-            if (layerViewTranslationNeeded == 0 && isResizing()) {
-                // We're already in the middle of a snap, so this new call is
-                // redundant as it's snapping to the same place. Ignore it.
-                return;
-            }
-            mHeightDuringResize = new Integer(mTarget.getViewportMetrics().viewportRectHeight);
-            mSnapRequired = mTarget.setViewportSize(
-                mTarget.getView().getWidth(),
-                mTarget.getView().getHeight() - Math.round(mMaxTranslation - mLayerViewTranslation),
-                new PointF(0, -layerViewTranslationNeeded));
-            if (!mSnapRequired) {
-                mHeightDuringResize = null;
-                ThreadUtils.postToUiThread(new Runnable() {
-                    // Post to run it outside of the synchronize blocks. The
-                    // delay shouldn't hurt.
-                    @Override
-                    public void run() {
-                        fireListeners();
-                    }
-                });
-            }
-            // Request a composite, which will trigger the snap.
-            mTarget.getView().requestRender();
+        if (mCompositor != null) {
+            mCompositor.sendToolbarAnimatorMessage(immediately ?
+                LayerView.REQUEST_HIDE_TOOLBAR_IMMEDIATELY : LayerView.REQUEST_HIDE_TOOLBAR_ANIMATED);
         }
     }
 
-    IntSize getViewportSize() {
+    /* package-private */ IntSize getViewportSize() {
         ThreadUtils.assertOnUiThread();
 
         int viewWidth = mTarget.getView().getWidth();
         int viewHeight = mTarget.getView().getHeight();
-        float toolbarTranslation = mToolbarTranslation;
-        if (mAnimationTask != null) {
-            // If we have an animation going, mToolbarTranslation may be in flux
-            // and we should use the final value it will settle on.
-            toolbarTranslation = mAnimationTask.getFinalToolbarTranslation();
-        }
-        int viewHeightVisible = viewHeight - Math.round(mMaxTranslation - toolbarTranslation);
-        return new IntSize(viewWidth, viewHeightVisible);
-    }
-
-    boolean isResizing() {
-        return mHeightDuringResize != null;
-    }
-
-    private final Runnable mSnapRunnable = new Runnable() {
-        private int mFrame = 0;
-
-        @Override
-        public final void run() {
-            // It takes 2 frames for the view translation to take effect, at
-            // least on a Nexus 4 device running Android 4.2.2. So we wait for
-            // two frames before doing the notifyAll(), otherwise we get a
-            // short user-visible glitch.
-            // TODO: find a better way to do this, if possible.
-            if (mFrame == 1) {
-                synchronized (this) {
-                    this.notifyAll();
-                }
-                mFrame = 0;
-                return;
-            }
-
-            if (mFrame == 0) {
-                fireListeners();
-            }
-
-            ViewCompat.postOnAnimation(mTarget.getView(), this);
-            mFrame++;
-        }
-    };
-
-    void scrollChangeResizeCompleted() {
-        synchronized (mTarget.getLock()) {
-            Log.v(LOGTAG, "Scrollchange resize completed");
-            mHeightDuringResize = null;
-        }
-    }
-
-    /**
-     * "Shrinks" the absolute value of aValue by moving it closer to zero by
-     * aShrinkAmount, but prevents it from crossing over zero. If aShrinkAmount
-     * is negative it is ignored.
-     * @return The shrunken value.
-     */
-    private static float shrinkAbs(float aValue, float aShrinkAmount) {
-        if (aShrinkAmount <= 0) {
-            return aValue;
-        }
-        float shrinkBy = Math.min(Math.abs(aValue), aShrinkAmount);
-        return (aValue < 0 ? aValue + shrinkBy : aValue - shrinkBy);
-    }
-
-    /**
-     * This function takes in a scroll amount and decides how much of that
-     * should be used up to translate things on screen because of the dynamic
-     * toolbar behaviour. It returns the maximum amount that could be used
-     * for translation purposes; the rest must be used for scrolling.
-     */
-    private float decideTranslation(float aDelta,
-                                    ImmutableViewportMetrics aMetrics,
-                                    float aTouchTravelDistance) {
-
-        float exposeThreshold = aMetrics.getHeight() * SCROLL_TOOLBAR_THRESHOLD;
-        float translation = aDelta;
-
-        if (translation < 0) { // finger moving upwards
-            translation = shrinkAbs(translation, aMetrics.getOverscroll().top);
-
-            // If the toolbar is in a state between fully hidden and fully shown
-            // (i.e. the user is actively translating it), then we want the
-            // translation to take effect right away. Or if the user has moved
-            // their finger past the required threshold (and is not trying to
-            // scroll past the bottom of the page) then also we want the touch
-            // to cause translation. If the toolbar is fully visible, we only
-            // want the toolbar to hide if the user is scrolling the root content.
-            boolean inBetween = (mToolbarTranslation != 0 && mToolbarTranslation != mMaxTranslation);
-            boolean reachedThreshold = -aTouchTravelDistance >= exposeThreshold;
-            boolean atBottomOfPage = aMetrics.viewportRectBottom() >= aMetrics.pageRectBottom;
-            if (inBetween || (mScrollingRootContent && reachedThreshold && !atBottomOfPage)) {
-                return translation;
-            }
-        } else {    // finger moving downwards
-            translation = shrinkAbs(translation, aMetrics.getOverscroll().bottom);
-
-            // Ditto above comment, but in this case if they reached the top and
-            // the toolbar is not shown, then we do want to allow translation
-            // right away.
-            boolean inBetween = (mToolbarTranslation != 0 && mToolbarTranslation != mMaxTranslation);
-            boolean reachedThreshold = aTouchTravelDistance >= exposeThreshold;
-            boolean atTopOfPage = aMetrics.viewportRectTop <= aMetrics.pageRectTop;
-            boolean isToolbarTranslated = (mToolbarTranslation != 0);
-            if (inBetween || reachedThreshold || (atTopOfPage && isToolbarTranslated)) {
-                return translation;
-            }
+        if ((mToolbarChromeProxy != null) && mToolbarChromeProxy.isToolbarChromeVisible()) {
+          viewHeight -= mMaxToolbarHeight;
         }
-
-        return 0;
-    }
-
-    // Timestamp of the start of the touch event used to calculate toolbar velocity
-    private long mLastEventTime;
-    // Current velocity of the toolbar. Used to populate the velocity queue in C++APZ.
-    private float mVelocity;
-
-    boolean onInterceptTouchEvent(MotionEvent event) {
-        if (isPinned()) {
-            return false;
-        }
-
-        // Animations should never co-exist with the user touching the screen.
-        if (mAnimationTask != null) {
-            mTarget.getView().removeRenderTask(mAnimationTask);
-            mAnimationTask = null;
-        }
-
-        // we only care about single-finger drags here; any other kind of event
-        // should reset and cause us to start over.
-        if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE ||
-            event.getActionMasked() != MotionEvent.ACTION_MOVE ||
-            event.getPointerCount() != 1)
-        {
-            if (mTouchStart != null) {
-                Log.v(LOGTAG, "Resetting touch sequence due to non-move");
-                mTouchStart = null;
-                mVelocity = 0.0f;
-            }
-
-            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
-                // We need to do this even if the toolbar is already fully
-                // visible or fully hidden, because this is what triggers the
-                // viewport resize in content and updates the viewport metrics.
-                boolean toolbarMostlyVisible = mToolbarTranslation < (mMaxTranslation / 2);
-                Log.v(LOGTAG, "All fingers lifted, completing " + (toolbarMostlyVisible ? "show" : "hide"));
-                animateToolbar(toolbarMostlyVisible, false);
-            }
-            return false;
-        }
-
-        if (mTouchStart != null) {
-            float prevDir = mLastTouch - mTouchStart.y;
-            float newDir = event.getRawY() - mLastTouch;
-            if (prevDir != 0 && newDir != 0 && ((prevDir < 0) != (newDir < 0))) {
-                // If the direction of movement changed, reset the travel
-                // distance properties.
-                mTouchStart = null;
-                mVelocity = 0.0f;
-            }
-        }
-
-        if (mTouchStart == null) {
-            mTouchStart = new PointF(event.getRawX(), event.getRawY());
-            mLastTouch = event.getRawY();
-            mLastEventTime = event.getEventTime();
-            return false;
-        }
-
-        float deltaY = event.getRawY() - mLastTouch;
-        long currentTime = event.getEventTime();
-        float deltaTime = (float)(currentTime - mLastEventTime);
-        mLastEventTime = currentTime;
-        if (deltaTime > 0.0f) {
-            mVelocity = -deltaY / deltaTime;
-        } else {
-            mVelocity = 0.0f;
-        }
-        mLastTouch = event.getRawY();
-        float travelDistance = event.getRawY() - mTouchStart.y;
-
-        ImmutableViewportMetrics metrics = mTarget.getViewportMetrics();
-
-        if (metrics.getPageHeight() <= mTarget.getView().getHeight() &&
-            mToolbarTranslation == 0) {
-            // If the page is short and the toolbar is already visible, don't
-            // allow translating it out of view.
-            return false;
-        }
-
-        float translation = decideTranslation(deltaY, metrics, travelDistance);
-
-        float oldToolbarTranslation = mToolbarTranslation;
-        float oldLayerViewTranslation = mLayerViewTranslation;
-        mToolbarTranslation = FloatUtils.clamp(mToolbarTranslation - translation, 0, mMaxTranslation);
-        mLayerViewTranslation = FloatUtils.clamp(mLayerViewTranslation - translation, 0, mMaxTranslation);
-
-        if (oldToolbarTranslation == mToolbarTranslation &&
-            oldLayerViewTranslation == mLayerViewTranslation) {
-            return false;
-        }
-
-        if (mToolbarTranslation == mMaxTranslation) {
-            Log.v(LOGTAG, "Toolbar at maximum translation, calling shiftLayerView(" + mMaxTranslation + ")");
-            shiftLayerView(mMaxTranslation);
-        } else if (mToolbarTranslation == 0) {
-            Log.v(LOGTAG, "Toolbar at minimum translation, calling shiftLayerView(0)");
-            shiftLayerView(0);
-        }
-
-        fireListeners();
-        mTarget.getView().requestRender();
-        return true;
-    }
-
-    // Get the current velocity of the toolbar.
-    float getVelocity() {
-        return mVelocity;
+        return new IntSize(viewWidth, viewHeight);
     }
 
     public PointF getVisibleEndOfLayerView() {
         return new PointF(mTarget.getView().getWidth(),
-            mTarget.getView().getHeight() - mMaxTranslation + mLayerViewTranslation);
-    }
-
-    private float bottomOfCssViewport(ImmutableViewportMetrics aMetrics) {
-        return (isResizing() ? mHeightDuringResize : aMetrics.getHeight())
-                + mMaxTranslation - mLayerViewTranslation;
-    }
-
-    private synchronized boolean getAndClearSnapRequired() {
-        boolean snapRequired = mSnapRequired;
-        mSnapRequired = false;
-        return snapRequired;
+            mTarget.getView().getHeight());
     }
 
-    void populateViewTransform(ViewTransform aTransform, ImmutableViewportMetrics aMetrics) {
-        if (getAndClearSnapRequired()) {
-            synchronized (mSnapRunnable) {
-                ViewCompat.postOnAnimation(mTarget.getView(), mSnapRunnable);
-                try {
-                    // hold the in-progress composite until the views have been
-                    // translated because otherwise there is a visible glitch.
-                    // don't hold for more than 100ms just in case.
-                    mSnapRunnable.wait(100);
-                } catch (InterruptedException ie) {
-                }
+    private void dumpStateToCompositor() {
+        if ((mCompositor != null) && mCompositorControllerOpen) {
+            mCompositor.setMaxToolbarHeight(mMaxToolbarHeight);
+            for (PinReason reason : pinFlags) {
+              mCompositor.setPinned(true, reason.mValue);
             }
         }
-
-        aTransform.x = aMetrics.viewportRectLeft;
-        aTransform.y = aMetrics.viewportRectTop;
-        aTransform.width = aMetrics.viewportRectWidth;
-        aTransform.height = aMetrics.viewportRectHeight;
-        aTransform.scale = aMetrics.zoomFactor;
+    }
 
-        aTransform.fixedLayerMarginTop = mLayerViewTranslation - mToolbarTranslation;
-        float bottomOfScreen = mTarget.getView().getHeight();
-        // We want to move a fixed item from "bottomOfCssViewport" to
-        // "bottomOfScreen". But also the bottom margin > 0 means that bottom
-        // fixed-pos items will move upwards.
-        aTransform.fixedLayerMarginBottom = bottomOfCssViewport(aMetrics) - bottomOfScreen;
-        //Log.v(LOGTAG, "ViewTransform is x=" + aTransform.x + " y=" + aTransform.y
-        //    + " z=" + aTransform.scale + " t=" + aTransform.fixedLayerMarginTop
-        //    + " b=" + aTransform.fixedLayerMarginBottom);
+    /* package-private */ void notifyCompositorCreated(LayerView.Compositor aCompositor) {
+        ThreadUtils.assertOnUiThread();
+        mCompositor = aCompositor;
+        dumpStateToCompositor();
     }
 
-    class DynamicToolbarAnimationTask extends RenderTask {
-        private final float mStartTranslation;
-        private final float mEndTranslation;
-        private final boolean mImmediate;
-        private final boolean mShiftLayerView;
-        private boolean mContinueAnimation;
-
-        public DynamicToolbarAnimationTask(float aTranslation, boolean aImmediate, boolean aShiftLayerView) {
-            super(false);
-            mContinueAnimation = true;
-            mStartTranslation = mToolbarTranslation;
-            mEndTranslation = aTranslation;
-            mImmediate = aImmediate;
-            mShiftLayerView = aShiftLayerView;
-        }
-
-        float getFinalToolbarTranslation() {
-            return mEndTranslation;
-        }
-
-        @Override
-        public boolean internalRun(long timeDelta, long currentFrameStartTime) {
-            if (!mContinueAnimation) {
-                return false;
-            }
+    /* package-private */ void notifyCompositorControllerOpen() {
+        mCompositorControllerOpen = true;
+        dumpStateToCompositor();
+    }
 
-            // Calculate the progress (between 0 and 1)
-            final float progress = mImmediate
-                ? 1.0f
-                : mInterpolator.getInterpolation(
-                    Math.min(1.0f, (System.nanoTime() - getStartTime())
-                                    / (float)ANIMATION_DURATION));
+    /* package-private */ void notifyCompositorDestroyed() {
+        mCompositor = null;
+    }
 
-            // This runs on the compositor thread, so we need to post the
-            // actual work to the UI thread.
-            ThreadUtils.assertNotOnUiThread();
 
-            ThreadUtils.postToUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    // Move the toolbar as per the animation
-                    mToolbarTranslation = FloatUtils.interpolate(mStartTranslation, mEndTranslation, progress);
-                    fireListeners();
-
-                    if (mShiftLayerView && progress >= 1.0f) {
-                        shiftLayerView(mEndTranslation);
-                    }
-                }
-            });
-
-            mTarget.getView().requestRender();
-            if (progress >= 1.0f) {
-                mContinueAnimation = false;
-            }
-            return mContinueAnimation;
+    /* package-private */ Bitmap getBitmapOfToolbarChrome() {
+        if (mToolbarChromeProxy != null) {
+            return mToolbarChromeProxy.getBitmapOfToolbarChrome();
         }
+        return null;
     }
 }