diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 4b695b93d0e92..ea0fbdab1b890 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -209,6 +209,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private Drawable mResizingBackgroundDrawable; private Drawable mCaptionBackgroundDrawable; private Drawable mUserCaptionBackgroundDrawable; + private Drawable mOriginalBackgroundDrawable; private float mAvailableWidth; @@ -888,6 +889,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mBackgroundPadding.setEmpty(); } drawableChanged(); + + // Make sure we don't reset to the old drawable when finishing resizing. + if (mResizeMode != RESIZE_MODE_INVALID) { + mOriginalBackgroundDrawable = null; + } } } @@ -1950,6 +1956,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateElevation(); updateColorViews(null /* insets */, false); + + mOriginalBackgroundDrawable = getBackground(); + setBackgroundDrawable(null); } mResizeMode = resizeMode; getViewRootImpl().requestInvalidateRootRenderNode(); @@ -1961,6 +1970,10 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind updateColorViews(null /* insets */, false); mResizeMode = RESIZE_MODE_INVALID; getViewRootImpl().requestInvalidateRootRenderNode(); + if (mOriginalBackgroundDrawable != null) { + setBackgroundDrawable(mOriginalBackgroundDrawable); + mOriginalBackgroundDrawable = null; + } } @Override diff --git a/packages/SystemUI/res/layout/recents_stack_action_button.xml b/packages/SystemUI/res/layout/recents_stack_action_button.xml index 87832616f7107..2b2ce4e534833 100644 --- a/packages/SystemUI/res/layout/recents_stack_action_button.xml +++ b/packages/SystemUI/res/layout/recents_stack_action_button.xml @@ -27,8 +27,6 @@ android:textSize="14sp" android:textColor="#FFFFFF" android:textAllCaps="true" - android:drawableStart="@drawable/ic_history" - android:drawablePadding="6dp" android:shadowColor="#99000000" android:shadowDx="0" android:shadowDy="2" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 622ae717058c7..fd051b1b371fa 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -153,6 +153,9 @@ 175 + + 300 + 200 diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index d1faa4a55d969..c094da9db43ae 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -574,10 +574,12 @@ 16dp 16dp 48dp + 16dp 64dp + 16dp - 56dp + 48dp 56dp diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java index 5e33a9f84cacb..17f4dab93bf47 100644 --- a/packages/SystemUI/src/com/android/systemui/Interpolators.java +++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java @@ -17,6 +17,7 @@ package com.android.systemui; import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; @@ -32,6 +33,7 @@ public class Interpolators { public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f); public static final Interpolator LINEAR = new LinearInterpolator(); + public static final Interpolator ACCELERATE = new AccelerateInterpolator(); public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator(); public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index b89c2f67a2202..d7777d5693370 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -90,6 +90,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD private RecentsPackageMonitor mPackageMonitor; private long mLastTabKeyEventTime; + private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; private boolean mFinishedOnStartup; private boolean mIgnoreAltTabRelease; private boolean mIsVisible; @@ -266,6 +267,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD getWindow().getAttributes().privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY; + mLastOrientation = getResources().getConfiguration().orientation; mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration); mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() { @Override @@ -274,6 +276,9 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD } }); + // Set the window background + getWindow().setBackgroundDrawable(mRecentsView.getBackgroundScrim()); + // Create the home intent runnable mHomeIntent = new Intent(Intent.ACTION_MAIN, null); mHomeIntent.addCategory(Intent.CATEGORY_HOME); @@ -415,13 +420,18 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD // Update the nav bar for the current orientation updateNavBarScrim(false /* animateNavBarScrim */, AnimationProps.IMMEDIATE); - EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */)); + // Notify of the config change + int newOrientation = getResources().getConfiguration().orientation; + EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */, + (mLastOrientation != newOrientation))); + mLastOrientation = newOrientation; } @Override public void onMultiWindowChanged(boolean inMultiWindow) { super.onMultiWindowChanged(inMultiWindow); - EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */)); + EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */, + false /* fromOrientationChange */)); if (mRecentsView != null) { // Reload the task stack completely diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java index 043510ed72ca3..171535691bbc9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java @@ -36,7 +36,7 @@ public class RecentsDebugFlags implements TunerService.Tunable { // Enables the task affiliations public static final boolean EnableAffiliatedTaskGroups = false; // TODO: To be repurposed - public static final boolean EnableStackActionButton = false; + public static final boolean EnableStackActionButton = true; // Overrides the Tuner flags and enables the timeout private static final boolean EnableFastToggleTimeout = false; // Overrides the Tuner flags and enables the paging via the Recents button diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index ffc037dba5e5b..43d627d9e13a5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -663,13 +663,18 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener @Override public void run() { final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform); - mHandler.post(new Runnable() { - @Override - public void run() { - mThumbnailTransitionBitmapCache = transitionBitmap; - mThumbnailTransitionBitmapCacheKey = toTask; - } - }); + if (transitionBitmap != null) { + mHandler.post(new Runnable() { + @Override + public void run() { + mThumbnailTransitionBitmapCache = transitionBitmap; + mThumbnailTransitionBitmapCacheKey = toTask; + } + }); + } else { + Log.e(TAG, "Could not load thumbnail for task: " + toTask + " at transform: " + + toTransform); + } } }); } @@ -774,7 +779,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener // Get the transform for the running task stackView.updateLayoutAlgorithm(true /* boundScroll */); stackView.updateToInitialState(true /* scrollToInitialState */); - mTmpTransform = stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask, + stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask, stackView.getScroller().getStackScroll(), mTmpTransform, null); return mTmpTransform; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java index c234c348ad66c..8be9ca7b5f2bc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java @@ -24,8 +24,10 @@ import com.android.systemui.recents.events.EventBus; public class ConfigurationChangedEvent extends EventBus.AnimatedEvent { public final boolean fromMultiWindow; + public final boolean fromOrientationChange; - public ConfigurationChangedEvent(boolean fromMultiWindow) { + public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange) { this.fromMultiWindow = fromMultiWindow; + this.fromOrientationChange = fromOrientationChange; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java similarity index 78% rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java rename to packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java index 863f40b39537b..f8b59c7c62f76 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResetBackgroundScrimEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissAllTaskViewsEvent.java @@ -17,10 +17,11 @@ package com.android.systemui.recents.events.ui; import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.views.TaskView; /** - * This is sent to reset the background scrim back to the initial state. + * This event is sent to request that all the {@link TaskView}s are dismissed. */ -public class ResetBackgroundScrimEvent extends EventBus.Event { +public class DismissAllTaskViewsEvent extends EventBus.AnimatedEvent { // Simple event } diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java index 1165f4e768618..1f8c6443502f3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java @@ -17,7 +17,6 @@ package com.android.systemui.recents.events.ui; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.model.Task; import com.android.systemui.recents.views.TaskView; /** @@ -26,10 +25,8 @@ import com.android.systemui.recents.views.TaskView; public class DismissTaskViewEvent extends EventBus.AnimatedEvent { public final TaskView taskView; - public final Task task; - public DismissTaskViewEvent(TaskView taskView, Task task) { + public DismissTaskViewEvent(TaskView taskView) { this.taskView = taskView; - this.task = task; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java deleted file mode 100644 index fdd4c673540db..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/UpdateBackgroundScrimEvent.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2016 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.systemui.recents.events.ui; - -import com.android.systemui.recents.events.EventBus; - -/** - * This is sent to request an update to the background scrim. - */ -public class UpdateBackgroundScrimEvent extends EventBus.Event { - - public final float alpha; - - public UpdateBackgroundScrimEvent(float alpha) { - this.alpha = alpha; - } -} diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index 5a2507debd7e1..df3f56c7c3acc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -221,6 +221,11 @@ public class TaskStack { void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask, Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture); + /** + * Notifies when all tasks have been removed from the stack. + */ + void onStackTasksRemoved(TaskStack stack); + /** * Notifies when tasks in the stack have been updated. */ @@ -509,6 +514,22 @@ public class TaskStack { mRawTaskList.remove(t); } + /** + * Removes all tasks from the stack. + */ + public void removeAllTasks() { + ArrayList tasks = mStackTaskList.getTasks(); + for (int i = tasks.size() - 1; i >= 0; i--) { + Task t = tasks.get(i); + removeTaskImpl(mStackTaskList, t); + mRawTaskList.remove(t); + } + if (mCb != null) { + // Notify that all tasks have been removed + mCb.onStackTasksRemoved(this); + } + } + /** * Sets a few tasks in one go, without calling any callbacks. * diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java index 3d0e75a8ef700..5eb9fda98d937 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java @@ -157,6 +157,11 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T } } + @Override + public void onStackTasksRemoved(TaskStack stack) { + // Do nothing + } + @Override public void onStackTasksUpdated(TaskStack stack) { // Do nothing diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java index 9dc3fb14936a8..9eec2ce030c2a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java @@ -28,11 +28,13 @@ import android.app.ActivityOptions.OnAnimationStartedListener; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.IRemoteCallback; import android.os.RemoteException; +import android.util.Log; import android.view.AppTransitionAnimationSpec; import android.view.IAppTransitionAnimationSpecsFuture; @@ -252,12 +254,13 @@ public class RecentsTransitionHelper { /** * Composes the transition spec when docking a task, which includes a full task bitmap. */ - public List composeDockAnimationSpec( - TaskView taskView, Rect transform) { - TaskViewTransform viewTransform = new TaskViewTransform(); - viewTransform.fillIn(taskView); - return Collections.singletonList(new AppTransitionAnimationSpec(taskView.getTask().key.id, - RecentsTransitionHelper.composeTaskBitmap(taskView, viewTransform), transform)); + public List composeDockAnimationSpec(TaskView taskView, + Rect bounds) { + mTmpTransform.fillIn(taskView); + Task task = taskView.getTask(); + Bitmap thumbnail = RecentsTransitionHelper.composeTaskBitmap(taskView, mTmpTransform); + return Collections.singletonList(new AppTransitionAnimationSpec(task.key.id, thumbnail, + bounds)); } /** @@ -336,18 +339,27 @@ public class RecentsTransitionHelper { float scale = transform.scale; int fromWidth = (int) (transform.rect.width() * scale); int fromHeight = (int) (transform.rect.height() * scale); - Bitmap b = Bitmap.createBitmap(fromWidth, fromHeight, - Bitmap.Config.ARGB_8888); + if (fromWidth == 0 || fromHeight == 0) { + Log.e(TAG, "Could not compose thumbnail for task: " + taskView.getTask() + + " at transform: " + transform); - if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) { - b.eraseColor(0xFFff0000); + Bitmap b = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + b.eraseColor(Color.TRANSPARENT); + return b; } else { - Canvas c = new Canvas(b); - c.scale(scale, scale); - taskView.draw(c); - c.setBitmap(null); + Bitmap b = Bitmap.createBitmap(fromWidth, fromHeight, + Bitmap.Config.ARGB_8888); + + if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) { + b.eraseColor(0xFFff0000); + } else { + Canvas c = new Canvas(b); + c.scale(scale, scale); + taskView.draw(c); + c.setBitmap(null); + } + return b.createAshmemBitmap(); } - return b.createAshmemBitmap(); } private static Bitmap composeHeaderBitmap(TaskView taskView, 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 b23b01f933200..da2f7212cae06 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -58,10 +58,11 @@ import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationC import com.android.systemui.recents.events.activity.HideStackActionButtonEvent; import com.android.systemui.recents.events.activity.LaunchTaskEvent; import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent; +import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent; +import com.android.systemui.recents.events.ui.DeleteTaskDataEvent; +import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent; import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent; import com.android.systemui.recents.events.ui.DraggingInRecentsEvent; -import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent; -import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent; import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; @@ -87,6 +88,9 @@ public class RecentsView extends FrameLayout { private static final int DEFAULT_UPDATE_SCRIM_DURATION = 200; private static final float DEFAULT_SCRIM_ALPHA = 0.33f; + private static final int SHOW_STACK_ACTION_BUTTON_DURATION = 150; + private static final int HIDE_STACK_ACTION_BUTTON_DURATION = 100; + private TaskStack mStack; private TaskStackView mTaskStackView; private TextView mStackActionButton; @@ -99,7 +103,8 @@ public class RecentsView extends FrameLayout { private Rect mSystemInsets = new Rect(); private int mDividerSize; - private ColorDrawable mBackgroundScrim = new ColorDrawable(Color.BLACK); + private Drawable mBackgroundScrim = new ColorDrawable( + Color.argb((int) (DEFAULT_SCRIM_ALPHA * 255), 0, 0, 0)).mutate(); private Animator mBackgroundScrimAnimator; private RecentsTransitionHelper mTransitionHelper; @@ -135,10 +140,11 @@ public class RecentsView extends FrameLayout { R.dimen.recents_task_view_rounded_corners_radius); mStackActionButton = (TextView) inflater.inflate(R.layout.recents_stack_action_button, this, false); + mStackActionButton.forceHasOverlappingRendering(false); mStackActionButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - // TODO: To be implemented + EventBus.getDefault().send(new DismissAllTaskViewsEvent()); } }); addView(mStackActionButton); @@ -152,8 +158,6 @@ public class RecentsView extends FrameLayout { } mEmptyView = (TextView) inflater.inflate(R.layout.recents_empty, this, false); addView(mEmptyView); - - setBackground(mBackgroundScrim); } /** @@ -179,14 +183,14 @@ public class RecentsView extends FrameLayout { if (isResumingFromVisible) { // If we are already visible, then restore the background scrim - animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION); + animateBackgroundScrim(1f, DEFAULT_UPDATE_SCRIM_DURATION); } else { // If we are already occluded by the app, then set the final background scrim alpha now. // Otherwise, defer until the enter animation completes to animate the scrim alpha with // the tasks for the home animation. if (launchState.launchedViaDockGesture || launchState.launchedFromApp || isTaskStackEmpty) { - mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255)); + mBackgroundScrim.setAlpha(255); } else { mBackgroundScrim.setAlpha(0); } @@ -215,6 +219,13 @@ public class RecentsView extends FrameLayout { return mStack; } + /* + * Returns the window background scrim. + */ + public Drawable getBackgroundScrim() { + return mBackgroundScrim; + } + /** * Returns whether the last task launched was in the freeform stack or not. */ @@ -566,17 +577,21 @@ public class RecentsView extends FrameLayout { RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); if (!launchState.launchedViaDockGesture && !launchState.launchedFromApp && mStack.getTaskCount() > 0) { - animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, + animateBackgroundScrim(1f, TaskStackAnimationHelper.ENTER_FROM_HOME_TRANSLATION_DURATION); } } - public final void onBusEvent(UpdateBackgroundScrimEvent event) { - animateBackgroundScrim(event.alpha, DEFAULT_UPDATE_SCRIM_DURATION); + public final void onBusEvent(AllTaskViewsDismissedEvent event) { + hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, true /* translate */); } - public final void onBusEvent(ResetBackgroundScrimEvent event) { - animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION); + public final void onBusEvent(DismissAllTaskViewsEvent event) { + SystemServicesProxy ssp = Recents.getSystemServices(); + if (!ssp.hasDockedTask()) { + // Animate the background away only if we are dismissing Recents to home + animateBackgroundScrim(0f, DEFAULT_UPDATE_SCRIM_DURATION); + } } public final void onBusEvent(ShowStackActionButtonEvent event) { @@ -584,7 +599,7 @@ public class RecentsView extends FrameLayout { return; } - showStackActionButton(150, event.translate); + showStackActionButton(SHOW_STACK_ACTION_BUTTON_DURATION, event.translate); } public final void onBusEvent(HideStackActionButtonEvent event) { @@ -592,7 +607,7 @@ public class RecentsView extends FrameLayout { return; } - hideStackActionButton(100, true /* translate */); + hideStackActionButton(HIDE_STACK_ACTION_BUTTON_DURATION, true /* translate */); } /** @@ -623,7 +638,6 @@ public class RecentsView extends FrameLayout { .alpha(1f) .setDuration(duration) .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .withLayer() .start(); } }); @@ -669,7 +683,6 @@ public class RecentsView extends FrameLayout { postAnimationTrigger.decrement(); } }) - .withLayer() .start(); postAnimationTrigger.increment(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java index 9c8189a216bd9..13ad9a5ee90d8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java @@ -24,6 +24,7 @@ import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent; +import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent; /** Manages the scrims for the various system bars. */ public class SystemBarScrimViews { @@ -107,4 +108,14 @@ public class SystemBarScrimViews { animateNavBarScrimVisibility(false, animation); } } + + public final void onBusEvent(DismissAllTaskViewsEvent event) { + if (mHasNavBarScrim) { + AnimationProps animation = new AnimationProps() + .setDuration(AnimationProps.BOUNDS, + TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION) + .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN); + animateNavBarScrimVisibility(false, animation); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java index 8db81f73f700e..1c433d8eb31c2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java @@ -31,6 +31,7 @@ import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.misc.ReferenceCountedTrigger; +import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; @@ -277,7 +278,6 @@ public class TaskStackAnimationHelper { public void startExitToHomeAnimation(boolean animated, ReferenceCountedTrigger postAnimationTrigger) { TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); - TaskStackViewScroller stackScroller = mStackView.getScroller(); TaskStack stack = mStackView.getStack(); // Break early if there are no tasks @@ -313,8 +313,7 @@ public class TaskStackAnimationHelper { taskAnimation = AnimationProps.IMMEDIATE; } - stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, - null); + mTmpTransform.fillIn(tv); mTmpTransform.alpha = 0f; mTmpTransform.rect.offset(0, offscreenYOffset); mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); @@ -328,8 +327,6 @@ public class TaskStackAnimationHelper { public void startLaunchTaskAnimation(TaskView launchingTaskView, boolean screenPinningRequested, final ReferenceCountedTrigger postAnimationTrigger) { Resources res = mStackView.getResources(); - TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); - TaskStackViewScroller stackScroller = mStackView.getScroller(); int taskViewExitToAppDuration = res.getInteger( R.integer.recents_task_exit_to_app_duration); @@ -362,8 +359,7 @@ public class TaskStackAnimationHelper { postAnimationTrigger.decrementOnAnimationEnd()); postAnimationTrigger.increment(); - stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, - null); + mTmpTransform.fillIn(tv); mTmpTransform.alpha = 0f; mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset); mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); @@ -374,16 +370,14 @@ public class TaskStackAnimationHelper { /** * Starts the delete animation for the specified {@link TaskView}. */ - public void startDeleteTaskAnimation(Task deleteTask, final TaskView deleteTaskView, + public void startDeleteTaskAnimation(final TaskView deleteTaskView, final ReferenceCountedTrigger postAnimationTrigger) { Resources res = mStackView.getResources(); TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); - TaskStackViewScroller stackScroller = mStackView.getScroller(); int taskViewRemoveAnimDuration = res.getInteger( R.integer.recents_animate_task_view_remove_duration); - int taskViewRemoveAnimTranslationXPx = res.getDimensionPixelSize( - R.dimen.recents_task_view_remove_anim_translation_x); + int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left; // Disabling clipping with the stack while the view is animating away, this will get // restored when the task is next picked up from the view pool @@ -399,13 +393,57 @@ public class TaskStackAnimationHelper { }); postAnimationTrigger.increment(); - stackLayout.getStackTransform(deleteTask, stackScroller.getStackScroll(), mTmpTransform, - null); + mTmpTransform.fillIn(deleteTaskView); mTmpTransform.alpha = 0f; - mTmpTransform.rect.offset(taskViewRemoveAnimTranslationXPx, 0); + mTmpTransform.rect.offset(offscreenXOffset, 0); mStackView.updateTaskViewToTransform(deleteTaskView, mTmpTransform, taskAnimation); } + /** + * Starts the delete animation for all the {@link TaskView}s. + */ + public void startDeleteAllTasksAnimation(final List taskViews, + final ReferenceCountedTrigger postAnimationTrigger) { + Resources res = mStackView.getResources(); + TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); + + int taskViewRemoveAnimDuration = res.getInteger( + R.integer.recents_animate_task_views_remove_all_duration); + int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left; + + int taskViewCount = taskViews.size(); + int startDelayMax = 125; + + for (int i = taskViewCount - 1; i >= 0; i--) { + TaskView tv = taskViews.get(i); + int indexFromFront = taskViewCount - i - 1; + float x = Interpolators.ACCELERATE.getInterpolation((float) indexFromFront / + taskViewCount); + int startDelay = (int) Utilities.mapRange(x, 0, startDelayMax); + + // Disabling clipping with the stack while the view is animating away + tv.setClipViewInStack(false); + + // Compose the new animation and transform and star the animation + AnimationProps taskAnimation = new AnimationProps(startDelay, + taskViewRemoveAnimDuration, Interpolators.FAST_OUT_LINEAR_IN, + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + postAnimationTrigger.decrement(); + + // Re-enable clipping with the stack (we will reuse this view) + tv.setClipViewInStack(true); + } + }); + postAnimationTrigger.increment(); + + mTmpTransform.fillIn(tv); + mTmpTransform.rect.offset(offscreenXOffset, 0); + mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); + } + } + /** * Starts the animation to focus the next {@link TaskView} when paging through recents. * diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index 4b1faf3ef3959..25083040df1d8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -557,15 +557,17 @@ public class TaskStackLayoutAlgorithm { mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP); mInitialNormX = null; } else { - float normX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP); - mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2)) - - Math.max(0, mUnfocusedRange.getAbsoluteX(normX))); + // We are overriding the initial two task positions, so set the initial scroll + // position to match the second task (aka focused task) position + float initialTopNormX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP); + mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2)) + - Math.max(0, mUnfocusedRange.getAbsoluteX(initialTopNormX))); // Set the initial scroll to the predefined state (which differs from the stack) mInitialNormX = new float[] { getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset, FROM_BOTTOM), - normX + initialTopNormX }; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 04f153fb79961..5416a4897666a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -72,6 +72,7 @@ import com.android.systemui.recents.events.activity.PackagesChangedEvent; import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent; import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent; import com.android.systemui.recents.events.ui.DeleteTaskDataEvent; +import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent; import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import com.android.systemui.recents.events.ui.TaskViewDismissedEvent; import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent; @@ -1322,7 +1323,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } // Update the stack action button visibility - if (mStackScroller.getStackScroll() < SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) { + if (mStackScroller.getStackScroll() < SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD && + mStack.getTaskCount() > 0) { EventBus.getDefault().send(new ShowStackActionButtonEvent(false /* translate */)); } else { EventBus.getDefault().send(new HideStackActionButtonEvent()); @@ -1446,6 +1448,26 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } + @Override + public void onStackTasksRemoved(TaskStack stack) { + // Reset the focused task + resetFocusedTask(getFocusedTask()); + + // Return all the views to the pool + List taskViews = new ArrayList<>(); + taskViews.addAll(getTaskViews()); + for (int i = taskViews.size() - 1; i >= 0; i--) { + mViewPool.returnViewToPool(taskViews.get(i)); + } + + // Remove all the ignore tasks + mIgnoreTasks.clear(); + + // If there are no remaining tasks, then just close recents + EventBus.getDefault().send(new AllTaskViewsDismissedEvent( + R.string.recents_empty_message_dismissed_all)); + } + @Override public void onStackTasksUpdated(TaskStack stack) { // Update the layout and immediately layout @@ -1597,7 +1619,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (mEnterAnimationComplete) { if (prevScroll > SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD && - curScroll <= SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) { + curScroll <= SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD && + mStack.getTaskCount() > 0) { EventBus.getDefault().send(new ShowStackActionButtonEvent(true /* translate */)); } else if (prevScroll < HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD && curScroll >= HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) { @@ -1705,14 +1728,42 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - public final void onBusEvent(final DismissTaskViewEvent event) { + public final void onBusEvent(DismissTaskViewEvent event) { // For visible children, defer removing the task until after the animation - mAnimationHelper.startDeleteTaskAnimation(event.task, event.taskView, - event.getAnimationTrigger()); + mAnimationHelper.startDeleteTaskAnimation(event.taskView, event.getAnimationTrigger()); + } + + public final void onBusEvent(final DismissAllTaskViewsEvent event) { + // Keep track of the tasks which will have their data removed + ArrayList tasks = new ArrayList<>(mStack.getStackTasks()); + mAnimationHelper.startDeleteAllTasksAnimation(getTaskViews(), event.getAnimationTrigger()); + event.addPostAnimationCallback(new Runnable() { + @Override + public void run() { + // Announce for accessibility + announceForAccessibility(getContext().getString( + R.string.accessibility_recents_all_items_dismissed)); + + // Remove all tasks and delete the task data for all tasks + mStack.removeAllTasks(); + for (int i = tasks.size() - 1; i >= 0; i--) { + EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i))); + } + + MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS_ALL); + } + }); + } public final void onBusEvent(TaskViewDismissedEvent event) { - removeTaskViewFromStack(event.taskView, event.task); + // Announce for accessibility + announceForAccessibility(getContext().getString( + R.string.accessibility_recents_item_dismissed, event.task.title)); + + // Remove the task from the stack + mStack.removeTask(event.task, new AnimationProps(DEFAULT_SYNC_STACK_DURATION, + Interpolators.FAST_OUT_SLOW_IN), false /* fromDockGesture */); EventBus.getDefault().send(new DeleteTaskDataEvent(event.task)); MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS, @@ -1948,27 +1999,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - // Trigger a new layout and scroll to the initial state - mInitialState = event.fromMultiWindow - ? INITIAL_STATE_UPDATE_ALL - : INITIAL_STATE_UPDATE_LAYOUT_ONLY; + // Trigger a new layout and update to the initial state if necessary + if (event.fromMultiWindow) { + mInitialState = INITIAL_STATE_UPDATE_ALL; + } else if (event.fromOrientationChange) { + mInitialState = INITIAL_STATE_UPDATE_LAYOUT_ONLY; + } requestLayout(); } - /** - * Removes the task from the stack, and updates the focus to the next task in the stack if the - * removed TaskView was focused. - */ - private void removeTaskViewFromStack(TaskView tv, Task task) { - // Announce for accessibility - tv.announceForAccessibility(getContext().getString( - R.string.accessibility_recents_item_dismissed, task.title)); - - // Remove the task from the stack - mStack.removeTask(task, new AnimationProps(DEFAULT_SYNC_STACK_DURATION, - Interpolators.FAST_OUT_SLOW_IN), false /* fromDockGesture */); - } - /** * Starts an alpha animation on the freeform workspace background. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index aed19c3e0b9a5..ee0de1ad05dfd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -356,6 +356,11 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { return; } + // Disallow tapping above and below the stack to dismiss recents + if (x > mSv.mLayoutAlgorithm.mStackRect.left && x < mSv.mLayoutAlgorithm.mStackRect.right) { + return; + } + // If tapping on the freeform workspace background, just launch the first freeform task SystemServicesProxy ssp = Recents.getSystemServices(); if (ssp.hasFreeformWorkspaceSupport()) { @@ -507,13 +512,13 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { tv.setClipViewInStack(true); // Re-enable touch events from this task view tv.setTouchEnabled(true); + // Remove the task view from the stack + EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv)); // Update the scroll to the final scroll position from onBeginDrag() mSv.getScroller().setStackScroll(mTargetStackScroll, null); // Update the focus state to the final focus state mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED); mSv.getStackAlgorithm().clearUnfocusedTaskOverrides(); - // Remove the task view from the stack - EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv)); // Stop tracking this deletion animation mSwipeHelperAnimations.remove(v); // Keep track of deletions by keyboard diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index c085d8092a1ff..f8ed7008d9126 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -384,7 +384,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks void dismissTask() { // Animate out the view and call the callback final TaskView tv = this; - DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv, mTask); + DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv); dismissEvent.addPostAnimationCallback(new Runnable() { @Override public void run() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java index dc76e61c0d1e9..b512393304c3c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java @@ -226,4 +226,9 @@ public class TaskViewTransform { v.getViewBounds().setClipBottom(0); v.setLeftTopRightBottom(0, 0, 0, 0); } + + @Override + public String toString() { + return "R: " + rect + " V: " + visible; + } } diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index d6f1499ef6847..a2cfae9f3f118 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -2017,6 +2017,9 @@ message MetricsEvent { // action pass package name of calling package. ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_AND_PERSIST_BY_PACKAGE = 356; + // Logged when a user dismisses all task in overview + OVERVIEW_DISMISS_ALL = 357; + // Add new aosp constants above this line. // END OF AOSP CONSTANTS }