diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index f18b35dcf541a..c01c6df4f2c8d 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -201,6 +201,11 @@ interface IWindowManager */ 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 4d575bcd1467e..b5a1a9346f5c1 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 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView 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 141562c86b901..81a949d1b7cfa 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.MutableBoolean; 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 @@ public class SystemServicesProxy { 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 422e917ef5ce1..a5b7aaf3036a6 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.R; 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 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // 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 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV 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 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV // 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 ad44196048964..d4d99af9675d3 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 @@ class Task implements DimLayer.DimLayerUser { } } + /** + * 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 75680a07b2960..bcfc8f22bf153 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 @@ public class WindowManagerService extends IWindowManager.Stub } } + @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