Better handling transparent activities
> Only hiding the task associated with the current task, instead of hiding all tasks
> Maintaining a state for hidden task so that it does not get reset when alpha is changed due
to some other reason.
Bug: 77830202
Change-Id: I202e99b153c6f9e3a8d9c68d6844672b3bff41e9
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 41f5bb8..8e2f2f1 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 28c950b..f7e45d3 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -23,6 +23,7 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_STEP_DRAG_SLOP_PX;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
@@ -45,6 +46,7 @@
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.AssistDataReceiver;
import com.android.systemui.shared.system.BackgroundExecutor;
@@ -229,8 +231,9 @@
Rect minimizedHomeBounds) {
if (mInteractionHandler == handler) {
TraceHelper.partitionSection("RecentsController", "Received");
- handler.onRecentsAnimationStart(controller, apps, homeContentInsets,
- minimizedHomeBounds);
+ handler.onRecentsAnimationStart(controller,
+ new RemoteAnimationTargetSet(apps, MODE_CLOSING),
+ homeContentInsets, minimizedHomeBounds);
} else {
TraceHelper.endSection("RecentsController", "Finishing no handler");
controller.finish(false /* toHome */);
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 5563aed..663a005 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -53,6 +53,7 @@
import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.util.SysuiEventLogger;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -279,15 +280,13 @@
return anim;
}
- RemoteAnimationTargetCompat closingTarget = null;
+ RemoteAnimationTargetSet targetSet =
+ new RemoteAnimationTargetSet(targetCompats, MODE_CLOSING);
+
+
// Use the top closing app to determine the insets for the animation
- for (RemoteAnimationTargetCompat target : targetCompats) {
- if (target.mode == MODE_CLOSING) {
- closingTarget = target;
- break;
- }
- }
- if (closingTarget == null) {
+ RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
+ if (runningTaskTarget == null) {
Log.e(TAG, "No closing app");
anim.play(ValueAnimator.ofInt(0, 1).setDuration(100));
return anim;
@@ -302,20 +301,18 @@
rootView.getLocationOnScreen(loc);
Rect homeBounds = new Rect(loc[0], loc[1],
loc[0] + rootView.getWidth(), loc[1] + rootView.getHeight());
- clipHelper.updateSource(homeBounds, closingTarget);
+ clipHelper.updateSource(homeBounds, runningTaskTarget);
Rect targetRect = new Rect();
mHelper.getSwipeUpDestinationAndLength(
mActivity.getDeviceProfile(), mActivity, targetRect);
clipHelper.updateTargetRect(targetRect);
-
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(RECENTS_LAUNCH_DURATION);
valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
- valueAnimator.addUpdateListener((v) -> {
- clipHelper.applyTransform(targetCompats, (float) v.getAnimatedValue());
- });
+ valueAnimator.addUpdateListener((v) ->
+ clipHelper.applyTransform(targetSet, (float) v.getAnimatedValue()));
anim.play(valueAnimator);
return anim;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
index 12f8d52..ebe2311 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -16,9 +16,9 @@
package com.android.quickstep;
import com.android.launcher3.util.TraceHelper;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
-import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
/**
* Wrapper around RecentsAnimationController to help with some synchronization
@@ -26,17 +26,17 @@
public class RecentsAnimationWrapper {
public RecentsAnimationControllerCompat controller;
- public RemoteAnimationTargetCompat[] targets;
+ public RemoteAnimationTargetSet targetSet;
private boolean mInputConsumerEnabled = false;
private boolean mBehindSystemBars = true;
private boolean mSplitScreenMinimized = false;
public synchronized void setController(
- RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] targets) {
+ RecentsAnimationControllerCompat controller, RemoteAnimationTargetSet targetSet) {
TraceHelper.partitionSection("RecentsController", "Set controller " + controller);
this.controller = controller;
- this.targets = targets;
+ this.targetSet = targetSet;
if (mInputConsumerEnabled) {
enableInputConsumer();
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index ce16adf..2709523 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -24,7 +24,6 @@
import static com.android.systemui.shared.recents.utilities.Utilities
.postAtFrontOfQueueAsynchronously;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.animation.Animator;
import android.animation.ObjectAnimator;
@@ -48,9 +47,9 @@
import android.view.animation.Interpolator;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
@@ -67,6 +66,7 @@
import com.android.quickstep.ActivityControlHelper.LayoutListener;
import com.android.quickstep.TouchConsumer.InteractionType;
import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.util.SysuiEventLogger;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -76,7 +76,6 @@
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowCallbacksCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -347,6 +346,7 @@
}
mRecentsView.showTask(mRunningTaskId);
+ mRecentsView.setRunningTaskHidden(true);
mRecentsView.setFirstTaskIconScaledDown(true /* isScaledDown */, false /* animate */);
mLayoutListener.open();
mStateCallback.setState(STATE_LAUNCHER_STARTED);
@@ -436,7 +436,8 @@
Interpolator interpolator = mInteractionType == INTERACTION_QUICK_SCRUB
? ACCEL_2 : LINEAR;
float interpolated = interpolator.getInterpolation(shift);
- mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targets, interpolated);
+ mClipAnimationHelper.applyTransform(
+ mRecentsAnimationWrapper.targetSet, interpolated);
}
}
@@ -478,36 +479,37 @@
}
public void onRecentsAnimationStart(RecentsAnimationControllerCompat controller,
- RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, Rect minimizedHomeBounds) {
- if (apps != null) {
- // Use the top closing app to determine the insets for the animation
- for (RemoteAnimationTargetCompat target : apps) {
- if (target.mode == MODE_CLOSING) {
- DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
- final Rect overviewStackBounds;
+ RemoteAnimationTargetSet targets, Rect homeContentInsets, Rect minimizedHomeBounds) {
+ LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
+ InvariantDeviceProfile idp = appState == null ?
+ new InvariantDeviceProfile(mContext) : appState.getInvariantDeviceProfile();
+ DeviceProfile dp = idp.getDeviceProfile(mContext);
+ final Rect overviewStackBounds;
+ RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(mRunningTaskId);
- if (minimizedHomeBounds != null) {
- overviewStackBounds = mActivityControlHelper
- .getOverviewWindowBounds(minimizedHomeBounds, target);
- dp = dp.getMultiWindowProfile(mContext,
- new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height()));
- dp.updateInsets(homeContentInsets);
- } else {
- overviewStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx);
- // TODO: Workaround for an existing issue where the home content insets are
- // not valid immediately after rotation, just use the stable insets for now
- Rect insets = new Rect();
- WindowManagerWrapper.getInstance().getStableInsets(insets);
- dp = dp.copy(mContext);
- dp.updateInsets(insets);
- }
-
- mClipAnimationHelper.updateSource(overviewStackBounds, target);
- initTransitionEndpoints(dp);
- }
- }
+ if (minimizedHomeBounds != null && runningTaskTarget != null) {
+ overviewStackBounds = mActivityControlHelper
+ .getOverviewWindowBounds(minimizedHomeBounds, runningTaskTarget);
+ dp = dp.getMultiWindowProfile(mContext,
+ new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height()));
+ dp.updateInsets(homeContentInsets);
+ } else {
+ overviewStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx);
+ // TODO: Workaround for an existing issue where the home content insets are
+ // not valid immediately after rotation, just use the stable insets for now
+ Rect insets = new Rect();
+ WindowManagerWrapper.getInstance().getStableInsets(insets);
+ dp = dp.copy(mContext);
+ dp.updateInsets(insets);
}
- mRecentsAnimationWrapper.setController(controller, apps);
+
+ if (runningTaskTarget != null) {
+ mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
+ }
+ initTransitionEndpoints(dp);
+
+
+ mRecentsAnimationWrapper.setController(controller, targets);
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
@@ -641,6 +643,7 @@
mLauncherTransitionController = null;
mLayoutListener.finish();
+ mRecentsView.setRunningTaskHidden(false);
mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, false /* animate */);
}
@@ -666,29 +669,22 @@
synchronized (mRecentsAnimationWrapper) {
if (mRecentsAnimationWrapper.controller != null) {
- for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
- if (app.mode == MODE_CLOSING) {
- // Update the screenshot of the task
- ThumbnailData thumbnail =
- mRecentsAnimationWrapper.controller.screenshotTask(app.taskId);
- final TaskView taskView =
- mRecentsView.updateThumbnail(app.taskId, thumbnail);
- if (taskView != null) {
- taskView.setAlpha(1);
+ // Update the screenshot of the task
+ ThumbnailData thumbnail =
+ mRecentsAnimationWrapper.controller.screenshotTask(mRunningTaskId);
+ final TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, thumbnail);
+ mRecentsView.setRunningTaskHidden(false);
+ if (taskView != null) {
+ // Defer finishing the animation until the next launcher frame with the
+ // new thumbnail
+ finishTransitionPosted = new WindowCallbacksCompat(taskView) {
- // Defer finishing the animation until the next launcher frame with the
- // new thumbnail
- finishTransitionPosted = new WindowCallbacksCompat(taskView) {
-
- @Override
- public void onPostDraw(Canvas canvas) {
- finishTransitionRunnable.run();
- detach();
- }
- }.attach();
- break;
+ @Override
+ public void onPostDraw(Canvas canvas) {
+ finishTransitionRunnable.run();
+ detach();
}
- }
+ }.attach();
}
}
}
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index 493e9e2..9276d238 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -15,8 +15,6 @@
*/
package com.android.quickstep.util;
-import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
-
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.Rect;
@@ -55,10 +53,9 @@
private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
private final Matrix mTmpMatrix = new Matrix();
-
public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
mHomeStackBounds.set(homeStackBounds);
- mSourceInsets.set(target.getContentInsets());
+ mSourceInsets.set(target.contentInsets);
mSourceStackBounds.set(target.sourceContainerBounds);
// TODO: Should sourceContainerBounds already have this offset?
@@ -91,7 +88,7 @@
mSourceRect.set(scaledTargetRect);
}
- public void applyTransform(RemoteAnimationTargetCompat[] targets, float progress) {
+ public void applyTransform(RemoteAnimationTargetSet targetSet, float progress) {
RectF currentRect;
synchronized (mTargetRect) {
currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
@@ -109,17 +106,14 @@
mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
TransactionCompat transaction = new TransactionCompat();
- for (RemoteAnimationTargetCompat app : targets) {
- if (app.mode == MODE_CLOSING) {
- mTmpMatrix.postTranslate(app.position.x, app.position.y);
- transaction.setMatrix(app.leash, mTmpMatrix)
- .setWindowCrop(app.leash, mClipRect);
- if (app.isNotInRecents) {
- transaction.setAlpha(app.leash, 1 - progress);
- }
-
- transaction.show(app.leash);
+ for (RemoteAnimationTargetCompat app : targetSet.apps) {
+ mTmpMatrix.postTranslate(app.position.x, app.position.y);
+ transaction.setMatrix(app.leash, mTmpMatrix)
+ .setWindowCrop(app.leash, mClipRect);
+ if (app.isNotInRecents) {
+ transaction.setAlpha(app.leash, 1 - progress);
}
+ transaction.show(app.leash);
}
transaction.setEarlyWakeup();
transaction.apply();
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
new file mode 100644
index 0000000..fc889e5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.quickstep.util;
+
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+
+import java.util.ArrayList;
+
+/**
+ * Holds a collection of RemoteAnimationTargets, filtered by different properties.
+ */
+public class RemoteAnimationTargetSet {
+
+ public final boolean allTransparent;
+ public final RemoteAnimationTargetCompat[] apps;
+
+ public RemoteAnimationTargetSet(RemoteAnimationTargetCompat[] apps, int targetMode) {
+ boolean allTransparent = true;
+
+ ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
+ if (apps != null) {
+ for (RemoteAnimationTargetCompat target : apps) {
+ if (target.mode == targetMode) {
+ allTransparent &= target.isTranslucent;
+ filteredApps.add(target);
+ }
+ }
+ }
+
+ this.allTransparent = allTransparent;
+ this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]);
+ }
+
+ public RemoteAnimationTargetCompat findTask(int taskId) {
+ for (RemoteAnimationTargetCompat target : apps) {
+ if (target.taskId == taskId) {
+ return target;
+ }
+ }
+ return null;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index a3f10f0..2e70e45 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -160,6 +160,7 @@
// Only valid until the launcher state changes to NORMAL
private int mRunningTaskId = -1;
+ private boolean mRunningTaskTileHidden;
private Task mTmpRunningTask;
private boolean mFirstTaskIconScaledDown = false;
@@ -238,14 +239,11 @@
}
public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) {
- for (int i = 0; i < getChildCount(); i++) {
- final TaskView taskView = (TaskView) getChildAt(i);
- if (taskView.getTask().key.id == taskId) {
- taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
- return taskView;
- }
+ TaskView taskView = getTaskView(taskId);
+ if (taskView != null) {
+ taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
}
- return null;
+ return taskView;
}
@Override
@@ -387,6 +385,9 @@
taskView.resetVisualProperties();
}
}
+ if (mRunningTaskTileHidden) {
+ setRunningTaskHidden(mRunningTaskTileHidden);
+ }
updateCurveProperties();
// Update the set of visible task's data
@@ -524,8 +525,10 @@
protected abstract void onAllTasksRemoved();
public void reset() {
- unloadVisibleTaskData();
mRunningTaskId = -1;
+ mRunningTaskTileHidden = false;
+
+ unloadVisibleTaskData();
setCurrentPage(0);
OverviewCallbacks.get(getContext()).onResetOverview();
@@ -562,12 +565,17 @@
new ActivityManager.TaskDescription(), 0, new ComponentName("", ""), false);
taskView.bind(mTmpRunningTask);
}
- setCurrentTask(mRunningTaskId);
+ setCurrentTask(runningTaskId);
+ }
- // Hide the task that we are animating into, ignore if there is no associated task (ie. the
- // assistant)
- if (getPageAt(mCurrentPage) != null) {
- getPageAt(mCurrentPage).setAlpha(0);
+ /**
+ * Hides the tile associated with {@link #mRunningTaskId}
+ */
+ public void setRunningTaskHidden(boolean isHidden) {
+ mRunningTaskTileHidden = isHidden;
+ TaskView runningTask = getTaskView(mRunningTaskId);
+ if (runningTask != null) {
+ runningTask.setAlpha(isHidden ? 0 : mContentAlpha);
}
}
@@ -575,7 +583,13 @@
* Similar to {@link #showTask(int)} but does not put any restrictions on the first tile.
*/
public void setCurrentTask(int runningTaskId) {
- mRunningTaskId = runningTaskId;
+ if (mRunningTaskTileHidden) {
+ setRunningTaskHidden(false);
+ mRunningTaskId = runningTaskId;
+ setRunningTaskHidden(true);
+ } else {
+ mRunningTaskId = runningTaskId;
+ }
setCurrentPage(0);
// Load the tasks (if the loading is already
@@ -837,7 +851,10 @@
mContentAlpha = alpha;
for (int i = getChildCount() - 1; i >= 0; i--) {
- getChildAt(i).setAlpha(alpha);
+ TaskView child = getPageAt(i);
+ if (!mRunningTaskTileHidden || child.getTask().key.id != mRunningTaskId) {
+ getChildAt(i).setAlpha(alpha);
+ }
}
int alphaInt = Math.round(alpha * 255);