Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f0b6db7f authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Removing static launcher activity dependency from FirstFrameAnimationHelper

Static dependency does not work in the presence of multiple activities and
when the main activity is not Launcher (eg in fallback recents). Instead
creating FirstFrameAnimatorHelper on demand for individual animations.

Change-Id: I17bb69bbaaca92f0db994fb56fd784302c57d543
parent b6ecb173
Loading
Loading
Loading
Loading
+8 −10
Original line number Diff line number Diff line
@@ -1269,11 +1269,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl

            int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - taskIndex);
            if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < getPageCount()) {
                anim.play(ObjectAnimator.ofPropertyValuesHolder(getPageAt(otherAdjacentTaskIndex),
                        new PropertyListBuilder()
                anim.play(new PropertyListBuilder()
                        .translationX(mIsRtl ? -displacementX : displacementX)
                        .scale(1)
                                .build()));
                        .build(getPageAt(otherAdjacentTaskIndex)));
            }
        }
        return anim;
@@ -1282,11 +1281,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
    private Animator createAnimForChild(TaskView child, float[] toScaleAndTranslation) {
        AnimatorSet anim = new AnimatorSet();
        anim.play(ObjectAnimator.ofFloat(child, TaskView.ZOOM_SCALE, toScaleAndTranslation[0]));
        anim.play(ObjectAnimator.ofPropertyValuesHolder(child,
                        new PropertyListBuilder()
        anim.play(new PropertyListBuilder()
                .translationX(toScaleAndTranslation[1])
                .translationY(toScaleAndTranslation[2])
                                .build()));
                .build(child));
        return anim;
    }

+7 −13
Original line number Diff line number Diff line
@@ -3,8 +3,6 @@ package com.android.launcher3;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
@@ -39,6 +37,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O

    private final Launcher mLauncher;
    private final DragViewStateAnnouncer mStateAnnouncer;
    private final FirstFrameAnimatorHelper mFirstFrameAnimatorHelper;

    private final View[] mDragHandles = new View[HANDLE_COUNT];

@@ -101,6 +100,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
        mBackgroundPadding = getResources()
                .getDimensionPixelSize(R.dimen.resize_frame_background_padding);
        mTouchTargetWidth = 2 * mBackgroundPadding;
        mFirstFrameAnimatorHelper = new FirstFrameAnimatorHelper(this);
    }

    @Override
@@ -368,12 +368,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
        mDeltaX = 0;
        mDeltaY = 0;

        post(new Runnable() {
            @Override
            public void run() {
                snapToWidget(true);
            }
        });
        post(() -> snapToWidget(true));
    }

    /**
@@ -433,20 +428,19 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
            }
            requestLayout();
        } else {
            ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(lp, this,
            ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(lp,
                    PropertyValuesHolder.ofInt("width", lp.width, newWidth),
                    PropertyValuesHolder.ofInt("height", lp.height, newHeight),
                    PropertyValuesHolder.ofInt("x", lp.x, newX),
                    PropertyValuesHolder.ofInt("y", lp.y, newY));
            oa.addUpdateListener(a -> requestLayout());
            mFirstFrameAnimatorHelper.addTo(oa).addUpdateListener(a -> requestLayout());

            AnimatorSet set = new AnimatorSet();
            set.play(oa);
            for (int i = 0; i < HANDLE_COUNT; i++) {
                set.play(LauncherAnimUtils.ofPropertyValuesHolder(mDragHandles[i],
                        PropertyValuesHolder.ofFloat(ALPHA, 1f)));
                set.play(mFirstFrameAnimatorHelper.addTo(
                        ObjectAnimator.ofFloat(mDragHandles[i], ALPHA, 1f)));
            }

            set.setDuration(SNAP_DURATION);
            set.start();
        }
+10 −8
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.launcher3;

import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -1921,7 +1923,7 @@ public class CellLayout extends ViewGroup {
        public static final int MODE_PREVIEW = 1;

        float animationProgress = 0;
        Animator a;
        ValueAnimator a;

        public ReorderPreviewAnimation(View child, int mode, int cellX0, int cellY0, int cellX1,
                int cellY1, int spanX, int spanY) {
@@ -2039,14 +2041,14 @@ public class CellLayout extends ViewGroup {
            }

            setInitialAnimationValues(true);
            a = LauncherAnimUtils.ofPropertyValuesHolder(child,
                    new PropertyListBuilder()
            a = new PropertyListBuilder()
                    .scale(initScale)
                    .translationX(initDeltaX)
                    .translationY(initDeltaY)
                            .build())
                    .build(child)
                    .setDuration(REORDER_ANIMATION_DURATION);
            a.setInterpolator(new android.view.animation.DecelerateInterpolator(1.5f));
            mLauncher.getDragController().addFirstFrameAnimationHelper(a);
            a.setInterpolator(DEACCEL_1_5);
            a.start();
        }
    }
+88 −72
Original line number Diff line number Diff line
@@ -13,61 +13,74 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.launcher3;

import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;

import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;

import com.android.launcher3.util.Thunk;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewTreeObserver.OnDrawListener;

/*
 *  This is a helper class that listens to updates from the corresponding animation.
 *  For the first two frames, it adjusts the current play time of the animation to
 *  prevent jank at the beginning of the animation
 */
public class FirstFrameAnimatorHelper implements ValueAnimator.AnimatorUpdateListener {
public class FirstFrameAnimatorHelper implements OnDrawListener, OnAttachStateChangeListener {

    private static final String TAG = "FirstFrameAnimatorHlpr";
    private static final boolean DEBUG = false;
    private static final int MAX_DELAY = 1000;
    private final View mTarget;
    private long mStartFrame;
    private long mStartTime = -1;
    private boolean mHandlingOnAnimationUpdate;
    private boolean mAdjustedSecondFrameTime;

    private static ViewTreeObserver.OnDrawListener sGlobalDrawListener;
    @Thunk static long sGlobalFrameCounter;
    private static boolean sVisible;
    private View mRootView;
    private long mGlobalFrameCount;

    public FirstFrameAnimatorHelper(ValueAnimator animator, View target) {
        mTarget = target;
        animator.addUpdateListener(this);
    public FirstFrameAnimatorHelper(View target) {
        target.addOnAttachStateChangeListener(this);
        if (target.isAttachedToWindow()) {
            onViewAttachedToWindow(target);
        }
    }

    public static void setIsVisible(boolean visible) {
        sVisible = visible;
    public <T extends ValueAnimator> T addTo(T anim) {
        anim.addUpdateListener(new MyListener());
        return anim;
    }

    @Override
    public void onDraw() {
        mGlobalFrameCount ++;
    }

    public static void initializeDrawListener(View view) {
        if (sGlobalDrawListener != null) {
            view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener);
    @Override
    public void onViewAttachedToWindow(View view) {
        mRootView = view.getRootView();
        mRootView.getViewTreeObserver().addOnDrawListener(this);
    }

        sGlobalDrawListener = () -> sGlobalFrameCounter++;
        view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener);
        sVisible = true;
    @Override
    public void onViewDetachedFromWindow(View view) {
        if (mRootView != null) {
            mRootView.getViewTreeObserver().removeOnDrawListener(this);
            mRootView = null;
        }
    }

    private class MyListener implements AnimatorUpdateListener {

        private long mStartFrame;
        private long mStartTime = -1;
        private boolean mHandlingOnAnimationUpdate;
        private boolean mAdjustedSecondFrameTime;

        @Override
        public void onAnimationUpdate(final ValueAnimator animation) {
            final long currentTime = System.currentTimeMillis();
            if (mStartTime == -1) {
            mStartFrame = sGlobalFrameCounter;
                mStartFrame = mGlobalFrameCount;
                mStartTime = currentTime;
            }

@@ -75,20 +88,22 @@ public class FirstFrameAnimatorHelper implements ValueAnimator.AnimatorUpdateLis
            boolean isFinalFrame = Float.compare(1f, animation.getAnimatedFraction()) == 0;

            if (!mHandlingOnAnimationUpdate &&
            sVisible &&
                    mRootView != null &&
                    mRootView.getWindowVisibility() == View.VISIBLE &&
                    // If the current play time exceeds the duration, or the animated fraction is 1,
            // the animation will get finished, even if we call setCurrentPlayTime -- therefore
            // don't adjust the animation in that case
                    // the animation will get finished, even if we call setCurrentPlayTime --
                    // therefore don't adjust the animation in that case
                    currentPlayTime < animation.getDuration() && !isFinalFrame) {
                mHandlingOnAnimationUpdate = true;
            long frameNum = sGlobalFrameCounter - mStartFrame;
                long frameNum = mGlobalFrameCount - mStartFrame;

                // If we haven't drawn our first frame, reset the time to t = 0
                // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
                // are no longer in the foreground and no frames are being rendered ever)
                if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY && currentPlayTime > 0) {
                    // The first frame on animations doesn't always trigger an invalidate...
                    // force an invalidate here to make sure the animation continues to advance
                mTarget.getRootView().invalidate();
                    mRootView.invalidate();
                    animation.setCurrentPlayTime(0);
                    // For the second frame, if the first frame took more than 16ms,
                    // adjust the start time and pretend it took only 16ms anyway. This
@@ -101,7 +116,7 @@ public class FirstFrameAnimatorHelper implements ValueAnimator.AnimatorUpdateLis
                    mAdjustedSecondFrameTime = true;
                } else {
                    if (frameNum > 1) {
                    mTarget.post(() -> animation.removeUpdateListener(this));
                        mRootView.post(() -> animation.removeUpdateListener(this));
                    }
                    if (DEBUG) print(animation);
                }
@@ -113,8 +128,9 @@ public class FirstFrameAnimatorHelper implements ValueAnimator.AnimatorUpdateLis

        public void print(ValueAnimator animation) {
            float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
        Log.d(TAG, sGlobalFrameCounter +
              "(" + (sGlobalFrameCounter - mStartFrame) + ") " + mTarget + " dirty? " +
              mTarget.isDirty() + " " + flatFraction + " " + this + " " + animation);
            Log.d(TAG, mGlobalFrameCount +
                    "(" + (mGlobalFrameCount - mStartFrame) + ") " + mRootView + " dirty? " +
                    mRootView.isDirty() + " " + flatFraction + " " + this + " " + animation);
        }
    }
}
+26 −38
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityOptions;
@@ -79,6 +78,7 @@ import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
@@ -740,8 +740,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
    @Override
    protected void onStop() {
        super.onStop();
        FirstFrameAnimatorHelper.setIsVisible(false);

        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.onStop();
        }
@@ -762,8 +760,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
    @Override
    protected void onStart() {
        super.onStart();
        FirstFrameAnimatorHelper.setIsVisible(true);

        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.onStart();
        }
@@ -1131,7 +1127,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
    public void onAttachedToWindow() {
        super.onAttachedToWindow();

        FirstFrameAnimatorHelper.initializeDrawListener(getWindow().getDecorView());
        if (mLauncherCallbacks != null) {
            mLauncherCallbacks.onAttachedToWindow();
        }
@@ -1839,7 +1834,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
    @Override
    public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
        // Get the list of added items and intersect them with the set of items here
        final AnimatorSet anim = new AnimatorSet();
        final Collection<Animator> bounceAnims = new ArrayList<>();
        final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
        Workspace workspace = mWorkspace;
@@ -1911,17 +1905,15 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
            }
        }

        if (animateIcons) {
        // Animate to the correct page
            if (newItemsScreenId > -1) {
        if (animateIcons && newItemsScreenId > -1) {
            AnimatorSet anim = new AnimatorSet();
            anim.playTogether(bounceAnims);

            long currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
            final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
                final Runnable startBounceAnimRunnable = new Runnable() {
                    public void run() {
                        anim.playTogether(bounceAnims);
                        anim.start();
                    }
                };
            final Runnable startBounceAnimRunnable = anim::start;

            if (newItemsScreenId != currentScreenId) {
                // We post the animation slightly delayed to prevent slowdowns
                // when we are loading right after we return to launcher.
@@ -1940,7 +1932,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
                mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
            }
        }
        }
        workspace.requestLayout();
    }

@@ -2161,11 +2152,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
    }

    private ValueAnimator createNewAppBounceAnimation(View v, int i) {
        ValueAnimator bounceAnim = LauncherAnimUtils.ofPropertyValuesHolder(v,
                PropertyValuesHolder.ofFloat(View.ALPHA, 1f),
                PropertyValuesHolder.ofFloat(View.SCALE_X, 1f),
                PropertyValuesHolder.ofFloat(View.SCALE_Y, 1f));
        bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
        ValueAnimator bounceAnim = new PropertyListBuilder().alpha(1).scale(1).build(v)
                .setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
        bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY);
        bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION));
        return bounceAnim;
Loading