Currently using quick switch is fine but sometimes with animation
glitches but very reproducible if tapping recents button very fast. The
problem is that low end device Recents entrance animation also has the
previous tasks animating downward causing more chances of animation
instability.
The problem is that transition is not finished and it is already
starting to do the next toggled animation. When the transition from
app to recents (RecentsImpl.toggleRecents) starts without finishing
RecentsActivity.onStop, the previous frame will be visible for a couple
of frames before the entrance animation starts (having the previous task
animate down). Therefore restrict toggling to after
RecentsActivity.onStop would allow the previous frame to finish and the
transitions run normally.
Bug:
62251652
Fixes:
64401391
Test: manual - using gobo device, launch multiple apps, rapidly tap recents
button
Change-Id: I4e70434bca3c9bec287fa30559b23a1e71b5ef20
import com.android.systemui.recents.events.component.ActivityUnpinnedEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
+import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
import com.android.systemui.recents.events.ui.HideIncompatibleAppOverlayEvent;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
+import android.app.ActivityOptions.OnAnimationFinishedListener;
import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.ActivityNotFoundException;
import android.content.Context;
mWaitingForTransitionStart = waitingForTransitionStart;
if (!waitingForTransitionStart && mToggleFollowingTransitionStart) {
- toggleRecents(DividerView.INVALID_RECENTS_GROW_TARGET);
+ mHandler.post(() -> toggleRecents(DividerView.INVALID_RECENTS_GROW_TARGET));
}
mToggleFollowingTransitionStart = false;
}
private Pair<ActivityOptions, AppTransitionAnimationSpecsFuture>
getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo runningTask,
Rect windowOverrideRect) {
+ final boolean isLowRamDevice = Recents.getConfiguration().isLowRamDevice;
if (runningTask != null && runningTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
ArrayList<Task> tasks;
AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
specs.toArray(specsArray);
+ // For low end ram devices, wait for transition flag is reset when Recents entrance
+ // animation is complete instead of when the transition animation starts
return new Pair<>(ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
- specsArray, mHandler, mResetToggleFlagListener, this), null);
+ specsArray, mHandler, isLowRamDevice ? null : mResetToggleFlagListener, this),
+ null);
} else {
// Update the destination rect
Task toTask = new Task();
toTask.key.id, thumbnail, rect));
});
+ // For low end ram devices, wait for transition flag is reset when Recents entrance
+ // animation is complete instead of when the transition animation starts
return new Pair<>(ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
- mHandler, future.getFuture(), mResetToggleFlagListener, false /* scaleUp */),
- future);
+ mHandler, future.getFuture(), isLowRamDevice ? null : mResetToggleFlagListener,
+ false /* scaleUp */), future);
}
}
mHandler.postDelayed(mStartScreenPinningRunnable, 350);
}
- // Reset the state where we are waiting for the transition to start
- EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ if (!Recents.getConfiguration().isLowRamDevice) {
+ // Reset the state where we are waiting for the transition to start
+ EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ }
}
};
} else {
EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
stackView.cancelAllTaskViewAnimations();
- // Reset the state where we are waiting for the transition to start
- EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ if (!Recents.getConfiguration().isLowRamDevice) {
+ // Reset the state where we are waiting for the transition to start
+ EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ }
}
};
}
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsDebugFlags;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
return;
}
+ final boolean isLowRamDevice = Recents.getConfiguration().isLowRamDevice;
int taskViewEnterFromAppDuration = res.getInteger(
R.integer.recents_task_enter_from_app_duration);
int taskViewEnterFromAffiliatedAppDuration = res.getInteger(
int dockGestureAnimDuration = appRes.getInteger(
R.integer.long_press_dock_anim_duration);
+ // Since low ram devices have an animation when entering app -> recents, do not allow
+ // toggle until the animation is complete
+ if (launchState.launchedFromApp && !launchState.launchedViaDockGesture && isLowRamDevice) {
+ postAnimationTrigger.addLastDecrementRunnable(() -> EventBus.getDefault()
+ .send(new SetWaitingForTransitionStartEvent(false)));
+ }
+
// Create enter animations for each of the views from front to back
List<TaskView> taskViews = mStackView.getTaskViews();
int taskViewCount = taskViews.size();
AnimationProps taskAnimation = new AnimationProps()
.setInterpolator(AnimationProps.ALPHA, ENTER_FROM_HOME_ALPHA_INTERPOLATOR)
.setListener(postAnimationTrigger.decrementOnAnimationEnd());
- if (Recents.getConfiguration().isLowRamDevice) {
+ if (isLowRamDevice) {
taskAnimation.setInterpolator(AnimationProps.BOUNDS,
Interpolators.FAST_OUT_SLOW_IN)
.setDuration(AnimationProps.BOUNDS, 150)