summaryrefslogtreecommitdiffstats
path: root/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
diff options
context:
space:
mode:
authorKevin <kevhan@google.com>2019-02-25 14:41:54 -0800
committerKevin <kevhan@google.com>2019-02-25 14:53:04 -0800
commit576d203a913680d8d81a3a39c1a19b8207a40985 (patch)
tree548a4c83fd9c0ebc1a921e6a3ac8684779ff21d4 /quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
parent6873fe517b1861e5695a0081152a10d08317b346 (diff)
downloadandroid_packages_apps_Trebuchet-576d203a913680d8d81a3a39c1a19b8207a40985.tar.gz
android_packages_apps_Trebuchet-576d203a913680d8d81a3a39c1a19b8207a40985.tar.bz2
android_packages_apps_Trebuchet-576d203a913680d8d81a3a39c1a19b8207a40985.zip
Remove several files from Recents Go src
As Go will not be using RecentsView, there are several files that are unneeded in the recents Go source. This moves these files to recents_ui_overrides where they will be used for non-Go builds. Bug: 114136250 Test: Build NexusLauncher, aospWithQuickstep, l3GoWithQuickstep Change-Id: I9d0154a75f4f2c71b865d414448e262b3019b2b9
Diffstat (limited to 'quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java')
-rw-r--r--quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java387
1 files changed, 387 insertions, 0 deletions
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
new file mode 100644
index 000000000..6d374c61b
--- /dev/null
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -0,0 +1,387 @@
+/*
+ * 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.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Build;
+import android.os.RemoteException;
+
+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.RecentsModel;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskThumbnailView;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+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.TransactionCompat;
+import com.android.systemui.shared.system.WindowManagerWrapper;
+
+import java.util.function.BiFunction;
+
+import androidx.annotation.Nullable;
+
+/**
+ * Utility class to handle window clip animation
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class ClipAnimationHelper {
+
+ // The bounds of the source app in device coordinates
+ private final Rect mSourceStackBounds = new Rect();
+ // The insets of the source app
+ private final Rect mSourceInsets = new Rect();
+ // The source app bounds with the source insets applied, in the source app window coordinates
+ private final RectF mSourceRect = new RectF();
+ // The bounds of the task view in launcher window coordinates
+ private final RectF mTargetRect = 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 insets to be used for clipping the app window. For live tile, we don't transform the clip
+ // relative to the target rect.
+ private final RectF mSourceWindowClipInsetsForLiveTile = new RectF();
+
+ // The bounds of launcher (not including insets) in device coordinates
+ public final Rect mHomeStackBounds = new Rect();
+
+ // The clip rect in source app window coordinates
+ private final RectF mClipRectF = new RectF();
+ private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
+ private final Matrix mTmpMatrix = new Matrix();
+ private final RectF mTmpRectF = new RectF();
+ private final RectF mCurrentRectWithInsets = new RectF();
+ // 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;
+
+ // Corner radius currently applied to transformed window.
+ private float mCurrentCornerRadius;
+
+ // Whether to boost the opening animation target layers, or the closing
+ private int mBoostModeTargetLayers = -1;
+
+ private BiFunction<RemoteAnimationTargetCompat, Float, Float> mTaskAlphaCallback =
+ (t, a1) -> a1;
+
+ public ClipAnimationHelper(Context context) {
+ mWindowCornerRadius = RecentsModel.INSTANCE.get(context).getWindowCornerRadius();
+ mSupportsRoundedCornersOnWindows = RecentsModel.INSTANCE.get(context)
+ .supportsRoundedCornersOnWindows();
+ int taskCornerRadiusRes = mSupportsRoundedCornersOnWindows ?
+ R.dimen.task_corner_radius : R.dimen.task_corner_radius_small;
+ mTaskCornerRadius = context.getResources().getDimension(taskCornerRadiusRes);
+ }
+
+ private void updateSourceStack(RemoteAnimationTargetCompat target) {
+ mSourceInsets.set(target.contentInsets);
+ mSourceStackBounds.set(target.sourceContainerBounds);
+
+ // TODO: Should sourceContainerBounds already have this offset?
+ mSourceStackBounds.offsetTo(target.position.x, target.position.y);
+
+ }
+
+ public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
+ mHomeStackBounds.set(homeStackBounds);
+ updateSourceStack(target);
+ }
+
+ 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);
+ Utilities.scaleRectFAboutCenter(scaledTargetRect,
+ mSourceRect.width() / mTargetRect.width());
+ 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));
+ mSourceWindowClipInsetsForLiveTile.set(mSourceWindowClipInsets);
+ mSourceRect.set(scaledTargetRect);
+ }
+
+ public void prepareAnimation(boolean isOpening) {
+ mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
+ }
+
+ public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params) {
+ if (params.currentRect == null) {
+ RectF currentRect;
+ mTmpRectF.set(mTargetRect);
+ Utilities.scaleRectFAboutCenter(mTmpRectF, params.offsetScale);
+ float progress = params.progress;
+ currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF);
+ currentRect.offset(params.offsetX, 0);
+
+ final RectF sourceWindowClipInsets = params.forLiveTile
+ ? mSourceWindowClipInsetsForLiveTile : mSourceWindowClipInsets;
+ mClipRectF.left = sourceWindowClipInsets.left * progress;
+ mClipRectF.top = sourceWindowClipInsets.top * progress;
+ mClipRectF.right =
+ mSourceStackBounds.width() - (sourceWindowClipInsets.right * progress);
+ mClipRectF.bottom =
+ mSourceStackBounds.height() - (sourceWindowClipInsets.bottom * progress);
+ params.setCurrentRectAndTargetAlpha(currentRect, 1);
+ }
+
+ SurfaceParams[] surfaceParams = new SurfaceParams[targetSet.unfilteredApps.length];
+ for (int i = 0; i < targetSet.unfilteredApps.length; i++) {
+ RemoteAnimationTargetCompat app = targetSet.unfilteredApps[i];
+ mTmpMatrix.setTranslate(app.position.x, app.position.y);
+ Rect crop = app.sourceContainerBounds;
+ float alpha = 1f;
+ int layer = RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers);
+ float cornerRadius = 0f;
+ float scale = params.currentRect.width() / crop.width();
+ if (app.mode == targetSet.targetMode) {
+ if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ mTmpMatrix.setRectToRect(mSourceRect, params.currentRect, ScaleToFit.FILL);
+ mTmpMatrix.postTranslate(app.position.x, app.position.y);
+ mClipRectF.roundOut(crop);
+ if (mSupportsRoundedCornersOnWindows) {
+ cornerRadius = Utilities.mapRange(params.progress, mWindowCornerRadius,
+ mTaskCornerRadius);
+ }
+ }
+ alpha = mTaskAlphaCallback.apply(app, params.targetAlpha);
+ } else if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ crop = null;
+ layer = Integer.MAX_VALUE;
+ }
+
+ // Since radius is in Surface space, but we draw the rounded corners in screen space, we
+ // have to undo the scale.
+ surfaceParams[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer,
+ cornerRadius / scale);
+ }
+ applySurfaceParams(params.syncTransactionApplier, surfaceParams);
+ return params.currentRect;
+ }
+
+ public RectF getCurrentRectWithInsets() {
+ mTmpMatrix.mapRect(mCurrentRectWithInsets, mClipRectF);
+ return mCurrentRectWithInsets;
+ }
+
+ private void applySurfaceParams(@Nullable SyncRtSurfaceTransactionApplierCompat
+ syncTransactionApplier, SurfaceParams[] params) {
+ if (syncTransactionApplier != null) {
+ syncTransactionApplier.scheduleApply(params);
+ } else {
+ TransactionCompat t = new TransactionCompat();
+ for (SurfaceParams param : params) {
+ SyncRtSurfaceTransactionApplierCompat.applyParams(t, param);
+ }
+ t.setEarlyWakeup();
+ t.apply();
+ }
+ }
+
+ public void setTaskAlphaCallback(
+ BiFunction<RemoteAnimationTargetCompat, Float, Float> callback) {
+ mTaskAlphaCallback = callback;
+ }
+
+ public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv) {
+ fromTaskThumbnailView(ttv, rv, null);
+ }
+
+ 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) {
+ ISystemUiProxy sysUiProxy = RecentsModel.INSTANCE.get(activity).getSystemUiProxy();
+ if (sysUiProxy != null) {
+ try {
+ mSourceStackBounds.set(sysUiProxy.getNonMinimizedSplitScreenSecondaryBounds());
+ return;
+ } catch (RemoteException e) {
+ // Use half screen size
+ }
+ }
+
+ // 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 void drawForProgress(TaskThumbnailView ttv, Canvas canvas, float progress) {
+ RectF currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
+ canvas.translate(mSourceStackBounds.left - mHomeStackBounds.left,
+ mSourceStackBounds.top - mHomeStackBounds.top);
+ mTmpMatrix.setRectToRect(mTargetRect, currentRect, ScaleToFit.FILL);
+
+ canvas.concat(mTmpMatrix);
+ canvas.translate(mTargetRect.left, mTargetRect.top);
+
+ float scale = mTargetRect.width() / mSourceRect.width();
+ float insetProgress = (1 - progress);
+ ttv.drawOnCanvas(canvas,
+ -mSourceWindowClipInsets.left * insetProgress,
+ -mSourceWindowClipInsets.top * insetProgress,
+ ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress,
+ ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress,
+ Utilities.mapRange(progress, mWindowCornerRadius * scale, ttv.getCornerRadius()));
+ }
+
+ public RectF getTargetRect() {
+ return mTargetRect;
+ }
+
+ public RectF getSourceRect() {
+ return mSourceRect;
+ }
+
+ public float getCurrentCornerRadius() {
+ return mCurrentCornerRadius;
+ }
+
+ public static class TransformParams {
+ float progress;
+ public float offsetX;
+ public float offsetScale;
+ @Nullable RectF currentRect;
+ float targetAlpha;
+ boolean forLiveTile;
+
+ SyncRtSurfaceTransactionApplierCompat syncTransactionApplier;
+
+ public TransformParams() {
+ progress = 0;
+ offsetX = 0;
+ offsetScale = 1;
+ currentRect = null;
+ targetAlpha = 0;
+ forLiveTile = false;
+ }
+
+ public TransformParams setProgress(float progress) {
+ this.progress = progress;
+ this.currentRect = null;
+ return this;
+ }
+
+ public TransformParams setCurrentRectAndTargetAlpha(RectF currentRect, float targetAlpha) {
+ this.currentRect = currentRect;
+ this.targetAlpha = targetAlpha;
+ return this;
+ }
+
+ public TransformParams setOffsetX(float offsetX) {
+ this.offsetX = offsetX;
+ return this;
+ }
+
+ public TransformParams setOffsetScale(float offsetScale) {
+ this.offsetScale = offsetScale;
+ return this;
+ }
+
+ public TransformParams setForLiveTile(boolean forLiveTile) {
+ this.forLiveTile = forLiveTile;
+ return this;
+ }
+
+ public TransformParams setSyncTransactionApplier(
+ SyncRtSurfaceTransactionApplierCompat applier) {
+ this.syncTransactionApplier = applier;
+ return this;
+ }
+ }
+}