diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java index 108006b5f0..cb439d5dea 100644 --- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java @@ -56,6 +56,7 @@ import android.graphics.drawable.Drawable; import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; +import android.os.SystemProperties; import android.util.Pair; import android.view.View; @@ -99,6 +100,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans private static final String TAG = "QuickstepTransition"; + private static final boolean ENABLE_SHELL_STARTING_SURFACE = + SystemProperties.getBoolean("persist.debug.shell_starting_surface", false); + /** Duration of status bar animations. */ public static final int STATUS_BAR_TRANSITION_DURATION = 120; @@ -442,9 +446,9 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets, Rect windowTargetBounds, boolean toggleVisibility) { - RectF bounds = new RectF(); + RectF launcherIconBounds = new RectF(); FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v, - toggleVisibility, bounds, true /* isOpening */); + toggleVisibility, launcherIconBounds, true /* isOpening */); Rect crop = new Rect(); Matrix matrix = new Matrix(); @@ -458,11 +462,17 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans mDragLayer.getLocationOnScreen(dragLayerBounds); AnimOpenProperties prop = new AnimOpenProperties(mLauncher.getResources(), mDeviceProfile, - windowTargetBounds, bounds, v, dragLayerBounds); + windowTargetBounds, launcherIconBounds, v, dragLayerBounds[0], dragLayerBounds[1]); + int left = (int) (prop.cropCenterXStart - prop.cropWidthStart / 2); + int top = (int) (prop.cropCenterYStart - prop.cropHeightStart / 2); + int right = (int) (left + prop.cropWidthStart); + int bottom = (int) (top + prop.cropHeightStart); + // Set the crop here so we can calculate the corner radius below. + crop.set(left, top, right, bottom); RectF targetBounds = new RectF(windowTargetBounds); - RectF iconBounds = new RectF(); - RectF temp = new RectF(); + RectF floatingIconBounds = new RectF(); + RectF tmpRectF = new RectF(); Point tmpPos = new Point(); AnimatorSet animatorSet = new AnimatorSet(); @@ -481,68 +491,79 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans }); final float initialWindowRadius = supportsRoundedCornersOnWindows(mLauncher.getResources()) - ? prop.startCrop / 2f : 0f; + ? Math.max(crop.width(), crop.height()) / 2f + : 0f; final float finalWindowRadius = mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher.getResources()); appAnimator.addUpdateListener(new MultiValueUpdateListener() { FloatProp mDx = new FloatProp(0, prop.dX, 0, prop.xDuration, AGGRESSIVE_EASE); FloatProp mDy = new FloatProp(0, prop.dY, 0, prop.yDuration, AGGRESSIVE_EASE); - FloatProp mScale = new FloatProp(prop.initialAppIconScale, + + FloatProp mIconScaleToFitScreen = new FloatProp(prop.initialAppIconScale, prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, EXAGGERATED_EASE); FloatProp mIconAlpha = new FloatProp(prop.iconAlphaStart, 0f, APP_LAUNCH_ALPHA_START_DELAY, prop.alphaDuration, LINEAR); - FloatProp mCroppedSize = new FloatProp(prop.startCrop, prop.endCrop, 0, CROP_DURATION, - EXAGGERATED_EASE); + FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0, RADIUS_DURATION, EXAGGERATED_EASE); FloatProp mShadowRadius = new FloatProp(0, mMaxShadowRadius, 0, APP_LAUNCH_DURATION, EXAGGERATED_EASE); + FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd, + 0, CROP_DURATION, EXAGGERATED_EASE); + FloatProp mCropRectCenterY = new FloatProp(prop.cropCenterYStart, prop.cropCenterYEnd, + 0, CROP_DURATION, EXAGGERATED_EASE); + FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, 0, + CROP_DURATION, EXAGGERATED_EASE); + FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0, + CROP_DURATION, EXAGGERATED_EASE); + @Override public void onUpdate(float percent) { // Calculate the size of the scaled icon. - float width = bounds.width() * mScale.value; - float height = bounds.height() * mScale.value; + float iconWidth = launcherIconBounds.width() * mIconScaleToFitScreen.value; + float iconHeight = launcherIconBounds.height() * mIconScaleToFitScreen.value; - // Animate the crop so that it starts off as a square. - final int cropWidth; - final int cropHeight; - if (mDeviceProfile.isVerticalBarLayout()) { - cropWidth = (int) mCroppedSize.value; - cropHeight = windowTargetBounds.height(); - } else { - cropWidth = windowTargetBounds.width(); - cropHeight = (int) mCroppedSize.value; - } - crop.set(0, 0, cropWidth, cropHeight); + int left = (int) (mCropRectCenterX.value - mCropRectWidth.value / 2); + int top = (int) (mCropRectCenterY.value - mCropRectHeight.value / 2); + int right = (int) (left + mCropRectWidth.value); + int bottom = (int) (top + mCropRectHeight.value); + crop.set(left, top, right, bottom); + + final int windowCropWidth = crop.width(); + final int windowCropHeight = crop.height(); // Scale the size of the icon to match the size of the window crop. - float scaleX = width / cropWidth; - float scaleY = height / cropHeight; + float scaleX = iconWidth / windowCropWidth; + float scaleY = iconHeight / windowCropHeight; float scale = Math.min(1f, Math.max(scaleX, scaleY)); - float scaledCropWidth = cropWidth * scale; - float scaledCropHeight = cropHeight * scale; - float offsetX = (scaledCropWidth - width) / 2; - float offsetY = (scaledCropHeight - height) / 2; + float scaledCropWidth = windowCropWidth * scale; + float scaledCropHeight = windowCropHeight * scale; + float offsetX = (scaledCropWidth - iconWidth) / 2; + float offsetY = (scaledCropHeight - iconHeight) / 2; // Calculate the window position to match the icon position. - temp.set(bounds); - temp.offset(dragLayerBounds[0], dragLayerBounds[1]); - temp.offset(mDx.value, mDy.value); - Utilities.scaleRectFAboutCenter(temp, mScale.value); - float windowTransX0 = temp.left - offsetX; - float windowTransY0 = temp.top - offsetY; + tmpRectF.set(launcherIconBounds); + tmpRectF.offset(dragLayerBounds[0], dragLayerBounds[1]); + tmpRectF.offset(mDx.value, mDy.value); + Utilities.scaleRectFAboutCenter(tmpRectF, mIconScaleToFitScreen.value); + float windowTransX0 = tmpRectF.left - offsetX; + float windowTransY0 = tmpRectF.top - offsetY; + if (ENABLE_SHELL_STARTING_SURFACE) { + windowTransX0 -= crop.left * scale; + windowTransY0 -= crop.top * scale; + } // Calculate the icon position. - iconBounds.set(bounds); - iconBounds.offset(mDx.value, mDy.value); - Utilities.scaleRectFAboutCenter(iconBounds, mScale.value); - iconBounds.left -= offsetX; - iconBounds.top -= offsetY; - iconBounds.right += offsetX; - iconBounds.bottom += offsetY; + floatingIconBounds.set(launcherIconBounds); + floatingIconBounds.offset(mDx.value, mDy.value); + Utilities.scaleRectFAboutCenter(floatingIconBounds, mIconScaleToFitScreen.value); + floatingIconBounds.left -= offsetX; + floatingIconBounds.top -= offsetY; + floatingIconBounds.right += offsetX; + floatingIconBounds.bottom += offsetY; SurfaceParams[] params = new SurfaceParams[appTargets.length]; for (int i = appTargets.length - 1; i >= 0; i--) { @@ -553,7 +574,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans matrix.setScale(scale, scale); matrix.postTranslate(windowTransX0, windowTransY0); - floatingView.update(iconBounds, mIconAlpha.value, percent, 0f, + floatingView.update(floatingIconBounds, mIconAlpha.value, percent, 0f, mWindowRadius.value * scale, true /* isOpening */); builder.withMatrix(matrix) .withWindowCrop(crop) @@ -932,8 +953,15 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans */ static class AnimOpenProperties { - public final float startCrop; - public final float endCrop; + public final int cropCenterXStart; + public final int cropCenterYStart; + public final int cropWidthStart; + public final int cropHeightStart; + + public final int cropCenterXEnd; + public final int cropCenterYEnd; + public final int cropWidthEnd; + public final int cropHeightEnd; public final float dX; public final float dY; @@ -948,7 +976,7 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans public final float iconAlphaStart; AnimOpenProperties(Resources r, DeviceProfile dp, Rect windowTargetBounds, - RectF launcherIconBounds, View view, int[] dragLayerBounds) { + RectF launcherIconBounds, View view, int dragLayerLeft, int dragLayerTop) { // Scale the app icon to take up the entire screen. This simplifies the math when // animating the app window position / scale. float smallestSize = Math.min(windowTargetBounds.height(), windowTargetBounds.width()); @@ -966,8 +994,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans finalAppIconScale = Math.max(maxScaleX, maxScaleY); // Animate the app icon to the center of the window bounds in screen coordinates. - float centerX = windowTargetBounds.centerX() - dragLayerBounds[0]; - float centerY = windowTargetBounds.centerY() - dragLayerBounds[1]; + float centerX = windowTargetBounds.centerX() - dragLayerLeft; + float centerY = windowTargetBounds.centerY() - dragLayerTop; dX = centerX - launcherIconBounds.centerX(); dY = centerY - launcherIconBounds.centerY(); @@ -981,15 +1009,31 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans alphaDuration = useUpwardAnimation ? APP_LAUNCH_ALPHA_DURATION : APP_LAUNCH_ALPHA_DOWN_DURATION; - if (dp.isVerticalBarLayout()) { - startCrop = windowTargetBounds.height(); - endCrop = windowTargetBounds.width(); + if (ENABLE_SHELL_STARTING_SURFACE) { + iconAlphaStart = 0; + + // TOOD: Share value from shell when available. + final float windowIconSize = Utilities.pxFromSp(108, r.getDisplayMetrics()); + + cropCenterXStart = windowTargetBounds.centerX(); + cropCenterYStart = windowTargetBounds.centerY(); + + cropWidthStart = (int) windowIconSize; + cropHeightStart = (int) windowIconSize; } else { - startCrop = windowTargetBounds.width(); - endCrop = windowTargetBounds.height(); + iconAlphaStart = 1; + + cropWidthStart = cropHeightStart = + Math.min(windowTargetBounds.width(), windowTargetBounds.height()); + cropCenterXStart = cropCenterYStart = + Math.min(windowTargetBounds.centerX(), windowTargetBounds.centerY()); } - iconAlphaStart = 1f; + cropWidthEnd = windowTargetBounds.width(); + cropHeightEnd = windowTargetBounds.height(); + + cropCenterXEnd = windowTargetBounds.centerX(); + cropCenterYEnd = windowTargetBounds.centerY(); } } }