Rounded corners on app transitions
Test: Manualy launch an app Test: Press home when activity is on top of the stack Test: Quick scrub Test: Swipe up on the home button, swipe down Bug: 111514493 Fixes: 116745318 Change-Id: I66d25bc433061ede46107ea9651c198614306692
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
<dimen name="task_thumbnail_top_margin">24dp</dimen>
|
||||
<dimen name="task_thumbnail_half_top_margin">12dp</dimen>
|
||||
<dimen name="task_thumbnail_icon_size">48dp</dimen>
|
||||
<dimen name="task_corner_radius">2dp</dimen>
|
||||
<dimen name="task_corner_radius">8dp</dimen>
|
||||
<dimen name="recents_page_spacing">10dp</dimen>
|
||||
<dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
|
||||
<dimen name="quickscrub_adjacent_visible_width">20dp</dimen>
|
||||
|
||||
@@ -67,6 +67,7 @@ import com.android.launcher3.graphics.DrawableFactory;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.util.ClipAnimationHelper;
|
||||
import com.android.quickstep.util.MultiValueUpdateListener;
|
||||
import com.android.quickstep.util.RemoteAnimationProvider;
|
||||
@@ -286,7 +287,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
? RECENTS_QUICKSCRUB_LAUNCH_DURATION
|
||||
: RECENTS_LAUNCH_DURATION;
|
||||
|
||||
ClipAnimationHelper helper = new ClipAnimationHelper();
|
||||
ClipAnimationHelper helper = new ClipAnimationHelper(mLauncher);
|
||||
target.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets, helper)
|
||||
.setDuration(duration));
|
||||
|
||||
@@ -605,6 +606,13 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
float transX0 = floatingViewBounds[0] - offsetX;
|
||||
float transY0 = floatingViewBounds[1] - offsetY;
|
||||
|
||||
// Animate window corner radius from 100% to windowCornerRadius.
|
||||
float windowCornerRadius = RecentsModel.INSTANCE.get(mLauncher)
|
||||
.getWindowCornerRadius();
|
||||
float circleRadius = scaledWindowWidth / 2f;
|
||||
float windowRadius = Utilities.mapRange(easePercent, circleRadius,
|
||||
windowCornerRadius);
|
||||
|
||||
// Animate the window crop so that it starts off as a square, and then reveals
|
||||
// horizontally.
|
||||
float cropHeight = windowHeight * easePercent + windowWidth * (1 - easePercent);
|
||||
@@ -619,20 +627,24 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
RemoteAnimationTargetCompat target = targets[i];
|
||||
|
||||
Rect targetCrop;
|
||||
float alpha;
|
||||
final float alpha;
|
||||
final float cornerRadius;
|
||||
if (target.mode == MODE_OPENING) {
|
||||
matrix.setScale(scale, scale);
|
||||
matrix.postTranslate(transX0, transY0);
|
||||
targetCrop = crop;
|
||||
alpha = mAlpha.value;
|
||||
cornerRadius = windowRadius;
|
||||
} else {
|
||||
matrix.setTranslate(target.position.x, target.position.y);
|
||||
alpha = 1f;
|
||||
targetCrop = target.sourceContainerBounds;
|
||||
cornerRadius = 0;
|
||||
}
|
||||
|
||||
params[i] = new SurfaceParams(target.leash, alpha, matrix, targetCrop,
|
||||
RemoteAnimationProvider.getLayer(target, MODE_OPENING));
|
||||
RemoteAnimationProvider.getLayer(target, MODE_OPENING),
|
||||
cornerRadius);
|
||||
}
|
||||
surfaceApplier.scheduleApply(params);
|
||||
}
|
||||
@@ -724,6 +736,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
Matrix matrix = new Matrix();
|
||||
ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
|
||||
int duration = CLOSING_TRANSITION_DURATION_MS;
|
||||
float windowCornerRadius = RecentsModel.INSTANCE.get(mLauncher).getWindowCornerRadius();
|
||||
closingAnimator.setDuration(duration);
|
||||
closingAnimator.addUpdateListener(new MultiValueUpdateListener() {
|
||||
FloatProp mDy = new FloatProp(0, mClosingWindowTransY, 0, duration, DEACCEL_1_7);
|
||||
@@ -735,7 +748,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
SurfaceParams[] params = new SurfaceParams[targets.length];
|
||||
for (int i = targets.length - 1; i >= 0; i--) {
|
||||
RemoteAnimationTargetCompat target = targets[i];
|
||||
float alpha;
|
||||
final float alpha;
|
||||
final float cornerRadius;
|
||||
if (target.mode == MODE_CLOSING) {
|
||||
matrix.setScale(mScale.value, mScale.value,
|
||||
target.sourceContainerBounds.centerX(),
|
||||
@@ -743,13 +757,16 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
|
||||
matrix.postTranslate(0, mDy.value);
|
||||
matrix.postTranslate(target.position.x, target.position.y);
|
||||
alpha = mAlpha.value;
|
||||
cornerRadius = windowCornerRadius;
|
||||
} else {
|
||||
matrix.setTranslate(target.position.x, target.position.y);
|
||||
alpha = 1f;
|
||||
cornerRadius = 0f;
|
||||
}
|
||||
params[i] = new SurfaceParams(target.leash, alpha, matrix,
|
||||
target.sourceContainerBounds,
|
||||
RemoteAnimationProvider.getLayer(target, MODE_CLOSING));
|
||||
RemoteAnimationProvider.getLayer(target, MODE_CLOSING),
|
||||
cornerRadius);
|
||||
}
|
||||
surfaceApplier.scheduleApply(params);
|
||||
}
|
||||
|
||||
@@ -319,7 +319,7 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
|
||||
float prevRvScale = recentsView.getScaleX();
|
||||
float targetRvScale = endState.getOverviewScaleAndTranslationYFactor(launcher)[0];
|
||||
SCALE_PROPERTY.set(recentsView, targetRvScale);
|
||||
ClipAnimationHelper clipHelper = new ClipAnimationHelper();
|
||||
ClipAnimationHelper clipHelper = new ClipAnimationHelper(launcher);
|
||||
clipHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(), null);
|
||||
SCALE_PROPERTY.set(recentsView, prevRvScale);
|
||||
|
||||
|
||||
@@ -326,7 +326,7 @@ public class OverviewCommandHelper {
|
||||
return anim;
|
||||
}
|
||||
|
||||
final ClipAnimationHelper clipHelper = new ClipAnimationHelper();
|
||||
final ClipAnimationHelper clipHelper = new ClipAnimationHelper(mActivity);
|
||||
|
||||
// At this point, the activity is already started and laid-out. Get the home-bounds
|
||||
// relative to the screen using the rootView of the activity.
|
||||
|
||||
@@ -189,7 +189,7 @@ public class RecentsActivity extends BaseDraggingActivity {
|
||||
RemoteAnimationTargetCompat[] targets) {
|
||||
AnimatorSet target = new AnimatorSet();
|
||||
boolean activityClosing = taskIsATargetWithMode(targets, getTaskId(), MODE_CLOSING);
|
||||
ClipAnimationHelper helper = new ClipAnimationHelper();
|
||||
ClipAnimationHelper helper = new ClipAnimationHelper(this);
|
||||
target.play(getRecentsWindowAnimator(taskView, !activityClosing, targets, helper)
|
||||
.setDuration(RECENTS_LAUNCH_DURATION));
|
||||
|
||||
|
||||
@@ -45,6 +45,9 @@ import androidx.annotation.WorkerThread;
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public class RecentsModel extends TaskStackChangeListener {
|
||||
|
||||
private static final String TAG = "RecentsModel";
|
||||
|
||||
// We do not need any synchronization for this variable as its only written on UI thread.
|
||||
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
|
||||
new MainThreadInitializedObject<>(c -> new RecentsModel(c));
|
||||
@@ -62,6 +65,9 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
private final TaskIconCache mIconCache;
|
||||
private final TaskThumbnailCache mThumbnailCache;
|
||||
|
||||
private float mWindowCornerRadius = -1;
|
||||
|
||||
|
||||
private RecentsModel(Context context) {
|
||||
mContext = context;
|
||||
|
||||
@@ -174,6 +180,26 @@ public class RecentsModel extends TaskStackChangeListener {
|
||||
return mSystemUiProxy;
|
||||
}
|
||||
|
||||
public float getWindowCornerRadius() {
|
||||
// The window corner radius is expressed in pixels and won't change if the
|
||||
// display density changes. It's safe to cache the value.
|
||||
if (mWindowCornerRadius == -1) {
|
||||
if (mSystemUiProxy != null) {
|
||||
try {
|
||||
mWindowCornerRadius = mSystemUiProxy.getWindowCornerRadius();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Connection to ISystemUIProxy was lost, ignoring window corner "
|
||||
+ "radius");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "ISystemUIProxy is null, ignoring window corner radius");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return mWindowCornerRadius;
|
||||
}
|
||||
|
||||
public void onTrimMemory(int level) {
|
||||
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
|
||||
mThumbnailCache.getHighResLoadingState().setVisible(false);
|
||||
|
||||
@@ -173,7 +173,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
private static final float SWIPE_DURATION_MULTIPLIER =
|
||||
Math.min(1 / MIN_PROGRESS_FOR_OVERVIEW, 1 / (1 - MIN_PROGRESS_FOR_OVERVIEW));
|
||||
|
||||
private final ClipAnimationHelper mClipAnimationHelper = new ClipAnimationHelper();
|
||||
private final ClipAnimationHelper mClipAnimationHelper;
|
||||
|
||||
protected Runnable mGestureEndCallback;
|
||||
protected boolean mIsGoingToHome;
|
||||
@@ -253,6 +253,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity> {
|
||||
mTouchInteractionLog = touchInteractionLog;
|
||||
mRecentsAnimationWrapper = new RecentsAnimationWrapper(inputConsumer,
|
||||
this::createNewTouchProxyHandler);
|
||||
mClipAnimationHelper = new ClipAnimationHelper(context);
|
||||
|
||||
initStateCallbacks();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MOD
|
||||
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;
|
||||
@@ -31,6 +32,8 @@ import android.os.Build;
|
||||
import android.os.RemoteException;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
@@ -50,8 +53,6 @@ import com.android.systemui.shared.system.WindowManagerWrapper;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Utility class to handle window clip animation
|
||||
*/
|
||||
@@ -82,6 +83,10 @@ public class ClipAnimationHelper {
|
||||
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;
|
||||
|
||||
private float mTargetScale = 1f;
|
||||
private float mOffsetScale = 1f;
|
||||
@@ -95,6 +100,11 @@ public class ClipAnimationHelper {
|
||||
private BiFunction<RemoteAnimationTargetCompat, Float, Float> mTaskAlphaCallback =
|
||||
(t, a1) -> a1;
|
||||
|
||||
public ClipAnimationHelper(Context context) {
|
||||
mTaskCornerRadius = context.getResources().getDimension(R.dimen.task_corner_radius);
|
||||
mWindowCornerRadius = RecentsModel.INSTANCE.get(context).getWindowCornerRadius();
|
||||
}
|
||||
|
||||
private void updateSourceStack(RemoteAnimationTargetCompat target) {
|
||||
mSourceInsets.set(target.contentInsets);
|
||||
mSourceStackBounds.set(target.sourceContainerBounds);
|
||||
@@ -168,11 +178,15 @@ public class ClipAnimationHelper {
|
||||
Rect crop = app.sourceContainerBounds;
|
||||
float alpha = 1f;
|
||||
int layer;
|
||||
float cornerRadius = 0f;
|
||||
if (app.mode == targetSet.targetMode) {
|
||||
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
|
||||
mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
|
||||
mTmpMatrix.postTranslate(app.position.x, app.position.y);
|
||||
mClipRectF.roundOut(crop);
|
||||
float scale = crop.width() / currentRect.width();
|
||||
cornerRadius = Utilities.mapRange(progress, mWindowCornerRadius,
|
||||
mTaskCornerRadius * scale);
|
||||
}
|
||||
|
||||
if (app.isNotInRecents
|
||||
@@ -186,7 +200,7 @@ public class ClipAnimationHelper {
|
||||
crop = null;
|
||||
layer = Integer.MAX_VALUE;
|
||||
}
|
||||
params[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer);
|
||||
params[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop, layer, cornerRadius);
|
||||
}
|
||||
applyParams(syncTransactionApplier, params);
|
||||
return currentRect;
|
||||
@@ -315,7 +329,7 @@ public class ClipAnimationHelper {
|
||||
-mSourceWindowClipInsets.top * insetProgress,
|
||||
ttv.getMeasuredWidth() + mSourceWindowClipInsets.right * insetProgress,
|
||||
ttv.getMeasuredHeight() + mSourceWindowClipInsets.bottom * insetProgress,
|
||||
ttv.getCornerRadius() * progress);
|
||||
Utilities.mapRange(progress, mWindowCornerRadius, ttv.getCornerRadius()));
|
||||
}
|
||||
|
||||
public RectF getTargetRect() {
|
||||
|
||||
@@ -71,7 +71,7 @@ public class TaskViewDrawable extends Drawable {
|
||||
Utilities.getDescendantCoordRelativeToAncestor(mIconView, parent, mIconPos, true);
|
||||
|
||||
mThumbnailView = tv.getThumbnail();
|
||||
mClipAnimationHelper = new ClipAnimationHelper();
|
||||
mClipAnimationHelper = new ClipAnimationHelper(parent.getContext());
|
||||
mClipAnimationHelper.fromTaskThumbnailView(mThumbnailView, parent);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user