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

Commit ed0e2b44 authored by Winson Chung's avatar Winson Chung
Browse files

Properly defer entrance animations until after the stack is reloaded.

- Change the enter animation animated event to a normal event (no
  animations were being choreographed on the event animation trigger
  anyways)
- Remove the code in RecentsActivity, which poorly tried to schedule
  the animation after the first layout.  Instead, properly defer the
  start animation until both the first layout _after stack reload_
  and enter animation callback happens (regardless of which one comes
  first).

Bug: 38391395
Test: Launch Chrome, dock, and ensure there are tasks visible
Change-Id: I4c2823fe25adbd3c200a0f786c478155541ccf26
parent a239ed1c
Loading
Loading
Loading
Loading
+1 −16
Original line number Diff line number Diff line
@@ -114,7 +114,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
    private boolean mFinishedOnStartup;
    private boolean mIgnoreAltTabRelease;
    private boolean mIsVisible;
    private boolean mReceivedNewIntent;

    // Top level views
    private RecentsView mRecentsView;
@@ -128,9 +127,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
    private int mFocusTimerDuration;
    private DozeTrigger mIterateTrigger;
    private final UserInteractionEvent mUserInteractionEvent = new UserInteractionEvent();
    private final Runnable mSendEnterWindowAnimationCompleteRunnable = () -> {
        EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
    };

    /**
     * A common Runnable to finish Recents by launching Home with an animation depending on the
@@ -390,7 +386,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        mReceivedNewIntent = true;

        // Reload the stack view
        reloadStackView();
@@ -469,16 +464,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
    @Override
    public void onEnterAnimationComplete() {
        super.onEnterAnimationComplete();

        // Workaround for b/28705801, on first docking, we may receive the enter animation callback
        // before the first layout, so in such cases, send the event on the next frame after all
        // the views are laid out and attached (and registered to the EventBus).
        mHandler.removeCallbacks(mSendEnterWindowAnimationCompleteRunnable);
        if (!mReceivedNewIntent) {
            mHandler.post(mSendEnterWindowAnimationCompleteRunnable);
        } else {
            mSendEnterWindowAnimationCompleteRunnable.run();
        }
        EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
    }

    @Override
@@ -516,7 +502,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD

        // Notify that recents is now hidden
        mIsVisible = false;
        mReceivedNewIntent = false;
        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
        MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
        Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(false);
+0 −26
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.recents.events.activity;

import com.android.systemui.recents.events.EventBus;

/**
 * This is sent when the in-app animations into Recents completes.
 */
public class EnterRecentsTaskStackAnimationCompletedEvent extends EventBus.AnimatedEvent {
    // Simple event
}
+1 −1
Original line number Diff line number Diff line
@@ -23,6 +23,6 @@ import com.android.systemui.recents.events.EventBus;
 * we can start in-app animations so that they don't conflict with the window transition into
 * Recents.
 */
public class EnterRecentsWindowAnimationCompletedEvent extends EventBus.AnimatedEvent {
public class EnterRecentsWindowAnimationCompletedEvent extends EventBus.Event {
    // Simple event
}
+59 −40
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.EnterRecentsTaskStackAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
@@ -97,6 +96,7 @@ import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
@@ -175,7 +175,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    @ViewDebug.ExportedProperty(category="recents")
    private boolean mTaskViewsClipDirty = true;
    @ViewDebug.ExportedProperty(category="recents")
    private boolean mAwaitingFirstLayout = true;
    private boolean mEnterAnimationComplete = false;
    @ViewDebug.ExportedProperty(category="recents")
    private boolean mStackReloaded = false;
    @ViewDebug.ExportedProperty(category="recents")
    private boolean mFinishedLayoutAfterStackReload = false;
    @ViewDebug.ExportedProperty(category="recents")
    private boolean mLaunchNextAfterFirstMeasure = false;
    @ViewDebug.ExportedProperty(category="recents")
@@ -184,8 +188,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    @ViewDebug.ExportedProperty(category="recents")
    private boolean mInMeasureLayout = false;
    @ViewDebug.ExportedProperty(category="recents")
    private boolean mEnterAnimationComplete = false;
    @ViewDebug.ExportedProperty(category="recents")
    boolean mTouchExplorationEnabled;
    @ViewDebug.ExportedProperty(category="recents")
    boolean mScreenPinningEnabled;
@@ -355,7 +357,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        // Reset the stack state
        readSystemFlags();
        mTaskViewsClipDirty = true;
        mEnterAnimationComplete = false;
        mUIDozeTrigger.stopDozing();
        if (isResumingFromVisible) {
            // Animate in the freeform workspace
@@ -370,7 +371,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal

        // Since we always animate to the same place in (the initial state), always reset the stack
        // to the initial state when resuming
        mAwaitingFirstLayout = true;
        mStackReloaded = true;
        mFinishedLayoutAfterStackReload = false;
        mLaunchNextAfterFirstMeasure = false;
        mInitialState = INITIAL_STATE_UPDATE_ALL;
        requestLayout();
@@ -1282,13 +1284,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        // TaskViews with the stack so that we can lay them out
        boolean resetToInitialState = (width != mLastWidth || height != mLastHeight)
                && mResetToInitialStateWhenResized;
        if (mAwaitingFirstLayout || mInitialState != INITIAL_STATE_UPDATE_NONE
        if (!mFinishedLayoutAfterStackReload || mInitialState != INITIAL_STATE_UPDATE_NONE
                || resetToInitialState) {
            if (mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY || resetToInitialState) {
                updateToInitialState();
                mResetToInitialStateWhenResized = false;
            }
            if (!mAwaitingFirstLayout) {
            if (mFinishedLayoutAfterStackReload) {
                mInitialState = INITIAL_STATE_UPDATE_NONE;
            }
        }
@@ -1361,10 +1363,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        relayoutTaskViews(AnimationProps.IMMEDIATE);
        clipTaskViews();

        if (mAwaitingFirstLayout || !mEnterAnimationComplete) {
            mAwaitingFirstLayout = false;
        if (!mFinishedLayoutAfterStackReload) {
            // Prepare the task enter animations (this can be called numerous times)
            mInitialState = INITIAL_STATE_UPDATE_NONE;
            onFirstLayout();

            if (mStackReloaded) {
                mFinishedLayoutAfterStackReload = true;
                tryStartEnterAnimation();
            }
        }
    }

@@ -1490,7 +1497,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        updateLayoutAlgorithm(true /* boundScroll */);

        // Animate all the tasks into place
        relayoutTaskViews(mAwaitingFirstLayout
        relayoutTaskViews(!mFinishedLayoutAfterStackReload
                ? AnimationProps.IMMEDIATE
                : new AnimationProps(DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN));
    }
@@ -1563,7 +1570,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal

    @Override
    public void onStackTasksUpdated(TaskStack stack) {
        if (mAwaitingFirstLayout) {
        if (!mFinishedLayoutAfterStackReload) {
            return;
        }

@@ -1805,7 +1812,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    }

    public final void onBusEvent(LaunchNextTaskRequestEvent event) {
        if (mAwaitingFirstLayout) {
        if (!mFinishedLayoutAfterStackReload) {
            mLaunchNextAfterFirstMeasure = true;
            return;
        }
@@ -2125,15 +2132,21 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal

    public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
        mEnterAnimationComplete = true;
        tryStartEnterAnimation();
    }

    private void tryStartEnterAnimation() {
        if (!mStackReloaded || !mFinishedLayoutAfterStackReload || !mEnterAnimationComplete) {
            return;
        }

        if (mStack.getTaskCount() > 0) {
            // Start the task enter animations
            mAnimationHelper.startEnterAnimation(event.getAnimationTrigger());
            ReferenceCountedTrigger trigger = new ReferenceCountedTrigger();
            mAnimationHelper.startEnterAnimation(trigger);

            // Add a runnable to the post animation ref counter to clear all the views
            event.addPostAnimationCallback(new Runnable() {
                @Override
                public void run() {
            trigger.addLastDecrementRunnable(() -> {
                // Start the dozer to trigger to trigger any UI that shows after a timeout
                if (!Recents.getSystemServices().hasFreeformWorkspaceSupport()) {
                    mUIDozeTrigger.startDozing();
@@ -2153,11 +2166,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                        focusedTaskView.requestAccessibilityFocus();
                    }
                }

                    EventBus.getDefault().send(new EnterRecentsTaskStackAnimationCompletedEvent());
                }
            });
        }

        // This flag is only used to choreograph the enter animation, so we can reset it here
        mStackReloaded = false;
    }

    public final void onBusEvent(UpdateFreeformTaskViewVisibilityEvent event) {
@@ -2235,15 +2248,21 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
    }

    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
        if (!event.visible && mTaskViewFocusFrame != null) {
        if (!event.visible) {
            if (mTaskViewFocusFrame != null) {
                mTaskViewFocusFrame.moveGridTaskViewFocus(null);
            }
        if (!event.visible) {

            List<TaskView> taskViews = new ArrayList<>(getTaskViews());
            for (int i = 0; i < taskViews.size(); i++) {
                mViewPool.returnViewToPool(taskViews.get(i));
            }
            clearPrefetchingTask();

            // We can not reset mEnterAnimationComplete in onReload() because when docking the top
            // task, we can receive the enter animation callback before onReload(), so reset it
            // here onces Recents is not visible
            mEnterAnimationComplete = false;
        }
    }

@@ -2377,7 +2396,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
        writer.print(" hasDefRelayout=");
        writer.print(mDeferredTaskViewLayoutAnimation != null ? "Y" : "N");
        writer.print(" clipDirty="); writer.print(mTaskViewsClipDirty ? "Y" : "N");
        writer.print(" awaitingFirstLayout="); writer.print(mAwaitingFirstLayout ? "Y" : "N");
        writer.print(" awaitingStackReload="); writer.print(mFinishedLayoutAfterStackReload ? "Y" : "N");
        writer.print(" initialState="); writer.print(mInitialState);
        writer.print(" inMeasureLayout="); writer.print(mInMeasureLayout ? "Y" : "N");
        writer.print(" enterAnimCompleted="); writer.print(mEnterAnimationComplete ? "Y" : "N");