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

Commit 681bab04 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Fallback recents activity fixes:

> Always deferring the start activity call
> Fixing quickscrub when start activtiy is deferred
> Preventing finish() call on the activity
> Fixing initTrack to work when the activity already exists

Bug: 75979063
Change-Id: Id6038c1f6c2680ec920222fb6a85c0ecc0172ed4
parent 38d2bf35
Loading
Loading
Loading
Loading
+18 −21
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
@@ -46,9 +47,6 @@ import com.android.quickstep.views.LauncherLayoutListener;
import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.AssistDataReceiver;
import com.android.systemui.shared.system.RecentsAnimationListener;

import java.util.function.BiPredicate;

@@ -85,9 +83,6 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {

    ActivityInitListener createActivityInitListener(BiPredicate<T, Boolean> onInitListener);

    void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
            final RecentsAnimationListener remoteAnimationListener);

    @Nullable
    T getCreatedActivity();

@@ -98,6 +93,12 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
    @UiThread
    boolean switchToRecentsIfVisible();

    /**
     * @return {@code true} if recents activity should be started immediately on touchDown,
     *         {@code false} if it should deferred until some threshold is crossed.
     */
    boolean deferStartingActivity(int downHitTarget);

    class LauncherActivityControllerHelper implements ActivityControlHelper<Launcher> {

        @Override
@@ -220,13 +221,6 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
            return new LauncherInitListener(onInitListener);
        }

        @Override
        public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
                final RecentsAnimationListener remoteAnimationListener) {
            ActivityManagerWrapper.getInstance().startRecentsActivity(
                    intent, assistDataReceiver, remoteAnimationListener, null, null);
        }

        @Nullable
        @Override
        public Launcher getCreatedActivity() {
@@ -262,6 +256,11 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
            }
            return false;
        }

        @Override
        public boolean deferStartingActivity(int downHitTarget) {
            return downHitTarget == HIT_TARGET_BACK;
        }
    }

    class FallbackActivityControllerHelper implements ActivityControlHelper<RecentsActivity> {
@@ -353,14 +352,6 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
            return new RecentsActivityTracker(onInitListener);
        }

        @Override
        public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
                final RecentsAnimationListener remoteAnimationListener) {
            // We can use the normal recents animation for swipe up
            ActivityManagerWrapper.getInstance().startRecentsActivity(
                    intent, assistDataReceiver, remoteAnimationListener, null, null);
        }

        @Nullable
        @Override
        public RecentsActivity getCreatedActivity() {
@@ -381,6 +372,12 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
        public boolean switchToRecentsIfVisible() {
            return false;
        }

        @Override
        public boolean deferStartingActivity(int downHitTarget) {
            // Always defer starting the activity when using fallback
            return true;
        }
    }

    interface LayoutListener {
+12 −8
Original line number Diff line number Diff line
@@ -21,8 +21,7 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;

import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_STEP_DRAG_SLOP_PX;

import android.annotation.TargetApi;
@@ -55,7 +54,6 @@ import com.android.systemui.shared.system.RecentsAnimationListener;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;

import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@@ -66,8 +64,6 @@ import java.util.concurrent.TimeUnit;
public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {

    private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
    private static final int[] DEFERRED_HIT_TARGETS = false
            ? new int[] {HIT_TARGET_BACK, HIT_TARGET_OVERVIEW} : new int[] {HIT_TARGET_BACK};

    private final RunningTaskInfo mRunningTask;
    private final RecentsModel mRecentsModel;
@@ -102,7 +98,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
        mActivityControlHelper = activityControl;
        mMainThreadExecutor = mainThreadExecutor;
        mBackgroundThreadChoreographer = backgroundThreadChoreographer;
        mIsDeferredDownTarget = Arrays.binarySearch(DEFERRED_HIT_TARGETS, downHitTarget) >= 0;
        mIsDeferredDownTarget = activityControl.deferStartingActivity(downHitTarget);
    }

    @Override
@@ -218,7 +214,8 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
        handler.initWhenReady();

        TraceHelper.beginSection("RecentsController");
        Runnable startActivity = () -> mActivityControlHelper.startRecentsFromSwipe(mHomeIntent,
        Runnable startActivity = () -> ActivityManagerWrapper.getInstance().startRecentsActivity(
                mHomeIntent,
                new AssistDataReceiver() {
                    @Override
                    public void onHandleAssistData(Bundle bundle) {
@@ -247,7 +244,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
                            handler.onRecentsAnimationCanceled();
                        }
                    }
                });
                }, null, null);

        if (Looper.myLooper() != Looper.getMainLooper()) {
            startActivity.run();
@@ -305,6 +302,13 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC

    @Override
    public void updateTouchTracking(int interactionType) {
        if (!mPassedInitialSlop && mIsDeferredDownTarget && mInteractionHandler == null) {
            // If we deferred starting the window animation on touch down, then
            // start tracking now
            startTouchTrackingForWindowAnimation(SystemClock.uptimeMillis());
            mPassedInitialSlop = true;
        }

        notifyGestureStarted();
        if (mInteractionHandler != null) {
            mInteractionHandler.updateInteractionType(interactionType);
+19 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.quickstep;

import android.app.ActivityOptions;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

@@ -102,9 +103,27 @@ public class RecentsActivity extends BaseDraggingActivity {
        UiFactory.onTrimMemory(this, level);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        RecentsActivityTracker.onRecentsActivityNewIntent(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        RecentsActivityTracker.onRecentsActivityDestroy(this);
    }

    @Override
    public void onBackPressed() {
        // TODO: Launch the task we came from
        startHome();
    }

    public void startHome() {
        startActivity(new Intent(Intent.ACTION_MAIN)
                .addCategory(Intent.CATEGORY_HOME)
                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
    }
}
+65 −29
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;

import com.android.launcher3.MainThreadExecutor;
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
import com.android.quickstep.util.RemoteAnimationProvider;

@@ -34,9 +35,8 @@ import java.util.function.BiPredicate;
@TargetApi(Build.VERSION_CODES.P)
public class RecentsActivityTracker implements ActivityInitListener {

    private static final Object LOCK = new Object();
    private static WeakReference<RecentsActivityTracker> sTracker = new WeakReference<>(null);
    private static WeakReference<RecentsActivity> sCurrentActivity = new WeakReference<>(null);
    private static final Scheduler sScheduler = new Scheduler();

    private final BiPredicate<RecentsActivity, Boolean> mOnInitListener;

@@ -46,50 +46,86 @@ public class RecentsActivityTracker implements ActivityInitListener {

    @Override
    public void register() {
        synchronized (LOCK) {
            sTracker = new WeakReference<>(this);
        }
        sScheduler.schedule(this);
    }

    @Override
    public void unregister() {
        synchronized (LOCK) {
            if (sTracker.get() == this) {
                sTracker.clear();
        sScheduler.clearReference(this);
    }

    private boolean init(RecentsActivity activity, boolean visible) {
        return mOnInitListener.test(activity, visible);
    }

    public static RecentsActivity getCurrentActivity() {
        return sCurrentActivity.get();
    }

    public static void onRecentsActivityCreate(RecentsActivity activity) {
        synchronized (LOCK) {
            RecentsActivityTracker tracker = sTracker.get();
            if (tracker != null && tracker.mOnInitListener.test(activity, false)) {
                sTracker.clear();
    @Override
    public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
            Context context, Handler handler, long duration) {
        register();

        Bundle options = animProvider.toActivityOptions(handler, duration).toBundle();
        context.startActivity(intent, options);
    }

    public static void onRecentsActivityCreate(RecentsActivity activity) {
        sCurrentActivity = new WeakReference<>(activity);
        sScheduler.initIfPending(activity, false);
    }


    public static void onRecentsActivityNewIntent(RecentsActivity activity) {
        sScheduler.initIfPending(activity, activity.isStarted());
    }

    public static void onRecentsActivityDestroy(RecentsActivity activity) {
        synchronized (LOCK) {
        if (sCurrentActivity.get() == activity) {
            sCurrentActivity.clear();
        }
    }
    }

    public static RecentsActivity getCurrentActivity() {
        synchronized (LOCK) {
            return sCurrentActivity.get();

    private static class Scheduler implements Runnable {

        private WeakReference<RecentsActivityTracker> mPendingTracker = new WeakReference<>(null);
        private MainThreadExecutor mMainThreadExecutor;

        public synchronized void schedule(RecentsActivityTracker tracker) {
            mPendingTracker = new WeakReference<>(tracker);
            if (mMainThreadExecutor == null) {
                mMainThreadExecutor = new MainThreadExecutor();
            }
            mMainThreadExecutor.execute(this);
        }

        @Override
    public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
            Context context, Handler handler, long duration) {
        register();
        public void run() {
            RecentsActivity activity = sCurrentActivity.get();
            if (activity != null) {
                initIfPending(activity, activity.isStarted());
            }
        }

        Bundle options = animProvider.toActivityOptions(handler, duration).toBundle();
        context.startActivity(intent, options);
        public synchronized boolean initIfPending(RecentsActivity activity, boolean alreadyOnHome) {
            RecentsActivityTracker tracker = mPendingTracker.get();
            if (tracker != null) {
                if (!tracker.init(activity, alreadyOnHome)) {
                    mPendingTracker.clear();
                }
                return true;
            }
            return false;
        }

        public synchronized boolean clearReference(RecentsActivityTracker tracker) {
            if (mPendingTracker.get() == tracker) {
                mPendingTracker.clear();
                return true;
            }
            return false;
        }
    }
}
+9 −7
Original line number Diff line number Diff line
@@ -164,6 +164,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
    private float mCurrentDisplacement;
    private boolean mGestureStarted;
    private int mLogAction = Touch.SWIPE;
    private float mCurrentQuickScrubProgress;

    private @InteractionType int mInteractionType = INTERACTION_NORMAL;

@@ -228,11 +229,11 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
                this::invalidateHandlerWithLauncher);

        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_QUICK_SCRUB_START,
        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START,
                this::onQuickScrubStart);
        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_QUICK_SCRUB_START
        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_QUICK_SCRUB_START
                | STATE_SCALED_CONTROLLER_RECENTS, this::onFinishedTransitionToQuickScrub);
        mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_SWITCH_TO_SCREENSHOT_COMPLETE
        mStateCallback.addCallback(STATE_LAUNCHER_STARTED | STATE_SWITCH_TO_SCREENSHOT_COMPLETE
                | STATE_QUICK_SCRUB_END, this::switchToFinalAppAfterQuickScrub);
    }

@@ -308,7 +309,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
            return;
        }

        mStateCallback.setState(STATE_LAUNCHER_STARTED);
        mActivityControlHelper.prepareRecentsUI(mActivity, mWasLauncherAlreadyVisible);
        AbstractFloatingView.closeAllOpenViews(activity, mWasLauncherAlreadyVisible);

@@ -343,6 +343,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
        mRecentsView.showTask(mRunningTaskId);
        mRecentsView.setFirstTaskIconScaledDown(true /* isScaledDown */, false /* animate */);
        mLayoutListener.open();
        mStateCallback.setState(STATE_LAUNCHER_STARTED);
    }

    public void setLauncherOnDrawCallback(Runnable callback) {
@@ -684,6 +685,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
    private void onQuickScrubStart() {
        mActivityControlHelper.onQuickInteractionStart(mActivity, mWasLauncherAlreadyVisible);
        mQuickScrubController.onQuickScrubStart(false);

        // Inform the last progress in case we skipped before.
        mQuickScrubController.onQuickScrubProgress(mCurrentQuickScrubProgress);
    }

    private void onFinishedTransitionToQuickScrub() {
@@ -691,10 +695,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
    }

    public void onQuickScrubProgress(float progress) {
        mCurrentQuickScrubProgress = progress;
        if (Looper.myLooper() != Looper.getMainLooper() || mQuickScrubController == null) {
            // TODO: We can still get progress events while launcher is not ready on the worker
            // thread. Keep track of last received progress and apply that progress when launcher
            // is ready
            return;
        }
        mQuickScrubController.onQuickScrubProgress(progress);
Loading