Merge "Don't rely on intent to call back from activity tracker" into sc-dev

This commit is contained in:
Winson Chung 2021-06-15 18:04:52 +00:00 committed by Android (Google) Code Review
commit 1b369c4763
10 changed files with 62 additions and 60 deletions

View File

@ -21,6 +21,7 @@ import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ActivityTracker; import com.android.launcher3.util.ActivityTracker;
@ -37,7 +38,8 @@ public class HotseatEduActivity extends Activity {
.addCategory(Intent.CATEGORY_HOME) .addCategory(Intent.CATEGORY_HOME)
.setPackage(getPackageName()) .setPackage(getPackageName())
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
new HotseatActivityTracker<>().addToIntent(homeIntent);
Launcher.ACTIVITY_TRACKER.registerCallback(new HotseatActivityTracker());
startActivity(homeIntent); startActivity(homeIntent);
finish(); finish();
} }

View File

@ -349,6 +349,13 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
} }
if (mActivity != null) { 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. // The launcher may have been recreated as a result of device rotation.
int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES; int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES;
initStateCallbacks(); initStateCallbacks();
@ -1717,13 +1724,12 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
/** /**
* Registers a callback to run when the activity is ready. * 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 // Preload the plan
RecentsModel.INSTANCE.get(mContext).getTasks(null); RecentsModel.INSTANCE.get(mContext).getTasks(null);
mActivityInitListener.register(intent); mActivityInitListener.register();
} }
/** /**

View File

@ -184,9 +184,7 @@ public class OverviewCommandHelper {
.newHandler(gestureState, cmd.createTime); .newHandler(gestureState, cmd.createTime);
interactionHandler.setGestureEndCallback( interactionHandler.setGestureEndCallback(
() -> onTransitionComplete(cmd, interactionHandler)); () -> onTransitionComplete(cmd, interactionHandler));
interactionHandler.initWhenReady();
Intent intent = new Intent(interactionHandler.getLaunchIntent());
interactionHandler.initWhenReady(intent);
RecentsAnimationListener recentAnimListener = new RecentsAnimationListener() { RecentsAnimationListener recentAnimListener = new RecentsAnimationListener() {
@Override @Override
@ -212,6 +210,7 @@ public class OverviewCommandHelper {
cmd.mActiveCallbacks.addListener(recentAnimListener); cmd.mActiveCallbacks.addListener(recentAnimListener);
mTaskAnimationManager.notifyRecentsAnimationState(recentAnimListener); mTaskAnimationManager.notifyRecentsAnimationState(recentAnimListener);
} else { } else {
Intent intent = new Intent(interactionHandler.getLaunchIntent());
intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, gestureState.getGestureId()); intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, gestureState.getGestureId());
cmd.mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation( cmd.mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(
gestureState, intent, interactionHandler); gestureState, intent, interactionHandler);

View File

@ -141,7 +141,7 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
@Override @Override
protected void onNewIntent(Intent intent) { protected void onNewIntent(Intent intent) {
super.onNewIntent(intent); super.onNewIntent(intent);
ACTIVITY_TRACKER.handleNewIntent(this, intent); ACTIVITY_TRACKER.handleNewIntent(this);
} }
/** /**

View File

@ -389,8 +389,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs); mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs);
mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished); mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished);
mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler.getMotionPauseListener()); mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler.getMotionPauseListener());
Intent intent = new Intent(mInteractionHandler.getLaunchIntent()); mInteractionHandler.initWhenReady();
mInteractionHandler.initWhenReady(intent);
if (mTaskAnimationManager.isRecentsAnimationRunning()) { if (mTaskAnimationManager.isRecentsAnimationRunning()) {
mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState); mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState);
@ -398,6 +397,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler); mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler);
notifyGestureStarted(true /*isLikelyToStartNewTask*/); notifyGestureStarted(true /*isLikelyToStartNewTask*/);
} else { } else {
Intent intent = new Intent(mInteractionHandler.getLaunchIntent());
intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId()); intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent, mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent,
mInteractionHandler); mInteractionHandler);

View File

@ -26,7 +26,8 @@ import com.android.launcher3.util.ActivityTracker.SchedulerCallback;
import java.util.function.BiPredicate; import java.util.function.BiPredicate;
public class ActivityInitListener<T extends BaseActivity> implements SchedulerCallback<T> { public class ActivityInitListener<T extends BaseActivity> implements
SchedulerCallback<T> {
private BiPredicate<T, Boolean> mOnInitListener; private BiPredicate<T, Boolean> mOnInitListener;
private final ActivityTracker<T> mActivityTracker; private final ActivityTracker<T> mActivityTracker;
@ -47,6 +48,7 @@ public class ActivityInitListener<T extends BaseActivity> implements SchedulerCa
@Override @Override
public final boolean init(T activity, boolean alreadyOnHome) { public final boolean init(T activity, boolean alreadyOnHome) {
if (!mIsRegistered) { if (!mIsRegistered) {
// Don't receive any more updates
return false; return false;
} }
return handleInit(activity, alreadyOnHome); return handleInit(activity, alreadyOnHome);
@ -59,18 +61,17 @@ public class ActivityInitListener<T extends BaseActivity> implements SchedulerCa
/** /**
* Registers the activity-created listener. If the activity is already created, then the * Registers the activity-created listener. If the activity is already created, then the
* callback provided in the constructor will be called synchronously. * 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; mIsRegistered = true;
mActivityTracker.runCallbackWhenActivityExists(this, intent); mActivityTracker.registerCallback(this);
} }
/** /**
* After calling this, we won't {@link #init} even when the activity is ready. * After calling this, we won't {@link #init} even when the activity is ready.
*/ */
public void unregister() { public void unregister() {
mActivityTracker.unregisterCallback(this);
mIsRegistered = false; mIsRegistered = false;
mOnInitListener = null; mOnInitListener = null;
} }
@ -82,9 +83,9 @@ public class ActivityInitListener<T extends BaseActivity> implements SchedulerCa
*/ */
public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
Context context, Handler handler, long duration) { Context context, Handler handler, long duration) {
mIsRegistered = true; register();
Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle(); Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle();
context.startActivity(addToIntent(new Intent(intent)), options); context.startActivity(new Intent(intent), options);
} }
} }

View File

@ -1478,7 +1478,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
boolean shouldMoveToDefaultScreen = alreadyOnHome && isInState(NORMAL) boolean shouldMoveToDefaultScreen = alreadyOnHome && isInState(NORMAL)
&& AbstractFloatingView.getTopOpenView(this) == null; && AbstractFloatingView.getTopOpenView(this) == null;
boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction()); boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this, intent); boolean internalStateHandled = ACTIVITY_TRACKER.handleNewIntent(this);
hideKeyboard(); hideKeyboard();
if (isActionMain) { if (isActionMain) {
if (!internalStateHandled) { if (!internalStateHandled) {

View File

@ -212,7 +212,7 @@ public class AddItemActivity extends BaseActivity
.addCategory(Intent.CATEGORY_HOME) .addCategory(Intent.CATEGORY_HOME)
.setPackage(getPackageName()) .setPackage(getPackageName())
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Launcher.ACTIVITY_TRACKER.runCallbackWhenActivityExists(listener, homeIntent); Launcher.ACTIVITY_TRACKER.registerCallback(listener);
startActivity(homeIntent, startActivity(homeIntent,
ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out) ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out)
.toBundle()); .toBundle());

View File

@ -25,6 +25,7 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.UiThreadHelper;
/** /**
@ -50,7 +51,7 @@ public class RotationHelper implements OnSharedPreferenceChangeListener,
/** /**
* Rotation request made by * Rotation request made by
* {@link com.android.launcher3.util.ActivityTracker.SchedulerCallback}. * {@link ActivityTracker.SchedulerCallback}.
* This supersedes any other request. * This supersedes any other request.
*/ */
private int mStateHandlerRequest = REQUEST_NONE; private int mStateHandlerRequest = REQUEST_NONE;

View File

@ -15,15 +15,14 @@
*/ */
package com.android.launcher3.util; package com.android.launcher3.util;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseActivity;
import java.lang.ref.WeakReference; 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 * Helper class to statically track activity creation
@ -32,8 +31,7 @@ import java.lang.ref.WeakReference;
public final class ActivityTracker<T extends BaseActivity> { public final class ActivityTracker<T extends BaseActivity> {
private WeakReference<T> mCurrentActivity = new WeakReference<>(null); private WeakReference<T> mCurrentActivity = new WeakReference<>(null);
private CopyOnWriteArrayList<SchedulerCallback<T>> mCallbacks = new CopyOnWriteArrayList<>();
private static final String EXTRA_SCHEDULER_CALLBACK = "launcher.scheduler_callback";
@Nullable @Nullable
public <R extends T> R getCreatedActivity() { public <R extends T> R getCreatedActivity() {
@ -47,43 +45,50 @@ public final class ActivityTracker<T extends BaseActivity> {
} }
/** /**
* Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the activity is ready. * Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the
* If the activity is already created, this is called immediately, otherwise we add the * activity is ready. If the activity is already created, this is called immediately.
* callback as an extra on the intent, and will call init() when we get handleIntent(). *
* 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 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<T> callback, Intent intent) { public void registerCallback(SchedulerCallback<T> callback) {
T activity = mCurrentActivity.get(); T activity = mCurrentActivity.get();
mCallbacks.add(callback);
if (activity != null) { if (activity != null) {
callback.init(activity, activity.isStarted()); if (!callback.init(activity, activity.isStarted())) {
} else { unregisterCallback(callback);
callback.addToIntent(intent);
} }
} }
}
/**
* Unregisters a registered callback.
*/
public void unregisterCallback(SchedulerCallback<T> callback) {
mCallbacks.remove(callback);
}
public boolean handleCreate(T activity) { public boolean handleCreate(T activity) {
mCurrentActivity = new WeakReference<>(activity); mCurrentActivity = new WeakReference<>(activity);
return handleIntent(activity, activity.getIntent(), false); return handleIntent(activity, false /* alreadyOnHome */);
} }
public boolean handleNewIntent(T activity, Intent intent) { public boolean handleNewIntent(T activity) {
return handleIntent(activity, intent, activity.isStarted()); return handleIntent(activity, activity.isStarted());
} }
private boolean handleIntent(T activity, Intent intent, boolean alreadyOnHome) { private boolean handleIntent(T activity, boolean alreadyOnHome) {
if (intent != null && intent.getExtras() != null) { boolean handled = false;
IBinder stateBinder = intent.getExtras().getBinder(EXTRA_SCHEDULER_CALLBACK); for (SchedulerCallback<T> cb : mCallbacks) {
SchedulerCallback<T> handler = ObjectWrapper.unwrap(stateBinder); if (!cb.init(activity, alreadyOnHome)) {
if (handler != null) { // Callback doesn't want any more updates
if (!handler.init(activity, alreadyOnHome)) { unregisterCallback(cb);
intent.getExtras().remove(EXTRA_SCHEDULER_CALLBACK);
} }
return true; handled = true;
} }
} return handled;
return false;
} }
public interface SchedulerCallback<T extends BaseActivity> { public interface SchedulerCallback<T extends BaseActivity> {
@ -94,17 +99,5 @@ public final class ActivityTracker<T extends BaseActivity> {
* @return Whether to continue receiving callbacks (i.e. if the activity is recreated). * @return Whether to continue receiving callbacks (i.e. if the activity is recreated).
*/ */
boolean init(T activity, boolean alreadyOnHome); 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;
}
} }
} }