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

Commit 706ff85f authored by Vinit Nayak's avatar Vinit Nayak
Browse files

Prevent setting task thumbnail during swipe to overview

Previously we were setting the incorrect thumbnail when
swiping to overview, then taking a task screenshot right
when the animation ends and replacing the first thumbnail.
This sometimes caused a flicker of the old thumbnail, now
we avoid setting the thumbnail at all for the taskview that
is being swiped up.

Another edge case handled here is when switching nav modes
and then immediately entering overview, Recents receives an
onConfigChange for changing task icon size. That would cause
all taskviews to null out both their existing icon and
thumbnail, now only the icon gets nulled out.
Existing issue where switching to 3 button nav and then
entering overview shows blank icon, doesn't register for
receiving the updated task snapshot fast enough.

Fixes: 179307265
Test: Ask assistant for weather, swipe to overview
Ask assistant for time, swipe to overview, no flicker

Switch nav modes to gesture, swipe to overview.
There's a flicker for config change, but thumbnail is correct

Change-Id: I300b29f999f6d6876f82bc0189b44f4c10ae33fe
parent dd1026b0
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
import static com.android.quickstep.views.SplitPlaceholderView.ALPHA_FLOAT;
import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;

import android.annotation.TargetApi;
import android.os.Build;
@@ -73,7 +74,7 @@ public final class RecentsViewStateController extends

        if (toState.overviewUi) {
            // While animating into recents, update the visible task data as needed
            builder.addOnFrameCallback(mRecentsView::loadVisibleTaskData);
            builder.addOnFrameCallback(() -> mRecentsView.loadVisibleTaskData(FLAG_UPDATE_ALL));
            mRecentsView.updateEmptyMessage();
        } else {
            builder.addListener(
+2 −1
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import static com.android.quickstep.views.TaskView.FLAG_UPDATE_ALL;

import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
@@ -70,7 +71,7 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState
            return;
        }
        // While animating into recents, update the visible task data as needed
        setter.addOnFrameCallback(mRecentsView::loadVisibleTaskData);
        setter.addOnFrameCallback(() -> mRecentsView.loadVisibleTaskData(FLAG_UPDATE_ALL));
        mRecentsView.updateEmptyMessage();

        setProperties(toState, config, setter);
+24 −12
Original line number Diff line number Diff line
@@ -315,6 +315,10 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
    private final ClearAllButton mClearAllButton;
    private final Rect mClearAllButtonDeadZoneRect = new Rect();
    private final Rect mTaskViewDeadZoneRect = new Rect();
    /**
     * Reflects if Recents is currently in the middle of a gesture
     */
    private boolean mGestureActive;

    private final ScrollState mScrollState = new ScrollState();
    // Keeps track of the previously known visible tasks for purposes of loading/unloading task data
@@ -624,8 +628,8 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
            return;
        }
        mModel.getIconCache().clear();
        unloadVisibleTaskData();
        loadVisibleTaskData();
        unloadVisibleTaskData(TaskView.FLAG_UPDATE_ICON);
        loadVisibleTaskData(TaskView.FLAG_UPDATE_ICON);
    }

    public void init(OverviewActionsView actionsView, SplitPlaceholderView splitPlaceholderView) {
@@ -908,7 +912,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
        }

        // Unload existing visible task data
        unloadVisibleTaskData();
        unloadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);

        TaskView ignoreResetTaskView =
                mIgnoreResetTaskId == -1 ? null : getTaskView(mIgnoreResetTaskId);
@@ -1031,7 +1035,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView

        updateCurveProperties();
        // Update the set of visible task's data
        loadVisibleTaskData();
        loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
        setTaskModalness(0);
    }

@@ -1147,7 +1151,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
            }

            // After scrolling, update the visible task's data
            loadVisibleTaskData();
            loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
        }

        // Update the high res thumbnail loader state
@@ -1210,7 +1214,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
     * Iterates through all the tasks, and loads the associated task data for newly visible tasks,
     * and unloads the associated task data for tasks that are no longer visible.
     */
    public void loadVisibleTaskData() {
    public void loadVisibleTaskData(@TaskView.TaskDataChanges int dataChanges) {
        if (!mOverviewStateEnabled || mTaskListChangeId == -1) {
            // Skip loading visible task data if we've already left the overview state, or if the
            // task list hasn't been loaded yet (the task views will not reflect the task list)
@@ -1252,12 +1256,18 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
                    continue;
                }
                if (!mHasVisibleTaskData.get(task.key.id)) {
                    taskView.onTaskListVisibilityChanged(true /* visible */);
                    // Ignore thumbnail update if it's current running task during the gesture
                    // We snapshot at end of gesture, it will update then
                    int changes = dataChanges;
                    if (taskView == getRunningTaskView() && mGestureActive) {
                        changes &= ~TaskView.FLAG_UPDATE_THUMBNAIL;
                    }
                    taskView.onTaskListVisibilityChanged(true /* visible */, changes);
                }
                mHasVisibleTaskData.put(task.key.id, visible);
            } else {
                if (mHasVisibleTaskData.get(task.key.id)) {
                    taskView.onTaskListVisibilityChanged(false /* visible */);
                    taskView.onTaskListVisibilityChanged(false /* visible */, dataChanges);
                }
                mHasVisibleTaskData.delete(task.key.id);
            }
@@ -1267,12 +1277,12 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
    /**
     * Unloads any associated data from the currently visible tasks
     */
    private void unloadVisibleTaskData() {
    private void unloadVisibleTaskData(@TaskView.TaskDataChanges int dataChanges) {
        for (int i = 0; i < mHasVisibleTaskData.size(); i++) {
            if (mHasVisibleTaskData.valueAt(i)) {
                TaskView taskView = getTaskView(mHasVisibleTaskData.keyAt(i));
                if (taskView != null) {
                    taskView.onTaskListVisibilityChanged(false /* visible */);
                    taskView.onTaskListVisibilityChanged(false /* visible */, dataChanges);
                }
            }
        }
@@ -1310,7 +1320,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
        mRecentsAnimationController = null;
        mLiveTileParams.setTargetSet(null);

        unloadVisibleTaskData();
        unloadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
        setCurrentPage(0);
        mDwbToastShown = false;
        mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
@@ -1358,6 +1368,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
     * Called when a gesture from an app is starting.
     */
    public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) {
        mGestureActive = true;
        // This needs to be called before the other states are set since it can create the task view
        if (mOrientationState.setGestureActive(true)) {
            updateOrientationHandler();
@@ -1428,6 +1439,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
     * Called when a gesture from an app has finished, and the animation to the target has ended.
     */
    public void onGestureAnimationEnd() {
        mGestureActive = false;
        if (mOrientationState.setGestureActive(false)) {
            updateOrientationHandler();
        }
@@ -2733,7 +2745,7 @@ public abstract class RecentsView<T extends StatefulActivity> extends PagedView
    @Override
    protected void notifyPageSwitchListener(int prevPage) {
        super.notifyPageSwitchListener(prevPage);
        loadVisibleTaskData();
        loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
        updateEnabledOverlays();
    }

+56 −12
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;

import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -67,6 +69,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.Toast;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;

import com.android.launcher3.DeviceProfile;
@@ -106,6 +109,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.QuickStepContract;

import java.lang.annotation.Retention;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
@@ -117,6 +121,19 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {

    private static final String TAG = TaskView.class.getSimpleName();

    public static final int FLAG_UPDATE_ICON = 1;
    public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;

    public static final int FLAG_UPDATE_ALL = FLAG_UPDATE_ICON | FLAG_UPDATE_THUMBNAIL;

    /**
     * Used in conjunction with {@link #onTaskListVisibilityChanged(boolean, int)}, providing more
     * granularity on which components of this task require an update
     */
    @Retention(SOURCE)
    @IntDef({FLAG_UPDATE_ALL, FLAG_UPDATE_ICON, FLAG_UPDATE_THUMBNAIL})
    public @interface TaskDataChanges {}

    /**
     * The alpha of a black scrim on a page in the carousel as it leaves the screen.
     * In the resting position of the carousel, the adjacent pages have about half this scrim.
@@ -557,7 +574,19 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
        }
    }

    /**
     * See {@link TaskDataChanges}
     * @param visible If this task view will be visible to the user in overview or hidden
     */
    public void onTaskListVisibilityChanged(boolean visible) {
        onTaskListVisibilityChanged(visible, FLAG_UPDATE_ALL);
    }

    /**
     * See {@link TaskDataChanges}
     * @param visible If this task view will be visible to the user in overview or hidden
     */
    public void onTaskListVisibilityChanged(boolean visible, @TaskDataChanges int changes) {
        if (mTask == null) {
            return;
        }
@@ -568,20 +597,35 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
            RecentsModel model = RecentsModel.INSTANCE.get(getContext());
            TaskThumbnailCache thumbnailCache = model.getThumbnailCache();
            TaskIconCache iconCache = model.getIconCache();

            if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
                mThumbnailLoadRequest = thumbnailCache.updateThumbnailInBackground(
                    mTask, thumbnail -> mSnapshotView.setThumbnail(mTask, thumbnail));
                        mTask, thumbnail -> {
                            mSnapshotView.setThumbnail(mTask, thumbnail);
                        });
            }
            if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
                mIconLoadRequest = iconCache.updateIconInBackground(mTask,
                        (task) -> {
                            setIcon(task.icon);
                            mDigitalWellBeingToast.initialize(mTask);
                        });
            }
        } else {
            if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
                mSnapshotView.setThumbnail(null, null);
            setIcon(null);
                // Reset the task thumbnail reference as well (it will be fetched from the cache or
                // reloaded next time we need it)
                mTask.thumbnail = null;
            }
            if (needsUpdate(changes, FLAG_UPDATE_ICON)) {
                setIcon(null);
            }
        }
    }

    private boolean needsUpdate(@TaskDataChanges int dataChange, @TaskDataChanges int flag) {
        return (dataChange & flag) == flag;
    }

    private void cancelPendingLoadTasks() {