Merge "Using TaskViewSimulator for animating task launch" into ub-launcher3-rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
32f6cd1116
+6
-4
@@ -19,8 +19,8 @@ package com.android.launcher3;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
|
||||
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
|
||||
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -34,6 +34,7 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
@@ -63,9 +64,10 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
|
||||
boolean skipLauncherChanges = !launcherClosing;
|
||||
|
||||
TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
|
||||
Animator recentsAnimator = getRecentsWindowAnimator(taskView, skipLauncherChanges,
|
||||
appTargets, wallpaperTargets, mLauncher.getDepthController());
|
||||
anim.play(recentsAnimator.setDuration(RECENTS_LAUNCH_DURATION));
|
||||
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
|
||||
createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
|
||||
mLauncher.getDepthController(), pa);
|
||||
anim.play(pa.buildAnim());
|
||||
|
||||
Animator childStateAnimation = null;
|
||||
// Found a visible recents task that matches the opening app, lets launch the app from there
|
||||
|
||||
@@ -23,7 +23,7 @@ import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR
|
||||
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_PRE_DELAY;
|
||||
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
|
||||
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
|
||||
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
|
||||
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
|
||||
|
||||
import android.animation.Animator;
|
||||
@@ -44,6 +44,7 @@ import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.LauncherAnimationRunner;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
|
||||
@@ -225,9 +226,10 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets) {
|
||||
AnimatorSet target = new AnimatorSet();
|
||||
boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING);
|
||||
Animator recentsAnimator = getRecentsWindowAnimator(taskView, !activityClosing, appTargets,
|
||||
wallpaperTargets, null /* depthController */);
|
||||
target.play(recentsAnimator.setDuration(RECENTS_LAUNCH_DURATION));
|
||||
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
|
||||
createRecentsWindowAnimator(taskView, !activityClosing, appTargets,
|
||||
wallpaperTargets, null /* depthController */, pa);
|
||||
target.play(pa.buildAnim());
|
||||
|
||||
// Found a visible recents task that matches the opening app, lets launch the app from there
|
||||
if (activityClosing) {
|
||||
|
||||
@@ -15,44 +15,46 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
|
||||
import static com.android.launcher3.anim.Interpolators.clampToProgress;
|
||||
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
|
||||
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Matrix.ScaleToFit;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.BaseActivity;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.statehandlers.DepthController;
|
||||
import com.android.quickstep.util.AppWindowAnimationHelper;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.launcher3.util.DefaultDisplay;
|
||||
import com.android.quickstep.util.TaskViewSimulator;
|
||||
import com.android.quickstep.util.TransformParams;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskThumbnailView;
|
||||
import com.android.quickstep.views.TaskView;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.R)
|
||||
public final class TaskViewUtils {
|
||||
|
||||
private TaskViewUtils() {}
|
||||
@@ -118,97 +120,116 @@ public final class TaskViewUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Animator that controls the window of the opening targets for the recents launch
|
||||
* Creates an animation that controls the window of the opening targets for the recents launch
|
||||
* animation.
|
||||
*/
|
||||
public static Animator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
|
||||
public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
|
||||
RemoteAnimationTargetCompat[] appTargets,
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets,
|
||||
DepthController depthController) {
|
||||
AppWindowAnimationHelper inOutHelper = new AppWindowAnimationHelper(
|
||||
v.getRecentsView().getPagedViewOrientedState(), v.getContext());
|
||||
RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
|
||||
PendingAnimation out) {
|
||||
|
||||
SyncRtSurfaceTransactionApplierCompat applier =
|
||||
new SyncRtSurfaceTransactionApplierCompat(v);
|
||||
final RemoteAnimationTargets targets =
|
||||
new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
|
||||
targets.addDependentTransactionApplier(applier);
|
||||
TransformParams params =
|
||||
new TransformParams()
|
||||
|
||||
TransformParams params = new TransformParams()
|
||||
.setSyncTransactionApplier(applier)
|
||||
.setTargetSet(targets);
|
||||
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
final RecentsView recentsView = v.getRecentsView();
|
||||
final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
|
||||
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
int taskIndex = recentsView.indexOfChild(v);
|
||||
boolean parallaxCenterAndAdjacentTask = taskIndex != recentsView.getCurrentPage();
|
||||
int startScroll = recentsView.getScrollOffset(taskIndex);
|
||||
|
||||
// Defer fading out the view until after the app window gets faded in
|
||||
final FloatProp mViewAlpha = new FloatProp(1f, 0f, 75, 75, LINEAR);
|
||||
final FloatProp mTaskAlpha = new FloatProp(0f, 1f, 0, 75, LINEAR);
|
||||
final RectF mThumbnailRect;
|
||||
params.setProgress(1);
|
||||
out.setFloat(params, TransformParams.PROGRESS, 0, TOUCH_RESPONSE_INTERPOLATOR);
|
||||
|
||||
{
|
||||
params.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
|
||||
inOutHelper.prepareAnimation(
|
||||
BaseActivity.fromContext(v.getContext()).getDeviceProfile());
|
||||
inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
|
||||
targets.apps.length == 0 ? null : targets.apps[0]);
|
||||
Context context = v.getContext();
|
||||
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
|
||||
// RecentsView never updates the display rotation until swipe-up so the value may be stale.
|
||||
// Use the display value instead.
|
||||
int displayRotation = DefaultDisplay.INSTANCE.get(context).getInfo().rotation;
|
||||
|
||||
mThumbnailRect = new RectF(inOutHelper.getTargetRect());
|
||||
mThumbnailRect.offset(-v.getTranslationX(), -v.getTranslationY());
|
||||
Utilities.scaleRectFAboutCenter(mThumbnailRect, 1 / v.getScaleX());
|
||||
}
|
||||
TaskViewSimulator topMostSimulator = null;
|
||||
if (targets.apps.length > 0) {
|
||||
TaskViewSimulator tsv = new TaskViewSimulator(context, recentsView.getSizeStrategy());
|
||||
tsv.setDp(dp);
|
||||
tsv.setLayoutRotation(displayRotation, displayRotation);
|
||||
tsv.setPreview(targets.apps[targets.apps.length - 1]);
|
||||
tsv.fullScreenProgress.value = 0;
|
||||
tsv.recentsViewScale.value = 1;
|
||||
tsv.setScroll(startScroll);
|
||||
|
||||
@Override
|
||||
public void onUpdate(float percent) {
|
||||
// TODO: Take into account the current fullscreen progress for animating the insets
|
||||
params.setProgress(1 - percent);
|
||||
RectF taskBounds;
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
List<SurfaceParams> surfaceParamsList = new ArrayList<>();
|
||||
// Append the surface transform params for the app that's being opened.
|
||||
Collections.addAll(surfaceParamsList, inOutHelper.computeSurfaceParams(params));
|
||||
out.setFloat(tsv.fullScreenProgress,
|
||||
AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
|
||||
out.setFloat(tsv.recentsViewScale,
|
||||
AnimatedFloat.VALUE, tsv.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
|
||||
out.setInt(tsv, TaskViewSimulator.SCROLL, 0, TOUCH_RESPONSE_INTERPOLATOR);
|
||||
|
||||
AppWindowAnimationHelper liveTileAnimationHelper =
|
||||
v.getRecentsView().getClipAnimationHelper();
|
||||
if (liveTileAnimationHelper != null) {
|
||||
// Append the surface transform params for the live tile app.
|
||||
TransformParams liveTileParams =
|
||||
v.getRecentsView().getLiveTileParams(true /* mightNeedToRefill */);
|
||||
if (liveTileParams != null) {
|
||||
SurfaceParams[] liveTileSurfaceParams =
|
||||
liveTileAnimationHelper.computeSurfaceParams(liveTileParams);
|
||||
if (liveTileSurfaceParams != null) {
|
||||
Collections.addAll(surfaceParamsList, liveTileSurfaceParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Apply surface transform using the surface params list.
|
||||
params.applySurfaceParams(
|
||||
surfaceParamsList.toArray(new SurfaceParams[surfaceParamsList.size()]));
|
||||
// Get the task bounds for the app that's being opened after surface transform
|
||||
// update.
|
||||
taskBounds = inOutHelper.updateCurrentRect(params);
|
||||
} else {
|
||||
taskBounds = inOutHelper.applyTransform(params);
|
||||
out.addOnFrameCallback(() -> tsv.apply(params));
|
||||
topMostSimulator = tsv;
|
||||
}
|
||||
|
||||
// Fade in the task during the initial 20% of the animation
|
||||
AnimatedFloat taskAlpha = new AnimatedFloat(() -> { });
|
||||
params.setTaskAlphaCallback((t, alpha) -> taskAlpha.value);
|
||||
out.addFloat(taskAlpha, AnimatedFloat.VALUE, 0, 1, clampToProgress(LINEAR, 0, 0.2f));
|
||||
|
||||
if (!skipViewChanges && parallaxCenterAndAdjacentTask && topMostSimulator != null) {
|
||||
out.addFloat(v, VIEW_ALPHA, 1, 0, clampToProgress(LINEAR, 0.2f, 0.4f));
|
||||
|
||||
TaskViewSimulator simulatorToCopy = topMostSimulator;
|
||||
simulatorToCopy.apply(params);
|
||||
|
||||
// Mt represents the overall transformation on the thumbnailView relative to the
|
||||
// Launcher's rootView
|
||||
// K(t) represents transformation on the running window by the taskViewSimulator at
|
||||
// any time t.
|
||||
// at t = 0, we know that the simulator matches the thumbnailView. So if we apply K(0)`
|
||||
// on the Launcher's rootView, the thumbnailView would match the full running task
|
||||
// window. If we apply "K(0)` K(t)" thumbnailView will match the final transformed
|
||||
// window at any time t. This gives the overall matrix on thumbnailView to be:
|
||||
// Mt K(0)` K(t)
|
||||
// During animation we apply transformation on the thumbnailView (and not the rootView)
|
||||
// to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
|
||||
// Mt K(0)` K(t) Mt`
|
||||
TaskThumbnailView ttv = v.getThumbnail();
|
||||
RectF tvBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight());
|
||||
float[] tvBoundsMapped = new float[]{0, 0, ttv.getWidth(), ttv.getHeight()};
|
||||
getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
|
||||
RectF tvBoundsInRoot = new RectF(
|
||||
tvBoundsMapped[0], tvBoundsMapped[1],
|
||||
tvBoundsMapped[2], tvBoundsMapped[3]);
|
||||
|
||||
Matrix mt = new Matrix();
|
||||
mt.setRectToRect(tvBounds, tvBoundsInRoot, ScaleToFit.FILL);
|
||||
|
||||
Matrix mti = new Matrix();
|
||||
mt.invert(mti);
|
||||
|
||||
Matrix k0i = new Matrix();
|
||||
simulatorToCopy.getCurrentMatrix().invert(k0i);
|
||||
|
||||
Matrix animationMatrix = new Matrix();
|
||||
out.addOnFrameCallback(() -> {
|
||||
animationMatrix.set(mt);
|
||||
animationMatrix.postConcat(k0i);
|
||||
animationMatrix.postConcat(simulatorToCopy.getCurrentMatrix());
|
||||
animationMatrix.postConcat(mti);
|
||||
ttv.setAnimationMatrix(animationMatrix);
|
||||
});
|
||||
|
||||
out.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
ttv.setAnimationMatrix(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int taskIndex = recentsView.indexOfChild(v);
|
||||
int centerTaskIndex = recentsView.getCurrentPage();
|
||||
boolean parallaxCenterAndAdjacentTask = taskIndex != centerTaskIndex;
|
||||
if (!skipViewChanges && parallaxCenterAndAdjacentTask) {
|
||||
float scale = taskBounds.width() / mThumbnailRect.width();
|
||||
v.setScaleX(scale);
|
||||
v.setScaleY(scale);
|
||||
v.setTranslationX(taskBounds.centerX() - mThumbnailRect.centerX());
|
||||
v.setTranslationY(taskBounds.centerY() - mThumbnailRect.centerY());
|
||||
v.setAlpha(mViewAlpha.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
appAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
out.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
targets.release();
|
||||
@@ -216,12 +237,8 @@ public final class TaskViewUtils {
|
||||
});
|
||||
|
||||
if (depthController != null) {
|
||||
ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController,
|
||||
DEPTH, BACKGROUND_APP.getDepth(v.getContext()));
|
||||
animatorSet.playTogether(appAnimator, backgroundRadiusAnim);
|
||||
} else {
|
||||
animatorSet.play(appAnimator);
|
||||
out.setFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(context),
|
||||
TOUCH_RESPONSE_INTERPOLATOR);
|
||||
}
|
||||
return animatorSet;
|
||||
}
|
||||
}
|
||||
|
||||
-294
@@ -1,294 +0,0 @@
|
||||
/*
|
||||
* 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 static com.android.launcher3.Utilities.boundToRange;
|
||||
import static com.android.launcher3.Utilities.mapRange;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Matrix.ScaleToFit;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.TaskThumbnailView;
|
||||
import com.android.systemui.shared.recents.utilities.RectFEvaluator;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
|
||||
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
|
||||
import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
|
||||
/**
|
||||
* Utility class to handle window clip animation
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.P)
|
||||
public class AppWindowAnimationHelper implements TransformParams.BuilderProxy {
|
||||
|
||||
// The bounds of the source app in device coordinates
|
||||
private final RectF mSourceStackBounds = new RectF();
|
||||
// The insets of the source app
|
||||
private final Rect mSourceInsets = new Rect();
|
||||
// The source app bounds with the source insets applied, in the device coordinates
|
||||
private final RectF mSourceRect = new RectF();
|
||||
// The bounds of the task view in device coordinates
|
||||
private final RectF mTargetRect = new RectF();
|
||||
// The bounds of the app window (between mSourceRect and mTargetRect) in device coordinates
|
||||
private final RectF mCurrentRect = new RectF();
|
||||
// The insets to be used for clipping the app window, which can be larger than mSourceInsets
|
||||
// if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
|
||||
// app window coordinates.
|
||||
private final RectF mSourceWindowClipInsets = new RectF();
|
||||
// The clip rect in source app window coordinates. The app window surface will only be drawn
|
||||
// within these bounds. This clip rect starts at the full mSourceStackBounds, and insets by
|
||||
// mSourceWindowClipInsets as the transform progress goes to 1.
|
||||
private final RectF mCurrentClipRectF = new RectF();
|
||||
|
||||
// The bounds of launcher (not including insets) in device coordinates
|
||||
public final Rect mHomeStackBounds = new Rect();
|
||||
private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
|
||||
private final Matrix mTmpMatrix = new Matrix();
|
||||
private final Rect mTmpRect = new Rect();
|
||||
private final RectF mTmpRectF = new RectF();
|
||||
private RecentsOrientedState mOrientedState;
|
||||
// Corner radius of windows, in pixels
|
||||
private final float mWindowCornerRadius;
|
||||
// Corner radius of windows when they're in overview mode.
|
||||
private final float mTaskCornerRadius;
|
||||
// If windows can have real time rounded corners.
|
||||
private final boolean mSupportsRoundedCornersOnWindows;
|
||||
// Whether or not to actually use the rounded cornders on windows
|
||||
private boolean mUseRoundedCornersOnWindows;
|
||||
|
||||
public AppWindowAnimationHelper(RecentsOrientedState orientedState, Context context) {
|
||||
Resources res = context.getResources();
|
||||
mOrientedState = orientedState;
|
||||
mWindowCornerRadius = getWindowCornerRadius(res);
|
||||
mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(res);
|
||||
mTaskCornerRadius = TaskCornerRadius.get(context);
|
||||
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows;
|
||||
}
|
||||
|
||||
private void updateSourceStack(RemoteAnimationTargetCompat target) {
|
||||
mSourceInsets.set(target.contentInsets);
|
||||
mSourceStackBounds.set(target.screenSpaceBounds);
|
||||
}
|
||||
|
||||
public void updateTargetRect(Rect targetRect) {
|
||||
mSourceRect.set(mSourceInsets.left, mSourceInsets.top,
|
||||
mSourceStackBounds.width() - mSourceInsets.right,
|
||||
mSourceStackBounds.height() - mSourceInsets.bottom);
|
||||
mTargetRect.set(targetRect);
|
||||
mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
|
||||
mHomeStackBounds.top - mSourceStackBounds.top);
|
||||
|
||||
// Calculate the clip based on the target rect (since the content insets and the
|
||||
// launcher insets may differ, so the aspect ratio of the target rect can differ
|
||||
// from the source rect. The difference between the target rect (scaled to the
|
||||
// source rect) is the amount to clip on each edge.
|
||||
RectF scaledTargetRect = new RectF(mTargetRect);
|
||||
float scale = getSrcToTargetScale();
|
||||
Utilities.scaleRectFAboutCenter(scaledTargetRect, scale);
|
||||
|
||||
scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top);
|
||||
mSourceWindowClipInsets.set(
|
||||
Math.max(scaledTargetRect.left, 0),
|
||||
Math.max(scaledTargetRect.top, 0),
|
||||
Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0),
|
||||
Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0));
|
||||
mSourceRect.set(scaledTargetRect);
|
||||
}
|
||||
|
||||
public float getSrcToTargetScale() {
|
||||
return LayoutUtils.getTaskScale(mOrientedState,
|
||||
mSourceRect.width(), mSourceRect.height(),
|
||||
mTargetRect.width(), mTargetRect.height());
|
||||
}
|
||||
|
||||
public void prepareAnimation(DeviceProfile dp) {
|
||||
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows && !dp.isMultiWindowMode;
|
||||
}
|
||||
|
||||
public RectF applyTransform(TransformParams params) {
|
||||
SurfaceParams[] surfaceParams = computeSurfaceParams(params);
|
||||
if (surfaceParams == null) {
|
||||
return null;
|
||||
}
|
||||
params.applySurfaceParams(surfaceParams);
|
||||
return mCurrentRect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates this AppWindowAnimationHelper's state based on the given TransformParams, and returns
|
||||
* the SurfaceParams to apply via {@link SyncRtSurfaceTransactionApplierCompat#applyParams}.
|
||||
*/
|
||||
public SurfaceParams[] computeSurfaceParams(TransformParams params) {
|
||||
if (params.getTargetSet() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
updateCurrentRect(params);
|
||||
return params.createSurfaceParams(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app,
|
||||
int targetMode, TransformParams params) {
|
||||
Rect crop = mTmpRect;
|
||||
crop.set(app.screenSpaceBounds);
|
||||
crop.offsetTo(0, 0);
|
||||
float cornerRadius = 0f;
|
||||
float scale = Math.max(mCurrentRect.width(), mTargetRect.width()) / crop.width();
|
||||
mTmpMatrix.setTranslate(0, 0);
|
||||
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
|
||||
mTmpMatrix.setTranslate(app.localBounds.left, app.localBounds.top);
|
||||
}
|
||||
if (app.mode == targetMode
|
||||
&& app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
|
||||
mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
|
||||
mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
|
||||
mCurrentClipRectF.roundOut(crop);
|
||||
if (mSupportsRoundedCornersOnWindows) {
|
||||
if (params.getCornerRadius() > -1) {
|
||||
cornerRadius = params.getCornerRadius();
|
||||
scale = mCurrentRect.width() / crop.width();
|
||||
} else {
|
||||
float windowCornerRadius = mUseRoundedCornersOnWindows
|
||||
? mWindowCornerRadius : 0;
|
||||
cornerRadius = mapRange(boundToRange(params.getProgress(), 0, 1),
|
||||
windowCornerRadius, mTaskCornerRadius);
|
||||
}
|
||||
}
|
||||
|
||||
builder.withMatrix(mTmpMatrix)
|
||||
.withWindowCrop(crop)
|
||||
// Since radius is in Surface space, but we draw the rounded corners in screen
|
||||
// space, we have to undo the scale
|
||||
.withCornerRadius(cornerRadius / scale);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public RectF updateCurrentRect(TransformParams params) {
|
||||
if (params.getCurrentRect() != null) {
|
||||
mCurrentRect.set(params.getCurrentRect());
|
||||
} else {
|
||||
mTmpRectF.set(mTargetRect);
|
||||
mCurrentRect.set(mRectFEvaluator.evaluate(
|
||||
params.getProgress(), mSourceRect, mTmpRectF));
|
||||
}
|
||||
|
||||
updateClipRect(params);
|
||||
return mCurrentRect;
|
||||
}
|
||||
|
||||
private void updateClipRect(TransformParams params) {
|
||||
// Don't clip past progress > 1.
|
||||
float progress = Math.min(1, params.getProgress());
|
||||
mCurrentClipRectF.left = mSourceWindowClipInsets.left * progress;
|
||||
mCurrentClipRectF.top = mSourceWindowClipInsets.top * progress;
|
||||
mCurrentClipRectF.right =
|
||||
mSourceStackBounds.width() - (mSourceWindowClipInsets.right * progress);
|
||||
mCurrentClipRectF.bottom =
|
||||
mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress);
|
||||
}
|
||||
|
||||
public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv,
|
||||
@Nullable RemoteAnimationTargetCompat target) {
|
||||
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext());
|
||||
BaseDragLayer dl = activity.getDragLayer();
|
||||
|
||||
int[] pos = new int[2];
|
||||
dl.getLocationOnScreen(pos);
|
||||
mHomeStackBounds.set(0, 0, dl.getWidth(), dl.getHeight());
|
||||
mHomeStackBounds.offset(pos[0], pos[1]);
|
||||
|
||||
if (target != null) {
|
||||
updateSourceStack(target);
|
||||
} else if (rv.shouldUseMultiWindowTaskSizeStrategy()) {
|
||||
updateStackBoundsToMultiWindowTaskSize(activity);
|
||||
} else {
|
||||
mSourceStackBounds.set(mHomeStackBounds);
|
||||
Rect fallback = dl.getInsets();
|
||||
mSourceInsets.set(ttv.getInsets(fallback));
|
||||
}
|
||||
|
||||
Rect targetRect = new Rect();
|
||||
dl.getDescendantRectRelativeToSelf(ttv, targetRect);
|
||||
updateTargetRect(targetRect);
|
||||
|
||||
if (target == null) {
|
||||
// Transform the clip relative to the target rect. Only do this in the case where we
|
||||
// aren't applying the insets to the app windows (where the clip should be in target app
|
||||
// space)
|
||||
float scale = mTargetRect.width() / mSourceRect.width();
|
||||
mSourceWindowClipInsets.left = mSourceWindowClipInsets.left * scale;
|
||||
mSourceWindowClipInsets.top = mSourceWindowClipInsets.top * scale;
|
||||
mSourceWindowClipInsets.right = mSourceWindowClipInsets.right * scale;
|
||||
mSourceWindowClipInsets.bottom = mSourceWindowClipInsets.bottom * scale;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) {
|
||||
SystemUiProxy proxy = SystemUiProxy.INSTANCE.get(activity);
|
||||
if (proxy.isActive()) {
|
||||
mSourceStackBounds.set(proxy.getNonMinimizedSplitScreenSecondaryBounds());
|
||||
return;
|
||||
}
|
||||
|
||||
// Assume that the task size is half screen size (minus the insets and the divider size)
|
||||
DeviceProfile fullDp = activity.getDeviceProfile().getFullScreenProfile();
|
||||
// Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
|
||||
// account for system insets
|
||||
int taskWidth = fullDp.availableWidthPx;
|
||||
int taskHeight = fullDp.availableHeightPx;
|
||||
int halfDividerSize = activity.getResources()
|
||||
.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
|
||||
|
||||
Rect insets = new Rect();
|
||||
WindowManagerWrapper.getInstance().getStableInsets(insets);
|
||||
if (fullDp.isLandscape) {
|
||||
taskWidth = taskWidth / 2 - halfDividerSize;
|
||||
} else {
|
||||
taskHeight = taskHeight / 2 - halfDividerSize;
|
||||
}
|
||||
|
||||
// Align the task to bottom left/right edge (closer to nav bar).
|
||||
int left = activity.getDeviceProfile().isSeascape() ? insets.left
|
||||
: (insets.left + fullDp.availableWidthPx - taskWidth);
|
||||
mSourceStackBounds.set(0, 0, taskWidth, taskHeight);
|
||||
mSourceStackBounds.offset(left, insets.top + fullDp.availableHeightPx - taskHeight);
|
||||
}
|
||||
|
||||
public RectF getTargetRect() {
|
||||
return mTargetRect;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import android.graphics.Matrix;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.IntProperty;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
@@ -47,6 +48,19 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.
|
||||
*/
|
||||
public class TaskViewSimulator implements TransformParams.BuilderProxy {
|
||||
|
||||
public static final IntProperty<TaskViewSimulator> SCROLL =
|
||||
new IntProperty<TaskViewSimulator>("scroll") {
|
||||
@Override
|
||||
public void setValue(TaskViewSimulator simulator, int i) {
|
||||
simulator.setScroll(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer get(TaskViewSimulator simulator) {
|
||||
return simulator.mScrollState.scroll;
|
||||
}
|
||||
};
|
||||
|
||||
private final Rect mTmpCropRect = new Rect();
|
||||
private final RectF mTempRectF = new RectF();
|
||||
private final float[] mTempPoint = new float[2];
|
||||
@@ -279,4 +293,5 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
|
||||
// Ideally we should use square-root. This is an optimization as one of the dimension is 0.
|
||||
return Math.max(Math.abs(mTempPoint[0]), Math.abs(mTempPoint[1]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,11 +15,8 @@
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import android.graphics.RectF;
|
||||
import android.util.FloatProperty;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.quickstep.RemoteAnimationTargets;
|
||||
@@ -44,7 +41,6 @@ public class TransformParams {
|
||||
};
|
||||
|
||||
private float mProgress;
|
||||
private @Nullable RectF mCurrentRect;
|
||||
private float mTargetAlpha;
|
||||
private float mCornerRadius;
|
||||
private RemoteAnimationTargets mTargetSet;
|
||||
@@ -55,7 +51,6 @@ public class TransformParams {
|
||||
|
||||
public TransformParams() {
|
||||
mProgress = 0;
|
||||
mCurrentRect = null;
|
||||
mTargetAlpha = 1;
|
||||
mCornerRadius = -1;
|
||||
}
|
||||
@@ -80,17 +75,6 @@ public class TransformParams {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current rect to show the transformed window, in device coordinates. This gives
|
||||
* the caller manual control of where to show the window. If unspecified (null), we
|
||||
* interpolate between {@link AppWindowAnimationHelper#mSourceRect} and
|
||||
* {@link AppWindowAnimationHelper#mTargetRect}, based on {@link #mProgress}.
|
||||
*/
|
||||
public TransformParams setCurrentRect(RectF currentRect) {
|
||||
mCurrentRect = currentRect;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the alpha of the transformed window. Default is 1.
|
||||
*/
|
||||
@@ -173,11 +157,6 @@ public class TransformParams {
|
||||
return mProgress;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RectF getCurrentRect() {
|
||||
return mCurrentRect;
|
||||
}
|
||||
|
||||
public float getTargetAlpha() {
|
||||
return mTargetAlpha;
|
||||
}
|
||||
|
||||
+2
-13
@@ -157,9 +157,8 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
|
||||
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
|
||||
if (tv.isRunningTask()) {
|
||||
mTransformParams.setProgress(1 - progress)
|
||||
.setCurrentRect(null)
|
||||
.setSyncTransactionApplier(mSyncTransactionApplier);
|
||||
mAppWindowAnimationHelper.applyTransform(mTransformParams);
|
||||
// TODO: Revisit live tiles
|
||||
} else {
|
||||
redrawLiveTile(true);
|
||||
}
|
||||
@@ -190,19 +189,11 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void redrawLiveTile(boolean mightNeedToRefill) {
|
||||
TransformParams transformParams = getLiveTileParams(mightNeedToRefill);
|
||||
if (transformParams != null) {
|
||||
mAppWindowAnimationHelper.applyTransform(transformParams);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformParams getLiveTileParams(
|
||||
boolean mightNeedToRefill) {
|
||||
if (!mEnableDrawingLiveTile || mRecentsAnimationController == null
|
||||
|| mRecentsAnimationTargets == null || mAppWindowAnimationHelper == null) {
|
||||
|| mRecentsAnimationTargets == null) {
|
||||
return null;
|
||||
}
|
||||
TaskView taskView = getRunningTaskView();
|
||||
@@ -222,9 +213,7 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
|
||||
if (mightNeedToRefill && offsetY > 0) {
|
||||
mTempRect.top -= offsetY;
|
||||
}
|
||||
mTempRectF.set(mTempRect);
|
||||
mTransformParams.setProgress(1f)
|
||||
.setCurrentRect(mTempRectF)
|
||||
.setTargetAlpha(taskView.getAlpha())
|
||||
.setSyncTransactionApplier(mSyncTransactionApplier)
|
||||
.setTargetSet(mRecentsAnimationTargets);
|
||||
|
||||
@@ -63,7 +63,6 @@ import android.graphics.Canvas;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
@@ -126,7 +125,6 @@ import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
import com.android.quickstep.TaskUtils;
|
||||
import com.android.quickstep.ViewUtils;
|
||||
import com.android.quickstep.util.AppWindowAnimationHelper;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
import com.android.quickstep.util.SplitScreenBounds;
|
||||
@@ -214,15 +212,12 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
protected final BaseActivityInterface mSizeStrategy;
|
||||
protected RecentsAnimationController mRecentsAnimationController;
|
||||
protected RecentsAnimationTargets mRecentsAnimationTargets;
|
||||
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
|
||||
protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
|
||||
protected int mTaskWidth;
|
||||
protected int mTaskHeight;
|
||||
protected boolean mEnableDrawingLiveTile = false;
|
||||
protected final Rect mTempRect = new Rect();
|
||||
protected final RectF mTempRectF = new RectF();
|
||||
private final PointF mTempPointF = new PointF();
|
||||
private final float[] mTempFloatPoint = new float[2];
|
||||
|
||||
private static final int DISMISS_TASK_DURATION = 300;
|
||||
private static final int ADDITION_TASK_DURATION = 200;
|
||||
@@ -980,7 +975,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
mRecentsAnimationController = null;
|
||||
mRecentsAnimationTargets = null;
|
||||
mAppWindowAnimationHelper = null;
|
||||
|
||||
unloadVisibleTaskData();
|
||||
setCurrentPage(0);
|
||||
@@ -2009,11 +2003,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
mRecentsAnimationTargets = recentsAnimationTargets;
|
||||
}
|
||||
|
||||
// TODO: To be removed in a follow up CL
|
||||
public void setAppWindowAnimationHelper(AppWindowAnimationHelper appWindowAnimationHelper) {
|
||||
mAppWindowAnimationHelper = appWindowAnimationHelper;
|
||||
}
|
||||
|
||||
public void setLiveTileOverlayAttached(boolean liveTileOverlayAttached) {
|
||||
mLiveTileOverlayAttached = liveTileOverlayAttached;
|
||||
}
|
||||
@@ -2096,13 +2085,20 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
|
||||
|
||||
/**
|
||||
* @return How many pixels the running task is offset on the x-axis due to the current scrollX.
|
||||
* @return How many pixels the running task is offset on the currently laid out dominant axis.
|
||||
*/
|
||||
public int getScrollOffset() {
|
||||
if (getRunningTaskIndex() == -1) {
|
||||
return getScrollOffset(getRunningTaskIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return How many pixels the page is offset on the currently laid out dominant axis.
|
||||
*/
|
||||
public int getScrollOffset(int pageIndex) {
|
||||
if (pageIndex == -1) {
|
||||
return 0;
|
||||
}
|
||||
return getScrollForPage(getRunningTaskIndex()) - mOrientationHandler.getPrimaryScroll(this);
|
||||
return getScrollForPage(pageIndex) - mOrientationHandler.getPrimaryScroll(this);
|
||||
}
|
||||
|
||||
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
|
||||
@@ -2134,10 +2130,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
|
||||
};
|
||||
}
|
||||
|
||||
public AppWindowAnimationHelper getClipAnimationHelper() {
|
||||
return mAppWindowAnimationHelper;
|
||||
}
|
||||
|
||||
public TransformParams getLiveTileParams(
|
||||
boolean mightNeedToRefill) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user