From 8477226a3d2c4b94c4263b8de92f9d3f258fe7ea Mon Sep 17 00:00:00 2001 From: Jeremy Sim Date: Wed, 22 Feb 2023 13:35:50 -0800 Subject: [PATCH] Fix bug with rotating in the middle of split select staging animation This patch fixes a bug where a user could cause a crash by rotating the device in the middle of the split staging animation. The bug arose because: 1) Normally, when you rotate the device, reapplyState() is called to refresh the UI. This reloads the state, cancels any animations that happen to be running at the time, and generally works fine in most cases. 2) When animations are canceled within Overview, we also call RecentsView#reset() to clean up loose ends and prevent bugs. 3) Unlike other states, the split select state is unique because it is a transient state that holds the user's choices temporarily. If that information was cleared -- by reset() -- before it loads, it will crash. Fixed by creating a new function in SplitScreenSelectState, onStateReapplied(), that is called when a reload is occurring. It makes sure that animations do not get canceled by calling end() to accelerate them to completion before the reloading occurs. Fixes: 249819567 Test: Manual Change-Id: I70c4651bcb5df81edd25f6e58e21520ebb391d01 --- .../uioverrides/states/SplitScreenSelectState.java | 5 +++++ .../src/com/android/quickstep/views/RecentsView.java | 2 -- src/com/android/launcher3/statemanager/BaseState.java | 8 ++++++++ src/com/android/launcher3/statemanager/StateManager.java | 7 +++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java index 8babd3470b..3ae221bbeb 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/SplitScreenSelectState.java @@ -53,4 +53,9 @@ public class SplitScreenSelectState extends OverviewState { return SplitAnimationTimings.ABORT_DURATION; } } + + @Override + public boolean shouldPreserveDataStateOnReapply() { + return true; + } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index e529b04577..b0bb9eb187 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -79,7 +79,6 @@ import android.animation.ValueAnimator; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.WindowConfiguration; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.LocusId; @@ -4624,7 +4623,6 @@ public abstract class RecentsView { default boolean showTaskThumbnailSplash() { return false; } + + /** + * For this state, whether member variables and other forms of data state should be preserved + * or wiped when the state is reapplied. (See {@link StateManager#reapplyState()}) + */ + default boolean shouldPreserveDataStateOnReapply() { + return false; + } } diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java index 34ac8c2ec3..89d89d6eca 100644 --- a/src/com/android/launcher3/statemanager/StateManager.java +++ b/src/com/android/launcher3/statemanager/StateManager.java @@ -184,6 +184,13 @@ public class StateManager> { public void reapplyState(boolean cancelCurrentAnimation) { boolean wasInAnimation = mConfig.currentAnimation != null; if (cancelCurrentAnimation) { + // Animation canceling can trigger a cleanup routine, causing problems when we are in a + // launcher state that relies on member variable data. So if we are in one of those + // states, accelerate the current animation to its end point rather than canceling it + // outright. + if (mState.shouldPreserveDataStateOnReapply() && mConfig.currentAnimation != null) { + mConfig.currentAnimation.end(); + } mAtomicAnimationFactory.cancelAllStateElementAnimation(); cancelAnimation(); }