diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java index 3a1a2f7ae2..3a7d821ed6 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.os.Bundle; import com.android.launcher3.BaseActivity; +import com.android.launcher3.Launcher; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.ActivityTracker; @@ -37,7 +38,8 @@ public class HotseatEduActivity extends Activity { .addCategory(Intent.CATEGORY_HOME) .setPackage(getPackageName()) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - new HotseatActivityTracker<>().addToIntent(homeIntent); + + Launcher.ACTIVITY_TRACKER.registerCallback(new HotseatActivityTracker()); startActivity(homeIntent); finish(); } diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 52f34d90e0..44ac4ae139 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -348,6 +348,13 @@ public abstract class AbsSwipeUpHandler, } if (mActivity != null) { + if (mStateCallback.hasStates(STATE_GESTURE_COMPLETED)) { + // If the activity has restarted between setting the page scroll settling callback + // and actually receiving the callback, just mark the gesture completed + mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED); + return true; + } + // The launcher may have been recreated as a result of device rotation. int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES; initStateCallbacks(); @@ -1713,13 +1720,12 @@ public abstract class AbsSwipeUpHandler, /** * Registers a callback to run when the activity is ready. - * @param intent The intent that will be used to start the activity if it doesn't exist already. */ - public void initWhenReady(Intent intent) { + public void initWhenReady() { // Preload the plan RecentsModel.INSTANCE.get(mContext).getTasks(null); - mActivityInitListener.register(intent); + mActivityInitListener.register(); } /** diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java index dbdd75fc13..2beef0a7ce 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java @@ -184,9 +184,7 @@ public class OverviewCommandHelper { .newHandler(gestureState, cmd.createTime); interactionHandler.setGestureEndCallback( () -> onTransitionComplete(cmd, interactionHandler)); - - Intent intent = new Intent(interactionHandler.getLaunchIntent()); - interactionHandler.initWhenReady(intent); + interactionHandler.initWhenReady(); RecentsAnimationListener recentAnimListener = new RecentsAnimationListener() { @Override @@ -212,6 +210,7 @@ public class OverviewCommandHelper { cmd.mActiveCallbacks.addListener(recentAnimListener); mTaskAnimationManager.notifyRecentsAnimationState(recentAnimListener); } else { + Intent intent = new Intent(interactionHandler.getLaunchIntent()); intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, gestureState.getGestureId()); cmd.mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation( gestureState, intent, interactionHandler); diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index 68526420ef..80c6a97a73 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -141,7 +141,7 @@ public final class RecentsActivity extends StatefulActivity { @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); - ACTIVITY_TRACKER.handleNewIntent(this, intent); + ACTIVITY_TRACKER.handleNewIntent(this); } /** diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 9878d4527a..725c7c45a5 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -389,8 +389,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs); mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished); mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler.getMotionPauseListener()); - Intent intent = new Intent(mInteractionHandler.getLaunchIntent()); - mInteractionHandler.initWhenReady(intent); + mInteractionHandler.initWhenReady(); if (mTaskAnimationManager.isRecentsAnimationRunning()) { mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState); @@ -398,6 +397,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler); notifyGestureStarted(true /*isLikelyToStartNewTask*/); } else { + Intent intent = new Intent(mInteractionHandler.getLaunchIntent()); intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId()); mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, mInteractionHandler); diff --git a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java index dfb8c1d548..b9879ab82b 100644 --- a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java +++ b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java @@ -26,7 +26,8 @@ import com.android.launcher3.util.ActivityTracker.SchedulerCallback; import java.util.function.BiPredicate; -public class ActivityInitListener implements SchedulerCallback { +public class ActivityInitListener implements + SchedulerCallback { private BiPredicate mOnInitListener; private final ActivityTracker mActivityTracker; @@ -47,6 +48,7 @@ public class ActivityInitListener implements SchedulerCa @Override public final boolean init(T activity, boolean alreadyOnHome) { if (!mIsRegistered) { + // Don't receive any more updates return false; } return handleInit(activity, alreadyOnHome); @@ -59,18 +61,17 @@ public class ActivityInitListener implements SchedulerCa /** * Registers the activity-created listener. If the activity is already created, then the * callback provided in the constructor will be called synchronously. - * @param intent The intent that will be used to initialize the activity, if the activity - * doesn't already exist. We add the callback as an extra on this intent. */ - public void register(Intent intent) { + public void register() { mIsRegistered = true; - mActivityTracker.runCallbackWhenActivityExists(this, intent); + mActivityTracker.registerCallback(this); } /** * After calling this, we won't {@link #init} even when the activity is ready. */ public void unregister() { + mActivityTracker.unregisterCallback(this); mIsRegistered = false; mOnInitListener = null; } @@ -82,9 +83,9 @@ public class ActivityInitListener implements SchedulerCa */ public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, Context context, Handler handler, long duration) { - mIsRegistered = true; + register(); Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle(); - context.startActivity(addToIntent(new Intent(intent)), options); + context.startActivity(new Intent(intent), options); } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 578379b70d..c91fb27619 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1472,7 +1472,7 @@ public class Launcher extends StatefulActivity implements Launche boolean shouldMoveToDefaultScreen = alreadyOnHome && isInState(NORMAL) && AbstractFloatingView.getTopOpenView(this) == null; boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction()); - boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this, intent); + boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this); hideKeyboard(); if (isActionMain) { if (!internalStateHandled) { diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index b4288ce1f5..2844fb2178 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -213,7 +213,7 @@ public class AddItemActivity extends BaseActivity .addCategory(Intent.CATEGORY_HOME) .setPackage(getPackageName()) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Launcher.ACTIVITY_TRACKER.runCallbackWhenActivityExists(listener, homeIntent); + Launcher.ACTIVITY_TRACKER.registerCallback(listener); startActivity(homeIntent, ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out) .toBundle()); diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java index 5832711f11..87871b11db 100644 --- a/src/com/android/launcher3/states/RotationHelper.java +++ b/src/com/android/launcher3/states/RotationHelper.java @@ -25,6 +25,7 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Utilities; +import com.android.launcher3.util.ActivityTracker; import com.android.launcher3.util.UiThreadHelper; /** @@ -50,7 +51,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener, /** * Rotation request made by - * {@link com.android.launcher3.util.ActivityTracker.SchedulerCallback}. + * {@link ActivityTracker.SchedulerCallback}. * This supersedes any other request. */ private int mStateHandlerRequest = REQUEST_NONE; diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java index b5b9c2f43a..7af1a13d67 100644 --- a/src/com/android/launcher3/util/ActivityTracker.java +++ b/src/com/android/launcher3/util/ActivityTracker.java @@ -15,15 +15,14 @@ */ package com.android.launcher3.util; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; - import androidx.annotation.Nullable; import com.android.launcher3.BaseActivity; import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.concurrent.CopyOnWriteArrayList; /** * Helper class to statically track activity creation @@ -32,8 +31,7 @@ import java.lang.ref.WeakReference; public final class ActivityTracker { private WeakReference mCurrentActivity = new WeakReference<>(null); - - private static final String EXTRA_SCHEDULER_CALLBACK = "launcher.scheduler_callback"; + private CopyOnWriteArrayList> mCallbacks = new CopyOnWriteArrayList<>(); @Nullable public R getCreatedActivity() { @@ -47,43 +45,50 @@ public final class ActivityTracker { } /** - * Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the activity is ready. - * If the activity is already created, this is called immediately, otherwise we add the - * callback as an extra on the intent, and will call init() when we get handleIntent(). + * Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the + * activity is ready. If the activity is already created, this is called immediately. + * + * The tracker maintains a strong ref to the callback, so it is up to the caller to return + * {@code false} in the callback OR to unregister the callback explicitly. + * * @param callback The callback to call init() on when the activity is ready. - * @param intent The intent that will be used to initialize the activity, if the activity - * doesn't already exist. We add the callback as an extra on this intent. */ - public void runCallbackWhenActivityExists(SchedulerCallback callback, Intent intent) { + public void registerCallback(SchedulerCallback callback) { T activity = mCurrentActivity.get(); + mCallbacks.add(callback); if (activity != null) { - callback.init(activity, activity.isStarted()); - } else { - callback.addToIntent(intent); + if (!callback.init(activity, activity.isStarted())) { + unregisterCallback(callback); + } } } + /** + * Unregisters a registered callback. + */ + public void unregisterCallback(SchedulerCallback callback) { + mCallbacks.remove(callback); + } + public boolean handleCreate(T activity) { mCurrentActivity = new WeakReference<>(activity); - return handleIntent(activity, activity.getIntent(), false); + return handleIntent(activity, false /* alreadyOnHome */); } - public boolean handleNewIntent(T activity, Intent intent) { - return handleIntent(activity, intent, activity.isStarted()); + public boolean handleNewIntent(T activity) { + return handleIntent(activity, activity.isStarted()); } - private boolean handleIntent(T activity, Intent intent, boolean alreadyOnHome) { - if (intent != null && intent.getExtras() != null) { - IBinder stateBinder = intent.getExtras().getBinder(EXTRA_SCHEDULER_CALLBACK); - SchedulerCallback handler = ObjectWrapper.unwrap(stateBinder); - if (handler != null) { - if (!handler.init(activity, alreadyOnHome)) { - intent.getExtras().remove(EXTRA_SCHEDULER_CALLBACK); - } - return true; + private boolean handleIntent(T activity, boolean alreadyOnHome) { + boolean handled = false; + for (SchedulerCallback cb : mCallbacks) { + if (!cb.init(activity, alreadyOnHome)) { + // Callback doesn't want any more updates + unregisterCallback(cb); } + handled = true; } - return false; + return handled; } public interface SchedulerCallback { @@ -94,17 +99,5 @@ public final class ActivityTracker { * @return Whether to continue receiving callbacks (i.e. if the activity is recreated). */ boolean init(T activity, boolean alreadyOnHome); - - /** - * Adds this callback as an extra on the intent, so we can retrieve it in handleIntent() and - * call {@link #init}. The intent should be used to start the activity after calling this - * method in order for us to get handleIntent(). - */ - default Intent addToIntent(Intent intent) { - Bundle extras = new Bundle(); - extras.putBinder(EXTRA_SCHEDULER_CALLBACK, ObjectWrapper.wrap(this)); - intent.putExtras(extras); - return intent; - } } }