Add ability to cancel task window transitions.
Bug: 25392381
Change-Id: I45f48edc21c058df0e4c22ceaf7e9aef5899a29c
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f18b35d..c01c6df 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -201,6 +201,11 @@
*/
void setScreenCaptureDisabled(int userId, boolean disabled);
+ /**
+ * Cancels the window transitions for the given task.
+ */
+ void cancelTaskWindowTransition(int taskId);
+
// These can only be called with the SET_ORIENTATION permission.
/**
* Update the current screen rotation based on the current state of
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 4d575bc..b5a1a93 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -517,6 +517,15 @@
boolean hasRepKeyTimeElapsed = (SystemClock.elapsedRealtime() -
mLastTabKeyEventTime) > altTabKeyDelay;
if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) {
+ // As we iterate to the next/previous task, cancel any current/lagging window
+ // transition animations
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ if (launchState.launchedToTaskId != -1) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ssp.cancelWindowTransition(launchState.launchedToTaskId);
+ }
+
// Focus the next task in the stack
final boolean backward = event.isShiftPressed();
if (backward) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 141562c..81a949d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -57,6 +57,7 @@
import android.util.Pair;
import android.view.Display;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import com.android.internal.app.AssistUtils;
import com.android.internal.os.BackgroundThread;
@@ -335,6 +336,19 @@
return stackInfo != null;
}
+ /**
+ * Cancels the current window transtion to/from Recents for the given task id.
+ */
+ public void cancelWindowTransition(int taskId) {
+ if (mWm == null) return;
+
+ try {
+ WindowManagerGlobal.getWindowManagerService().cancelTaskWindowTransition(taskId);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
/** Returns the top task thumbnail for the given task id */
public Bitmap getTaskThumbnail(int taskId) {
if (mAm == null) return null;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 422e917..a5b7aaf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -44,6 +44,7 @@
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsAppWidgetHostView;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
@@ -587,6 +588,20 @@
return new AppTransitionAnimationSpec(taskId, b, rect);
}
+ /**
+ * Cancels any running window transitions for the launched task (the task animating into
+ * Recents).
+ */
+ private void cancelLaunchedTaskWindowTransition(final Task task) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
+ if (launchState.launchedToTaskId != -1 &&
+ launchState.launchedToTaskId != task.key.id) {
+ ssp.cancelWindowTransition(launchState.launchedToTaskId);
+ }
+ }
+
/**** TaskStackView.TaskStackCallbacks Implementation ****/
@Override
@@ -617,34 +632,37 @@
// Compute the thumbnail to scale up from
final SystemServicesProxy ssp = Recents.getSystemServices();
+ boolean screenPinningRequested = false;
ActivityOptions opts = null;
ActivityOptions.OnAnimationStartedListener animStartedListener = null;
if (task.thumbnail != null && task.thumbnail.getWidth() > 0 &&
task.thumbnail.getHeight() > 0) {
- if (lockToTask) {
- animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
- boolean mTriggered = false;
- @Override
- public void onAnimationStarted() {
- if (!mTriggered) {
- postDelayed(new Runnable() {
- @Override
- public void run() {
- EventBus.getDefault().send(new ScreenPinningRequestEvent(
- getContext(), ssp));
- }
- }, 350);
- mTriggered = true;
- }
+ animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
+ @Override
+ public void onAnimationStarted() {
+ // If we are launching into another task, cancel the previous task's
+ // window transition
+ cancelLaunchedTaskWindowTransition(task);
+
+ if (lockToTask) {
+ // Request screen pinning after the animation runs
+ postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ EventBus.getDefault().send(new ScreenPinningRequestEvent(
+ getContext(), ssp));
+ }
+ }, 350);
}
- };
- }
+ }
+ };
postDrawHeaderThumbnailTransitionRunnable(stackView, tv, offsetX, offsetY, stackScroll,
animStartedListener, destinationStack);
opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
offsetX, offsetY, (int) transform.rect.width(), (int) transform.rect.height(),
sourceView.getHandler(), animStartedListener);
+ screenPinningRequested = true;
} else {
opts = ActivityOptions.makeBasic();
}
@@ -652,7 +670,7 @@
opts.setBounds(bounds.isEmpty() ? null : bounds);
}
final ActivityOptions launchOpts = opts;
- final boolean screenPinningRequested = (animStartedListener == null) && lockToTask;
+ final boolean finalScreenPinningRequested = screenPinningRequested;
final Runnable launchRunnable = new Runnable() {
@Override
public void run() {
@@ -660,9 +678,11 @@
// Bring an active task to the foreground
ssp.moveTaskToFront(task.key.id, launchOpts);
} else {
- if (ssp.startActivityFromRecents(getContext(), task.key.id,
- task.activityLabel, launchOpts)) {
- if (screenPinningRequested) {
+ if (ssp.startActivityFromRecents(getContext(), task.key.id, task.activityLabel,
+ launchOpts)) {
+ if (!finalScreenPinningRequested) {
+ // If we have not requested this already to be run after the window
+ // transition, then just run it now
EventBus.getDefault().send(new ScreenPinningRequestEvent(
getContext(), ssp));
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index ad44196..d4d99af 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -320,6 +320,15 @@
}
}
+ /**
+ * Cancels any running app transitions associated with the task.
+ */
+ void cancelTaskWindowTransition() {
+ for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+ mAppTokens.get(activityNdx).mAppAnimator.clearAnimation();
+ }
+ }
+
boolean showForAllUsers() {
final int tokensCount = mAppTokens.size();
return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 75680a0..bcfc8f2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4607,6 +4607,16 @@
}
}
+ @Override
+ public void cancelTaskWindowTransition(int taskId) {
+ synchronized (mWindowMap) {
+ Task task = mTaskIdToTask.get(taskId);
+ if (task != null) {
+ task.cancelTaskWindowTransition();
+ }
+ }
+ }
+
public void addTask(int taskId, int stackId, boolean toTop) {
synchronized (mWindowMap) {
if (DEBUG_STACK) Slog.i(TAG, "addTask: adding taskId=" + taskId