Merge "Cancel gestures on launcher destroy" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2022-12-05 20:25:47 +00:00
committed by Android (Google) Code Review
11 changed files with 243 additions and 118 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2018 The Android Open Source Project
* Copyright (C) 2022 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.
@@ -16,19 +16,23 @@
package com.android.launcher3;
import android.animation.AnimatorSet;
import android.annotation.Nullable;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.CancellationSignal;
import android.view.RemoteAnimationTarget;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.RemoteAnimationProvider;
import java.util.function.BiPredicate;
/**
* {@link ActivityLifecycleListener} for the in-launcher recents.
*/
@TargetApi(Build.VERSION_CODES.P)
public class LauncherInitListener extends ActivityInitListener<Launcher> {
public class LauncherLifecycleListener extends ActivityLifecycleListener<Launcher> {
private RemoteAnimationProvider mRemoteAnimationProvider;
@@ -36,13 +40,16 @@ public class LauncherInitListener extends ActivityInitListener<Launcher> {
* @param onInitListener a callback made when the activity is initialized. The callback should
* return true to continue receiving callbacks (ie. for if the activity is
* recreated).
* @param onDestroyListener a callback made when the activity is destroyed.
*/
public LauncherInitListener(BiPredicate<Launcher, Boolean> onInitListener) {
super(onInitListener, Launcher.ACTIVITY_TRACKER);
public LauncherLifecycleListener(
@Nullable BiPredicate<Launcher, Boolean> onInitListener,
@Nullable Runnable onDestroyListener) {
super(onInitListener, onDestroyListener, Launcher.ACTIVITY_TRACKER);
}
@Override
public boolean handleInit(Launcher launcher, boolean alreadyOnHome) {
public boolean handleActivityReady(Launcher launcher, boolean alreadyOnHome) {
if (mRemoteAnimationProvider != null) {
QuickstepTransitionManager appTransitionManager =
((QuickstepLauncher) launcher).getAppTransitionManager();
@@ -68,7 +75,7 @@ public class LauncherInitListener extends ActivityInitListener<Launcher> {
}, cancellationSignal);
}
launcher.deferOverlayCallbacksUntilNextResumeOrStop();
return super.handleInit(launcher, alreadyOnHome);
return super.handleActivityReady(launcher, alreadyOnHome);
}
@Override

View File

@@ -50,6 +50,7 @@ import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHE
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.LAUNCHER_DESTROYED;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
@@ -113,7 +114,7 @@ import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.InputConsumerProxy;
import com.android.quickstep.util.InputProxyHandlerFactory;
@@ -159,7 +160,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
protected final BaseActivityInterface<S, T> mActivityInterface;
protected final InputConsumerProxy mInputConsumerProxy;
protected final ActivityInitListener mActivityInitListener;
protected final ActivityLifecycleListener mActivityInitListener;
// Callbacks to be made once the recents animation starts
private final ArrayList<Runnable> mRecentsAnimationStartCallbacks = new ArrayList<>();
private final OnScrollChangedListener mOnRecentsScrollListener = this::onRecentsViewScroll;
@@ -329,7 +330,8 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
InputConsumerController inputConsumer) {
super(context, deviceState, gestureState);
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mActivityInitListener = mActivityInterface.createActivityLifecycleListener(
this::onActivityInit, this::onActivityDestroy);
mInputConsumerProxy =
new InputConsumerProxy(context, /* rotationSupplier = */ () -> {
if (mRecentsView == null) {
@@ -520,6 +522,11 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
return true;
}
private void onActivityDestroy() {
ActiveGestureLog.INSTANCE.addLog("Launcher activity destroyed", LAUNCHER_DESTROYED);
onGestureCancelled();
}
/**
* Return true if the window should be translated horizontally if the recents view scrolls
*/

View File

@@ -60,7 +60,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -123,8 +123,17 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
public abstract AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState deviceState,
boolean activityVisible, Consumer<AnimatorControllerWithResistance> callback);
public abstract ActivityInitListener createActivityInitListener(
Predicate<Boolean> onInitListener);
/**
* Creates a activity listener for activity initialized and/or destroyed. One or both of these
* listeners must be provided.
*
* @param onInitListener a callback made when the activity is initialized. The callback should
* return true to continue receiving callbacks (ie. for if the activity is
* recreated).
* @param onDestroyListener a callback made when the activity is destroyed.
*/
public abstract ActivityLifecycleListener createActivityLifecycleListener(
@Nullable Predicate<Boolean> onInitListener, @Nullable Runnable onDestroyListener);
/**
* Sets a callback to be run when an activity launch happens while launcher is not yet resumed.

View File

@@ -36,7 +36,7 @@ import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.views.RecentsView;
@@ -88,10 +88,12 @@ public final class FallbackActivityInterface extends
}
@Override
public ActivityInitListener createActivityInitListener(
Predicate<Boolean> onInitListener) {
return new ActivityInitListener<>((activity, alreadyOnHome) ->
onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER);
public ActivityLifecycleListener createActivityLifecycleListener(
@Nullable Predicate<Boolean> onInitListener, @Nullable Runnable onDestroyListener) {
return new ActivityLifecycleListener<>(
(activity, alreadyOnHome) -> onInitListener.test(alreadyOnHome),
onDestroyListener,
RecentsActivity.ACTIVITY_TRACKER);
}
@Nullable

View File

@@ -37,7 +37,7 @@ import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherLifecycleListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statehandlers.DepthController;
@@ -49,7 +49,7 @@ import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.NavigationMode;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.ActivityLifecycleListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
@@ -136,9 +136,10 @@ public final class LauncherActivityInterface extends
}
@Override
public ActivityInitListener createActivityInitListener(Predicate<Boolean> onInitListener) {
return new LauncherInitListener((activity, alreadyOnHome) ->
onInitListener.test(alreadyOnHome));
public ActivityLifecycleListener createActivityLifecycleListener(
@Nullable Predicate<Boolean> onInitListener, @Nullable Runnable onDestroyListener) {
return new LauncherLifecycleListener((activity, alreadyOnHome) ->
onInitListener.test(alreadyOnHome), onDestroyListener);
}
@Override

View File

@@ -37,7 +37,7 @@ public class ActiveGestureErrorDetector {
ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION, FINISH_RECENTS_ANIMATION,
CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION,
CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED,
FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER,
FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, LAUNCHER_DESTROYED,
/**
* These GestureEvents are specifically associated to state flags that get set in
@@ -162,6 +162,13 @@ public class ActiveGestureErrorDetector {
+ "before/without setting end target to new task",
writer);
break;
case LAUNCHER_DESTROYED:
errorDetected |= printErrorIfTrue(
true,
prefix,
/* errorMessage= */ "Launcher destroyed mid-gesture",
writer);
break;
case STATE_GESTURE_COMPLETED:
errorDetected |= printErrorIfTrue(
!encounteredEvents.contains(GestureEvent.MOTION_UP),

View File

@@ -1,73 +0,0 @@
/*
* Copyright (C) 2019 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.quickstep.util;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ActivityTracker.SchedulerCallback;
import java.util.function.BiPredicate;
public class ActivityInitListener<T extends BaseActivity> implements
SchedulerCallback<T> {
private BiPredicate<T, Boolean> mOnInitListener;
private final ActivityTracker<T> mActivityTracker;
private boolean mIsRegistered = false;
/**
* @param onInitListener a callback made when the activity is initialized. The callback should
* return true to continue receiving callbacks (ie. for if the activity is
* recreated).
*/
public ActivityInitListener(BiPredicate<T, Boolean> onInitListener,
ActivityTracker<T> tracker) {
mOnInitListener = onInitListener;
mActivityTracker = tracker;
}
@Override
public final boolean init(T activity, boolean alreadyOnHome) {
if (!mIsRegistered) {
// Don't receive any more updates
return false;
}
return handleInit(activity, alreadyOnHome);
}
protected boolean handleInit(T activity, boolean alreadyOnHome) {
return mOnInitListener.test(activity, alreadyOnHome);
}
/**
* Registers the activity-created listener. If the activity is already created, then the
* callback provided in the constructor will be called synchronously.
*/
public void register() {
mIsRegistered = true;
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;
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2022 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.quickstep.util;
import android.util.Log;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ActivityTracker.SchedulerCallback;
import java.util.function.BiPredicate;
/**
* Listener for activity initialized and/or destroyed.
*/
public class ActivityLifecycleListener<T extends BaseActivity> implements
SchedulerCallback<T> {
private static final String TAG = "ActivityLifecycleListener";
@Nullable private final BiPredicate<T, Boolean> mOnInitListener;
@Nullable private final Runnable mOnDestroyListener;
private final ActivityTracker<T> mActivityTracker;
private boolean mIsRegistered = false;
/**
* One or both of {@code onInitListener} and {@code onInitListener} must be provided, otherwise
* the created instance will effectively be a no-op.
*
* @param onInitListener a callback made when the activity is initialized. The callback should
* return true to continue receiving callbacks (ie. for if the activity is
* recreated).
* @param onDestroyListener a callback made when the activity is destroyed.
*/
public ActivityLifecycleListener(
@Nullable BiPredicate<T, Boolean> onInitListener,
@Nullable Runnable onDestroyListener,
ActivityTracker<T> tracker) {
if (onInitListener == null && onDestroyListener == null) {
throw new IllegalArgumentException("Both listeners cannot be null");
}
mOnInitListener = onInitListener;
mOnDestroyListener = onDestroyListener;
mActivityTracker = tracker;
}
@Override
public final boolean onActivityReady(T activity, boolean alreadyOnHome) {
if (!mIsRegistered) {
// Don't receive any more updates
return false;
}
return handleActivityReady(activity, alreadyOnHome);
}
protected boolean handleActivityReady(T activity, boolean alreadyOnHome) {
if (mOnInitListener == null) {
Log.e(TAG, "Cannot handle init: init listener is null", new Exception());
return false;
}
return mOnInitListener.test(activity, alreadyOnHome);
}
@Override
public void onActivityDestroyed() {
if (mOnDestroyListener == null) {
Log.e(TAG, "Cannot clean up: destroy listener is null", new Exception());
return;
}
mOnDestroyListener.run();
}
/**
* Registers the activity-created listener. If the activity is already created, then the
* callback provided in the constructor will be called synchronously.
*/
public void register() {
mIsRegistered = true;
mActivityTracker.registerCallback(this, getType());
}
/**
* After calling this, we won't call {@link #onActivityReady} even when the activity is ready.
*/
public void unregister() {
mActivityTracker.unregisterCallback(this, getType());
mIsRegistered = false;
}
private int getType() {
return mOnInitListener != null && mOnDestroyListener != null
? ActivityTracker.TYPE_BOTH
: (mOnInitListener != null
? ActivityTracker.TYPE_INIT
: ActivityTracker.TYPE_DESTROY);
}
}