From 0c4d278ed2f4602c3ae20e63145eade1b6fc0ba0 Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Thu, 29 Apr 2021 15:56:13 -0700 Subject: [PATCH 1/7] Don't fade out active page outline during drag-and-drop => Keep page backgrounds stable and only slightly modify the alpha + add stroke for active page => Don't shrink cell outlines to be too small (issue in hotseat on some devices) => Reduce cell radius to 22dp Bug: 185163323 Test: manual Change-Id: Ic17999f5672a3355dceeb25af923f02e960389d9 --- res/color/cell_layout_bg_color_active.xml | 2 +- res/color/cell_layout_bg_color_inactive.xml | 2 +- res/values/config.xml | 2 +- res/values/dimens.xml | 2 +- src/com/android/launcher3/CellLayout.java | 25 ++++++++++++--------- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/res/color/cell_layout_bg_color_active.xml b/res/color/cell_layout_bg_color_active.xml index e826489944..d1a3d7c48f 100644 --- a/res/color/cell_layout_bg_color_active.xml +++ b/res/color/cell_layout_bg_color_active.xml @@ -1,5 +1,5 @@ - diff --git a/res/color/cell_layout_bg_color_inactive.xml b/res/color/cell_layout_bg_color_inactive.xml index d60a27a120..0632100dfc 100644 --- a/res/color/cell_layout_bg_color_inactive.xml +++ b/res/color/cell_layout_bg_color_inactive.xml @@ -1,5 +1,5 @@ - \ No newline at end of file diff --git a/res/values/config.xml b/res/values/config.xml index f8a517d1d0..1e7837353f 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -35,7 +35,7 @@ - 900 + 500 255 diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 600a550700..0a6cce943c 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -293,7 +293,7 @@ 0dp - 28dp + 22dp 6dp diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index c3816ccf0c..2f755e11e0 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -502,7 +502,7 @@ public class CellLayout extends ViewGroup { } private void updateBgAlpha() { - mBackground.setAlpha((int) (mSpringLoadedProgress * mScrollProgress * 255)); + mBackground.setAlpha((int) (mSpringLoadedProgress * 255)); } /** @@ -525,9 +525,12 @@ public class CellLayout extends ViewGroup { } protected void visualizeGrid(Canvas canvas) { - mVisualizeGridRect.set(mGridVisualizationPadding, mGridVisualizationPadding, - mCellWidth - mGridVisualizationPadding, - mCellHeight - mGridVisualizationPadding); + DeviceProfile dp = mActivity.getDeviceProfile(); + int paddingX = (int) Math.min((mCellWidth - dp.iconSizePx) / 2, mGridVisualizationPadding); + int paddingY = (int) Math.min((mCellHeight - dp.iconSizePx) / 2, mGridVisualizationPadding); + mVisualizeGridRect.set(paddingX, paddingY, + mCellWidth - paddingX, + mCellHeight - paddingY); mVisualizeGridPaint.setStrokeWidth(8); int paintAlpha = (int) (120 * mGridAlpha); @@ -537,9 +540,9 @@ public class CellLayout extends ViewGroup { for (int i = 0; i < mCountX; i++) { for (int j = 0; j < mCountY; j++) { int transX = i * mCellWidth + (i * mBorderSpacing) + getPaddingLeft() - + mGridVisualizationPadding; + + paddingX; int transY = j * mCellHeight + (j * mBorderSpacing) + getPaddingTop() - + mGridVisualizationPadding; + + paddingY; mVisualizeGridRect.offsetTo(transX, transY); mVisualizeGridPaint.setStyle(Paint.Style.FILL); @@ -560,14 +563,14 @@ public class CellLayout extends ViewGroup { int spanX = mDragOutlines[i].cellHSpan; int spanY = mDragOutlines[i].cellVSpan; - mVisualizeGridRect.set(mGridVisualizationPadding, mGridVisualizationPadding, - mCellWidth * spanX - mGridVisualizationPadding, - mCellHeight * spanY - mGridVisualizationPadding); + mVisualizeGridRect.set(paddingX, paddingY, + mCellWidth * spanX - paddingX, + mCellHeight * spanY - paddingY); int transX = x * mCellWidth + (x * mBorderSpacing) - + getPaddingLeft() + mGridVisualizationPadding; + + getPaddingLeft() + paddingX; int transY = y * mCellHeight + (y * mBorderSpacing) - + getPaddingTop() + mGridVisualizationPadding; + + getPaddingTop() + paddingY; mVisualizeGridRect.offsetTo(transX, transY); From 3bdfc3cd2d77715164fada62fdf27a57369646f5 Mon Sep 17 00:00:00 2001 From: Cyrus Boadway Date: Thu, 29 Apr 2021 11:35:04 +0000 Subject: [PATCH 2/7] Create return-to-home app widget animation If an app has been most recently launched from an app widget, when swiped away, the app animates to the widget's position. This is done by attributing the app launch to the widget through the ActivityOptions's launch cookies, and using a FloatingWidgetView throughout the animation. Bug: 169042867 Test: manual Change-Id: I24c2623b5b3407504a4768b076849c47f73cbae0 --- .../launcher3/BaseQuickstepLauncher.java | 3 +- .../launcher3/QuickstepTransitionManager.java | 5 +- .../QuickstepInteractionHandler.java | 5 + .../quickstep/LauncherSwipeHandlerV2.java | 341 ++++++++++-------- .../quickstep/SwipeUpAnimationLogic.java | 12 +- .../quickstep/views/FloatingWidgetView.java | 14 +- 6 files changed, 224 insertions(+), 156 deletions(-) diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index 7aae38c7f1..9dbe9c225a 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -447,7 +447,8 @@ public abstract class BaseQuickstepLauncher extends Launcher case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: - // Fall through and continue if it's an app or shortcut + case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: + // Fall through and continue if it's an app, shortcut, or widget break; default: return; diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 1a464b14b2..6b190ed4b4 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -60,6 +60,7 @@ import android.os.Handler; import android.os.Looper; import android.os.SystemProperties; import android.util.Pair; +import android.util.Size; import android.view.View; import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; @@ -781,7 +782,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final float finalWindowRadius = mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher.getResources()); final FloatingWidgetView floatingView = FloatingWidgetView.getFloatingWidgetView(mLauncher, - v, widgetBackgroundBounds, windowTargetBounds, finalWindowRadius); + v, widgetBackgroundBounds, + new Size(windowTargetBounds.width(), windowTargetBounds.height()), + finalWindowRadius); final float initialWindowRadius = supportsRoundedCornersOnWindows(mLauncher.getResources()) ? floatingView.getInitialCornerRadius() : 0; diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java index 66e4f4c61c..5c19ab8bf4 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java @@ -23,6 +23,7 @@ import android.util.Pair; import android.view.View; import android.widget.RemoteViews; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.widget.LauncherAppWidgetHostView; @@ -49,6 +50,10 @@ class QuickstepInteractionHandler implements RemoteViews.InteractionHandler { Pair options = remoteResponse.getLaunchOptions(hostView); ActivityOptionsWrapper activityOptions = mLauncher.getAppTransitionManager() .getActivityLaunchOptions(mLauncher, hostView); + Object itemInfo = hostView.getTag(); + if (itemInfo instanceof ItemInfo) { + mLauncher.addLaunchCookie((ItemInfo) itemInfo, activityOptions.options); + } options = Pair.create(options.first, activityOptions.options); return RemoteViews.startPendingIntent(hostView, pendingIntent, options); } diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index dd35d68dcf..99c5baf37d 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -30,9 +30,11 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.content.Context; +import android.graphics.Rect; import android.graphics.RectF; import android.os.IBinder; import android.os.UserHandle; +import android.util.Size; import android.view.View; import androidx.annotation.NonNull; @@ -50,9 +52,11 @@ import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.util.DynamicResource; import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.views.FloatingIconView; +import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.quickstep.util.AppCloseConfig; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.StaggeredWorkspaceAnim; +import com.android.quickstep.views.FloatingWidgetView; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.plugins.ResourceProvider; @@ -77,155 +81,206 @@ public class LauncherSwipeHandlerV2 extends @Override protected HomeAnimationFactory createHomeAnimationFactory(ArrayList launchCookies, long duration) { - HomeAnimationFactory homeAnimFactory; - if (mActivity != null) { - final View workspaceView = findWorkspaceView(launchCookies, - mRecentsView.getRunningTaskView()); - boolean canUseWorkspaceView = - workspaceView != null && workspaceView.isAttachedToWindow(); - - mActivity.getRootView().setForceHideBackArrow(true); - mActivity.setHintUserWillBeActive(); - - if (canUseWorkspaceView) { - final ResourceProvider rp = DynamicResource.provider(mActivity); - final float transY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp)); - float dpPerSecond = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp_per_s)); - final float launcherAlphaMax = - rp.getFloat(R.dimen.swipe_up_launcher_alpha_max_progress); - - RectF iconLocation = new RectF(); - FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView, - true /* hideOriginal */, iconLocation, false /* isOpening */); - - // We want the window alpha to be 0 once this threshold is met, so that the - // FolderIconView can be seen morphing into the icon shape. - float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION; - homeAnimFactory = new LauncherHomeAnimationFactory() { - - // There is a delay in loading the icon, so we need to keep the window - // opaque until it is ready. - private boolean mIsFloatingIconReady = false; - - private @Nullable ValueAnimator mBounceBackAnimator; - - @Override - public RectF getWindowTargetRect() { - if (PROTOTYPE_APP_CLOSE.get()) { - // We want the target rect to be at this offset position, so that all - // launcher content can spring back upwards. - floatingIconView.setPositionOffsetY(transY); - } - return iconLocation; - } - - @Override - public void setAnimation(RectFSpringAnim anim) { - anim.addAnimatorListener(floatingIconView); - floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged); - floatingIconView.setFastFinishRunnable(anim::end); - if (PROTOTYPE_APP_CLOSE.get()) { - mBounceBackAnimator = bounceBackToRestingPosition(); - // Use a spring to put drag layer translation back to 0. - anim.addAnimatorListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - floatingIconView.setPositionOffsetY(0); - mBounceBackAnimator.start(); - } - }); - - Workspace workspace = mActivity.getWorkspace(); - workspace.setPivotToScaleWithSelf(mActivity.getHotseat()); - } - } - - private ValueAnimator bounceBackToRestingPosition() { - DragLayer dl = mActivity.getDragLayer(); - Workspace workspace = mActivity.getWorkspace(); - Hotseat hotseat = mActivity.getHotseat(); - - final float startValue = transY; - final float endValue = 0; - // Ensures the velocity is always aligned with the direction. - float pixelPerSecond = Math.abs(dpPerSecond) - * Math.signum(endValue - transY); - - ValueAnimator springTransY = new SpringAnimationBuilder(dl.getContext()) - .setStiffness(rp.getFloat(R.dimen.swipe_up_trans_y_stiffness)) - .setDampingRatio(rp.getFloat(R.dimen.swipe_up_trans_y_damping)) - .setMinimumVisibleChange(1f) - .setStartValue(startValue) - .setEndValue(endValue) - .setStartVelocity(pixelPerSecond) - .build(dl, VIEW_TRANSLATE_Y); - springTransY.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - dl.setTranslationY(0f); - dl.setAlpha(1f); - SCALE_PROPERTY.set(workspace, 1f); - SCALE_PROPERTY.set(hotseat, 1f); - } - }); - return springTransY; - } - - @Override - public boolean keepWindowOpaque() { - if (mIsFloatingIconReady || floatingIconView.isVisibleToUser()) { - mIsFloatingIconReady = true; - return false; - } - return true; - } - - @Override - public void update(@Nullable AppCloseConfig config, RectF currentRect, - float progress, float radius) { - int fgAlpha = 255; - if (config != null && PROTOTYPE_APP_CLOSE.get()) { - DragLayer dl = mActivity.getDragLayer(); - float translationY = config.getWorkspaceTransY(); - dl.setTranslationY(translationY); - - float alpha = mapToRange(progress, 0, launcherAlphaMax, 0, 1f, LINEAR); - dl.setAlpha(Math.min(alpha, 1f)); - - float scale = Math.min(1f, config.getWorkspaceScale()); - SCALE_PROPERTY.set(mActivity.getWorkspace(), scale); - SCALE_PROPERTY.set(mActivity.getHotseat(), scale); - SCALE_PROPERTY.set(mActivity.getAppsView(), scale); - - progress = config.getInterpolatedProgress(); - fgAlpha = config.getFgAlpha(); - } - floatingIconView.update(1f, fgAlpha, currentRect, progress, - windowAlphaThreshold, radius, false); - } - - @Override - public void onCancel() { - floatingIconView.fastFinish(); - if (mBounceBackAnimator != null) { - mBounceBackAnimator.cancel(); - } - } - }; - } else { - homeAnimFactory = new LauncherHomeAnimationFactory(); - } - } else { - homeAnimFactory = new HomeAnimationFactory() { + if (mActivity == null) { + mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, + isPresent -> mRecentsView.startHome()); + return new HomeAnimationFactory() { @Override public AnimatorPlaybackController createActivityAnimationToHome() { return AnimatorPlaybackController.wrap(new AnimatorSet(), duration); } }; - mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, - isPresent -> mRecentsView.startHome()); } - return homeAnimFactory; + + final View workspaceView = findWorkspaceView(launchCookies, + mRecentsView.getRunningTaskView()); + boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow(); + + mActivity.getRootView().setForceHideBackArrow(true); + mActivity.setHintUserWillBeActive(); + + if (!canUseWorkspaceView) { + return new LauncherHomeAnimationFactory(); + } + if (workspaceView instanceof LauncherAppWidgetHostView) { + return createWidgetHomeAnimationFactory((LauncherAppWidgetHostView) workspaceView); + } + return createIconHomeAnimationFactory(workspaceView); + } + + private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) { + final ResourceProvider rp = DynamicResource.provider(mActivity); + final float transY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp)); + float dpPerSecond = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp_per_s)); + final float launcherAlphaMax = + rp.getFloat(R.dimen.swipe_up_launcher_alpha_max_progress); + + RectF iconLocation = new RectF(); + FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView, + true /* hideOriginal */, iconLocation, false /* isOpening */); + + // We want the window alpha to be 0 once this threshold is met, so that the + // FolderIconView can be seen morphing into the icon shape. + float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION; + return new LauncherHomeAnimationFactory() { + + // There is a delay in loading the icon, so we need to keep the window + // opaque until it is ready. + private boolean mIsFloatingIconReady = false; + + private @Nullable ValueAnimator mBounceBackAnimator; + + @Override + public RectF getWindowTargetRect() { + if (PROTOTYPE_APP_CLOSE.get()) { + // We want the target rect to be at this offset position, so that all + // launcher content can spring back upwards. + floatingIconView.setPositionOffsetY(transY); + } + return iconLocation; + } + + @Override + public void setAnimation(RectFSpringAnim anim) { + anim.addAnimatorListener(floatingIconView); + floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged); + floatingIconView.setFastFinishRunnable(anim::end); + if (PROTOTYPE_APP_CLOSE.get()) { + mBounceBackAnimator = bounceBackToRestingPosition(); + // Use a spring to put drag layer translation back to 0. + anim.addAnimatorListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + floatingIconView.setPositionOffsetY(0); + mBounceBackAnimator.start(); + } + }); + + Workspace workspace = mActivity.getWorkspace(); + workspace.setPivotToScaleWithSelf(mActivity.getHotseat()); + } + } + + private ValueAnimator bounceBackToRestingPosition() { + DragLayer dl = mActivity.getDragLayer(); + Workspace workspace = mActivity.getWorkspace(); + Hotseat hotseat = mActivity.getHotseat(); + + final float startValue = transY; + final float endValue = 0; + // Ensures the velocity is always aligned with the direction. + float pixelPerSecond = Math.abs(dpPerSecond) * Math.signum(endValue - transY); + + ValueAnimator springTransY = new SpringAnimationBuilder(dl.getContext()) + .setStiffness(rp.getFloat(R.dimen.swipe_up_trans_y_stiffness)) + .setDampingRatio(rp.getFloat(R.dimen.swipe_up_trans_y_damping)) + .setMinimumVisibleChange(1f) + .setStartValue(startValue) + .setEndValue(endValue) + .setStartVelocity(pixelPerSecond) + .build(dl, VIEW_TRANSLATE_Y); + springTransY.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + dl.setTranslationY(0f); + dl.setAlpha(1f); + SCALE_PROPERTY.set(workspace, 1f); + SCALE_PROPERTY.set(hotseat, 1f); + } + }); + return springTransY; + } + + @Override + public boolean keepWindowOpaque() { + if (mIsFloatingIconReady || floatingIconView.isVisibleToUser()) { + mIsFloatingIconReady = true; + return false; + } + return true; + } + + @Override + public void update(@Nullable AppCloseConfig config, RectF currentRect, + float progress, float radius) { + int fgAlpha = 255; + if (config != null && PROTOTYPE_APP_CLOSE.get()) { + DragLayer dl = mActivity.getDragLayer(); + float translationY = config.getWorkspaceTransY(); + dl.setTranslationY(translationY); + + float alpha = mapToRange(progress, 0, launcherAlphaMax, 0, 1f, LINEAR); + dl.setAlpha(Math.min(alpha, 1f)); + + float scale = Math.min(1f, config.getWorkspaceScale()); + SCALE_PROPERTY.set(mActivity.getWorkspace(), scale); + SCALE_PROPERTY.set(mActivity.getHotseat(), scale); + SCALE_PROPERTY.set(mActivity.getAppsView(), scale); + + progress = config.getInterpolatedProgress(); + fgAlpha = config.getFgAlpha(); + } + floatingIconView.update(1f, fgAlpha, currentRect, progress, + windowAlphaThreshold, radius, false); + } + + @Override + public void onCancel() { + floatingIconView.fastFinish(); + if (mBounceBackAnimator != null) { + mBounceBackAnimator.cancel(); + } + } + }; + } + + private HomeAnimationFactory createWidgetHomeAnimationFactory( + LauncherAppWidgetHostView hostView) { + + RectF backgroundLocation = new RectF(); + Rect crop = new Rect(); + mTaskViewSimulator.getCurrentCropRect().roundOut(crop); + Size windowSize = new Size(crop.width(), crop.height()); + FloatingWidgetView floatingWidgetView = FloatingWidgetView.getFloatingWidgetView(mActivity, + hostView, backgroundLocation, windowSize, + mTaskViewSimulator.getCurrentCornerRadius()); + + return new LauncherHomeAnimationFactory() { + + @Override + public RectF getWindowTargetRect() { + return backgroundLocation; + } + + @Override + public float getEndRadius(RectF cropRectF) { + return floatingWidgetView.getInitialCornerRadius(); + } + + @Override + public void setAnimation(RectFSpringAnim anim) { + anim.addAnimatorListener(floatingWidgetView); + floatingWidgetView.setFastFinishRunnable(anim::end); + } + + @Override + public boolean keepWindowOpaque() { + return false; + } + + @Override + public void update(@Nullable AppCloseConfig config, RectF currentRect, + float progress, float radius) { + floatingWidgetView.update(currentRect, 1 /* floatingWidgetAlpha */, + config != null ? config.getFgAlpha() : 1f /* foregroundAlpha */, + 0 /* fallbackBackgroundAlpha */, 1 - progress); + } + + @Override + public void onCancel() { + floatingWidgetView.fastFinish(); + } + }; } /** diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java index 0f34a72ad4..29a00d16b0 100644 --- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -145,6 +145,11 @@ public abstract class SwipeUpAnimationLogic { targetX + halfIconSize, targetY + halfIconSize); } + /** Returns the corner radius of the window at the end of the animation. */ + public float getEndRadius(RectF cropRectF) { + return cropRectF.width() / 2f; + } + public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome(); public void playAtomicAnimation(float velocity) { @@ -197,8 +202,7 @@ public abstract class SwipeUpAnimationLogic { final RectF targetRect = homeAnimationFactory.getWindowTargetRect(); Matrix homeToWindowPositionMap = new Matrix(); - final RectF startRect = updateProgressForStartRect( - homeToWindowPositionMap, startProgress); + final RectF startRect = updateProgressForStartRect(homeToWindowPositionMap, startProgress); RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect()); // Move the startRect to Launcher space as floatingIconView runs in Launcher @@ -210,7 +214,7 @@ public abstract class SwipeUpAnimationLogic { if (PROTOTYPE_APP_CLOSE.get()) { anim = new RectFSpringAnim2(startRect, targetRect, mContext, mTaskViewSimulator.getCurrentCornerRadius(), - cropRectF.width() / 2f); + homeAnimationFactory.getEndRadius(cropRectF)); } else { anim = new RectFSpringAnim(startRect, targetRect, mContext); } @@ -269,7 +273,7 @@ public abstract class SwipeUpAnimationLogic { // End on a "round-enough" radius so that the shape reveal doesn't have to do too much // rounding at the end of the animation. mStartRadius = mTaskViewSimulator.getCurrentCornerRadius(); - mEndRadius = cropRectF.width() / 2f; + mEndRadius = factory.getEndRadius(cropRectF); } @Override diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java index d23884c9ef..8499902f23 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java @@ -20,10 +20,10 @@ import android.animation.Animator.AnimatorListener; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Matrix; -import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; import android.util.AttributeSet; +import android.util.Size; import android.view.GhostView; import android.view.View; import android.view.ViewGroup; @@ -113,7 +113,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener } private void init(DragLayer dragLayer, LauncherAppWidgetHostView originalView, - RectF widgetBackgroundPosition, Rect windowTargetBounds, float windowCornerRadius) { + RectF widgetBackgroundPosition, Size windowSize, float windowCornerRadius) { mAppWidgetView = originalView; mAppWidgetView.beginDeferringUpdates(); mBackgroundPosition = widgetBackgroundPosition; @@ -128,7 +128,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener getRelativePosition(mAppWidgetBackgroundView, mAppWidgetView, mBackgroundOffset); mBackgroundView.init(mAppWidgetView, mAppWidgetBackgroundView, windowCornerRadius); // Layout call before GhostView creation so that the overlaid view isn't clipped - layout(0, 0, windowTargetBounds.width(), windowTargetBounds.height()); + layout(0, 0, windowSize.getWidth(), windowSize.getHeight()); mForegroundOverlayView = GhostView.addGhost(mAppWidgetView, this); positionViews(); @@ -219,19 +219,19 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener * * @param widgetBackgroundPosition a {@link RectF} that will be updated with the widget's * background bounds - * @param windowTargetBounds the bounds of the window when launched + * @param windowSize the size of the window when launched * @param windowCornerRadius the corner radius of the window */ public static FloatingWidgetView getFloatingWidgetView(Launcher launcher, LauncherAppWidgetHostView originalView, RectF widgetBackgroundPosition, - Rect windowTargetBounds, float windowCornerRadius) { + Size windowSize, float windowCornerRadius) { final DragLayer dragLayer = launcher.getDragLayer(); ViewGroup parent = (ViewGroup) dragLayer.getParent(); FloatingWidgetView floatingView = launcher.getViewCache().getView(R.layout.floating_widget_view, launcher, parent); floatingView.recycle(); - floatingView.init(dragLayer, originalView, widgetBackgroundPosition, windowTargetBounds, + floatingView.init(dragLayer, originalView, widgetBackgroundPosition, windowSize, windowCornerRadius); parent.addView(floatingView); return floatingView; @@ -240,7 +240,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener private static void getRelativePosition(View descendant, View ancestor, RectF position) { float[] points = new float[]{0, 0, descendant.getWidth(), descendant.getHeight()}; Utilities.getDescendantCoordRelativeToAncestor(descendant, ancestor, points, - false /* includeRootScroll */); + false /* includeRootScroll */, true /* ignoreTransform */); position.set( Math.min(points[0], points[2]), Math.min(points[1], points[3]), From 908e3d1312693682642a3093c11df13a9c1583d0 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 30 Apr 2021 14:18:08 -0700 Subject: [PATCH 3/7] Fixing nullPointer exception when wallpaper colors is null Bug: 186722571 Test: Presubmit Change-Id: Iee0d15d460de47cc20395cf9f3d92784aef6268e --- src/com/android/launcher3/util/Themes.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java index 11b856e266..99942aa56d 100644 --- a/src/com/android/launcher3/util/Themes.java +++ b/src/com/android/launcher3/util/Themes.java @@ -19,6 +19,7 @@ package com.android.launcher3.util; import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_TEXT; import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_THEME; +import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.Context; import android.content.res.Configuration; @@ -41,9 +42,14 @@ import com.android.launcher3.icons.GraphicsUtils; public class Themes { public static int getActivityThemeRes(Context context) { - int colorHints = Utilities.ATLEAST_P ? context.getSystemService(WallpaperManager.class) - .getWallpaperColors(WallpaperManager.FLAG_SYSTEM).getColorHints() - : 0; + final int colorHints; + if (Utilities.ATLEAST_P) { + WallpaperColors colors = context.getSystemService(WallpaperManager.class) + .getWallpaperColors(WallpaperManager.FLAG_SYSTEM); + colorHints = colors == null ? 0 : colors.getColorHints(); + } else { + colorHints = 0; + } return getActivityThemeRes(context, colorHints); } From bdf64e79bd86b8c1b15fb5db9cd7ea1da0ae395b Mon Sep 17 00:00:00 2001 From: Jon Spivack Date: Thu, 29 Apr 2021 19:08:03 -0700 Subject: [PATCH 4/7] Add app package names to NIU Actions Intents This adds the package name of the currently suspended app to the NIU Actions Intents, for logging purposes. Bug: 186388671 Test: Manual (printed out the Intent extras while trying various apps) Test: m -j RunLauncherGoGoogleRoboTests Change-Id: I8180347675c8940c960e4aa4c47dec508207c780 --- .../src/com/android/quickstep/TaskOverlayFactoryGo.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java index 79e50ef35b..67e9d898e5 100644 --- a/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java +++ b/go/quickstep/src/com/android/quickstep/TaskOverlayFactoryGo.java @@ -49,6 +49,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { public static final String ACTION_SEARCH = "com.android.quickstep.ACTION_SEARCH"; public static final String ELAPSED_NANOS = "niu_actions_elapsed_realtime_nanos"; public static final String ACTIONS_URL = "niu_actions_app_url"; + public static final String ACTIONS_APP_PACKAGE = "niu_actions_app_package"; public static final String ACTIONS_ERROR_CODE = "niu_actions_app_error_code"; public static final int ERROR_PERMISSIONS = 1; private static final String TAG = "TaskOverlayFactoryGo"; @@ -72,6 +73,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { */ public static final class TaskOverlayGo extends TaskOverlay { private String mNIUPackageName; + private String mTaskPackageName; private String mWebUrl; private boolean mAssistPermissionsEnabled; @@ -87,7 +89,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { boolean rotated) { getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null); mNIUPackageName = - mApplicationContext.getResources().getString(R.string.niu_actions_package); + mApplicationContext.getString(R.string.niu_actions_package); if (thumbnail == null || TextUtils.isEmpty(mNIUPackageName)) { return; @@ -96,6 +98,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { getActionsView().updateDisabledFlags(DISABLED_ROTATED, rotated); boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot(); getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task)); + mTaskPackageName = task.key.getPackageName(); checkPermissions(); if (!mAssistPermissionsEnabled) { @@ -150,6 +153,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory { .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION) .setPackage(mNIUPackageName) + .putExtra(ACTIONS_APP_PACKAGE, mTaskPackageName) .putExtra(ELAPSED_NANOS, SystemClock.elapsedRealtimeNanos()); if (mWebUrl != null) { From 20d00faf727a15d03db4fe6f24f330bc28dfaf19 Mon Sep 17 00:00:00 2001 From: Zak Cohen Date: Fri, 30 Apr 2021 14:43:52 -0700 Subject: [PATCH 5/7] Overview - fade task icon instead of scaling it per new ux Bug: 186256286 Test: Local build and run on p5 Change-Id: I318b62ddbf9cb475736d2844489a7ed2d9a8a409 --- quickstep/src/com/android/quickstep/views/TaskView.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 3349b74f05..45bcdc314b 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -777,8 +777,7 @@ public class TaskView extends FrameLayout implements Reusable { float upperClamp = invert ? 1 : iconScalePercentage; float scale = Interpolators.clampToProgress(FAST_OUT_SLOW_IN, lowerClamp, upperClamp) .getInterpolation(progress); - mIconView.setScaleX(scale); - mIconView.setScaleY(scale); + mIconView.setAlpha(scale); if (mContextualChipWrapper != null && mContextualChipWrapper != null) { mContextualChipWrapper.setAlpha(scale); mContextualChipWrapper.setScaleX(Math.min(scale, comp(mModalness))); From ef7b4d5dae976c1c6f4dbf5e43d6ab020361aa3a Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Sun, 2 May 2021 07:14:46 +0000 Subject: [PATCH 6/7] Revert "Revert "Finish recents animation upon home rotation"" This reverts commit 0f8787db8038301608e39418a7b15610dbcac425. Reason for revert: Revert and fix the broken tapl test Fixes: 184054813 Change-Id: Ib647e11bfa0a2dc79a5a815be56452bb07e04ddf --- .../src/com/android/quickstep/views/RecentsView.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index e5ce9509c8..1a0a1a4357 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -2486,6 +2486,15 @@ public abstract class RecentsView finishRecentsAnimation(true, this::onConfigurationChangedInternal)); + } else { + onConfigurationChangedInternal(); + } + } + + private void onConfigurationChangedInternal() { final int rotation = mActivity.getDisplay().getRotation(); if (mOrientationState.setRecentsRotation(rotation)) { updateOrientationHandler(); @@ -3438,7 +3447,7 @@ public abstract class RecentsView Date: Mon, 3 May 2021 16:42:11 +0000 Subject: [PATCH 7/7] Revert "Use color extraction for arrow popup." This reverts commit 242c805f8269d65391f257deb062969910f791b6. Reason for revert: Introduces a leak. I haven't seen a bug for it yet, but this CL is the only in the culprit list; the leak can block multiple teams presubmits, and the leak is via ArrowPopup. Enough evidence. https://fusion2.corp.google.com/invocations/4b50db71-d598-4e52-9076-e91d42b65014/targets Change-Id: I1700a9eea8705983598aee43c0a63e67c1d9cf71 Bug: 187075409 --- src/com/android/launcher3/CellLayout.java | 11 +- src/com/android/launcher3/Utilities.java | 50 -------- .../graphics/PreloadIconDrawable.java | 6 +- .../android/launcher3/popup/ArrowPopup.java | 105 +---------------- .../launcher3/util/ColorExtractionUtils.java | 110 ------------------ src/com/android/launcher3/util/Themes.java | 7 +- .../launcher3/views/FloatingIconView.java | 11 +- .../widget/LauncherAppWidgetHostView.java | 80 +++++++++---- .../launcher3/widget/LocalColorExtractor.java | 5 +- 9 files changed, 86 insertions(+), 299 deletions(-) delete mode 100644 src/com/android/launcher3/util/ColorExtractionUtils.java diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index a037675029..c3816ccf0c 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -18,7 +18,6 @@ package com.android.launcher3; import static android.animation.ValueAnimator.areAnimatorsEnabled; -import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer; import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5; import android.animation.Animator; @@ -194,7 +193,6 @@ public class CellLayout extends ViewGroup { private static final int INVALID_DIRECTION = -100; private final Rect mTempRect = new Rect(); - private final RectF mTempRectF = new RectF(); private static final Paint sPaint = new Paint(); @@ -1069,16 +1067,11 @@ public class CellLayout extends ViewGroup { // Apply local extracted color if the DragView is an AppWidgetHostViewDrawable. View view = dragObject.dragView.getContentView(); if (view instanceof LauncherAppWidgetHostView) { - Launcher launcher = Launcher.getLauncher(dragObject.dragView.getContext()); - Workspace workspace = launcher.getWorkspace(); + Workspace workspace = + Launcher.getLauncher(dragObject.dragView.getContext()).getWorkspace(); int screenId = workspace.getIdForScreen(this); int pageId = workspace.getPageIndexForScreenId(screenId); cellToRect(targetCell[0], targetCell[1], spanX, spanY, mTempRect); - - // Now get the rect in drag layer coordinates. - getBoundsForViewInDragLayer(launcher.getDragLayer(), workspace, mTempRect, false, - mTempRectF); - Utilities.setRect(mTempRectF, mTempRect); ((LauncherAppWidgetHostView) view).handleDrag(mTempRect, pageId); } } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 073a46c0e0..a799b4a33a 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -33,7 +33,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; -import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; @@ -85,7 +84,6 @@ import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.PackageManagerHelper; -import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.widget.PendingAddShortcutInfo; import java.lang.reflect.Method; @@ -106,8 +104,6 @@ public final class Utilities { private static final Pattern sTrimPattern = Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$"); - private static final float[] sTmpFloatArray = new float[4]; - private static final int[] sLoc0 = new int[2]; private static final int[] sLoc1 = new int[2]; private static final Matrix sMatrix = new Matrix(); @@ -137,15 +133,6 @@ public final class Utilities { Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") || Build.TYPE.toLowerCase(Locale.ROOT).equals("eng"); - /** - * Returns true if theme is dark. - */ - public static boolean isDarkTheme(Context context) { - Configuration configuration = context.getResources().getConfiguration(); - int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK; - return nightMode == Configuration.UI_MODE_NIGHT_YES; - } - public static boolean isDevelopersOptionsEnabled(Context context) { return Settings.Global.getInt(context.getApplicationContext().getContentResolver(), Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) != 0; @@ -231,33 +218,6 @@ public final class Utilities { return scale; } - /** - * Returns bounds for a child view of DragLayer, in drag layer coordinates. - * - * see {@link com.android.launcher3.dragndrop.DragLayer}. - * - * @param viewBounds Bounds of the view wanted in drag layer coordinates, relative to the view - * itself. eg. (0, 0, view.getWidth, view.getHeight) - * @param ignoreTransform If true, view transform is ignored - * @param outRect The out rect where we return the bounds of {@param view} in drag layer coords. - */ - public static void getBoundsForViewInDragLayer(BaseDragLayer dragLayer, View view, - Rect viewBounds, boolean ignoreTransform, RectF outRect) { - float[] points = sTmpFloatArray; - points[0] = viewBounds.left; - points[1] = viewBounds.top; - points[2] = viewBounds.right; - points[3] = viewBounds.bottom; - - Utilities.getDescendantCoordRelativeToAncestor(view, dragLayer, points, - false, ignoreTransform); - outRect.set( - Math.min(points[0], points[2]), - Math.min(points[1], points[3]), - Math.max(points[0], points[2]), - Math.max(points[1], points[3])); - } - /** * Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, float[], boolean)}. */ @@ -313,16 +273,6 @@ public final class Utilities { return new int[] {sLoc1[0] - sLoc0[0], sLoc1[1] - sLoc0[1]}; } - /** - * Helper method to set rectOut with rectFSrc. - */ - public static void setRect(RectF rectFSrc, Rect rectOut) { - rectOut.left = (int) rectFSrc.left; - rectOut.top = (int) rectFSrc.top; - rectOut.right = (int) rectFSrc.right; - rectOut.bottom = (int) rectFSrc.bottom; - } - public static void scaleRectFAboutCenter(RectF r, float scale) { if (scale != 1.0f) { float cx = r.centerX(); diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java index e45b8f7918..13ae866efb 100644 --- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -21,6 +21,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; @@ -33,7 +34,6 @@ import android.util.Property; import android.util.SparseArray; import android.view.ContextThemeWrapper; -import com.android.launcher3.Utilities; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.GraphicsUtils; @@ -119,7 +119,9 @@ public class PreloadIconDrawable extends FastBitmapDrawable { info, IconPalette.getPreloadProgressColor(context, info.bitmap.color), getPreloadColors(context), - Utilities.isDarkTheme(context)); + (context.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_NIGHT_MASK + & Configuration.UI_MODE_NIGHT_YES) != 0) /* isDarkMode */; } public PreloadIconDrawable( diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 48c5d0a854..c19dfe9300 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -16,9 +16,9 @@ package com.android.launcher3.popup; +import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType; import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL; import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS; -import static com.android.launcher3.util.ColorExtractionUtils.getColorExtractionRect; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -31,7 +31,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Outline; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; @@ -42,21 +41,17 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; -import android.view.ViewTreeObserver; import android.widget.FrameLayout; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.InsettableFrameLayout; -import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.Workspace; import com.android.launcher3.anim.RevealOutlineAnimation; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.dragndrop.DragLayer; @@ -64,11 +59,9 @@ import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; -import com.android.launcher3.widget.LocalColorExtractor; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; /** * A container for shortcuts to deep links and notifications associated with an app. @@ -80,9 +73,6 @@ public abstract class ArrowPopup> // +1 for system shortcut view private static final int MAX_NUM_CHILDREN = MAX_SHORTCUTS + 1; - // Index used to get background color when using local wallpaper color extraction, - private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50; - private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_800; private final Rect mTempRect = new Rect(); @@ -114,14 +104,8 @@ public abstract class ArrowPopup> private Runnable mOnCloseCallback = () -> { }; - // The rect string of the view that the arrow is attached to, in screen reference frame. - private String mArrowColorRectString; private int mArrowColor; private final int[] mColors; - private final HashMap mViewForRect = new HashMap<>(); - - private final int mColorExtractionIndex; - @Nullable private LocalColorExtractor mColorExtractor; public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); @@ -129,9 +113,7 @@ public abstract class ArrowPopup> mOutlineRadius = Themes.getDialogCornerRadius(context); mLauncher = BaseDraggingActivity.fromContext(context); mIsRtl = Utilities.isRtl(getResources()); - mColorExtractionIndex = Utilities.isDarkTheme(context) - ? DARK_COLOR_EXTRACTION_INDEX - : LIGHT_COLOR_EXTRACTION_INDEX; + setClipToOutline(true); setOutlineProvider(new ViewOutlineProvider() { @Override @@ -176,10 +158,6 @@ public abstract class ArrowPopup> mColors[i] = (int) argb.evaluate((i + 1) * step, primaryColor, secondaryColor); } - - if (Utilities.ATLEAST_S) { - setupColorExtraction(); - } } } @@ -364,15 +342,6 @@ public abstract class ArrowPopup> // so we centered it instead. In that case we don't want to showDefaultOptions the arrow. mArrow.setVisibility(INVISIBLE); } else { - updateArrowColor(); - } - - mArrow.setPivotX(mArrowWidth / 2.0f); - mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0); - } - - private void updateArrowColor() { - if (!Gravity.isVertical(mGravity)) { mArrow.setBackground(new RoundedArrowDrawable( mArrowWidth, mArrowHeight, mArrowPointRadius, mOutlineRadius, getMeasuredWidth(), getMeasuredHeight(), @@ -381,6 +350,9 @@ public abstract class ArrowPopup> mArrowColor)); mArrow.setElevation(getElevation()); } + + mArrow.setPivotX(mArrowWidth / 2.0f); + mArrow.setPivotY(mIsAboveIcon ? mArrowHeight : 0); } /** @@ -699,11 +671,6 @@ public abstract class ArrowPopup> getPopupContainer().removeView(this); getPopupContainer().removeView(mArrow); mOnCloseCallback.run(); - mArrowColorRectString = null; - mViewForRect.clear(); - if (mColorExtractor != null) { - mColorExtractor.removeLocations(); - } } /** @@ -713,68 +680,6 @@ public abstract class ArrowPopup> mOnCloseCallback = callback; } - private void setupColorExtraction() { - Workspace workspace = mLauncher.findViewById(R.id.workspace); - if (workspace == null) { - return; - } - - mColorExtractor = LocalColorExtractor.newInstance(mLauncher); - mColorExtractor.setListener((rect, extractedColors) -> { - String rectString = rect.toShortString(); - View v = mViewForRect.get(rectString); - if (v != null) { - int newColor = extractedColors.get(mColorExtractionIndex); - setChildColor(v, newColor); - if (rectString.equals(mArrowColorRectString)) { - mArrowColor = newColor; - updateArrowColor(); - } - } - }); - - getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - getViewTreeObserver().removeOnPreDrawListener(this); - - ArrayList locations = new ArrayList<>(); - Rect r = new Rect(); - - int count = getChildCount(); - int numVisibleChild = 0; - for (int i = 0; i < count; i++) { - View view = getChildAt(i); - if (view.getVisibility() == VISIBLE) { - RectF rf = new RectF(); - getColorExtractionRect(Launcher.getLauncher(getContext()), - workspace.getCurrentPage(), view, rf); - if (rf.isEmpty()) { - numVisibleChild++; - continue; - } - - locations.add(rf); - String rectString = rf.toShortString(); - mViewForRect.put(rectString, view); - - // Arrow color matches the first child or the last child. - if (!mIsAboveIcon && numVisibleChild == 0) { - mArrowColorRectString = rectString; - } else if (mIsAboveIcon) { - mArrowColorRectString = rectString; - } - - numVisibleChild++; - } - } - - mColorExtractor.addLocation(locations); - return false; - } - }); - } - protected BaseDragLayer getPopupContainer() { return mLauncher.getDragLayer(); } diff --git a/src/com/android/launcher3/util/ColorExtractionUtils.java b/src/com/android/launcher3/util/ColorExtractionUtils.java deleted file mode 100644 index b377ded44a..0000000000 --- a/src/com/android/launcher3/util/ColorExtractionUtils.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2021 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.launcher3.util; - -import android.content.res.Resources; -import android.graphics.Rect; -import android.graphics.RectF; -import android.view.View; - -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Launcher; -import com.android.launcher3.Utilities; - -/** - * Utility class used to map launcher views to wallpaper rect. - */ -public class ColorExtractionUtils { - - public static final String TAG = "ColorExtractionUtils"; - - private static final Rect sTempRect = new Rect(); - private static final RectF sTempRectF = new RectF(); - - /** - * Takes a view and returns its rect that can be used by the wallpaper local color extractor. - * - * @param launcher Launcher class class. - * @param pageId The page the workspace item is on. - * @param v The view. - * @param colorExtractionRectOut The location rect, but converted to a format expected by the - * wallpaper local color extractor. - */ - public static void getColorExtractionRect(Launcher launcher, int pageId, View v, - RectF colorExtractionRectOut) { - Rect viewRect = sTempRect; - viewRect.set(0, 0, v.getWidth(), v.getHeight()); - Utilities.getBoundsForViewInDragLayer(launcher.getDragLayer(), v, viewRect, false, - sTempRectF); - Utilities.setRect(sTempRectF, viewRect); - getColorExtractionRect(launcher, pageId, viewRect, colorExtractionRectOut); - } - - /** - * Takes a rect in drag layer coordinates and returns the rect that can be used by the wallpaper - * local color extractor. - * - * @param launcher Launcher class. - * @param pageId The page the workspace item is on. - * @param rectInDragLayer The relevant bounds of the view in drag layer coordinates. - * @param colorExtractionRectOut The location rect, but converted to a format expected by the - * wallpaper local color extractor. - */ - public static void getColorExtractionRect(Launcher launcher, int pageId, Rect rectInDragLayer, - RectF colorExtractionRectOut) { - // If the view hasn't been measured and laid out, we cannot do this. - if (rectInDragLayer.isEmpty()) { - colorExtractionRectOut.setEmpty(); - return; - } - - Resources res = launcher.getResources(); - DeviceProfile dp = launcher.getDeviceProfile().inv.getDeviceProfile(launcher); - float screenWidth = dp.widthPx; - float screenHeight = dp.heightPx; - int numScreens = launcher.getWorkspace().getNumPagesForWallpaperParallax(); - pageId = Utilities.isRtl(res) ? numScreens - pageId - 1 : pageId; - float relativeScreenWidth = 1f / numScreens; - - int[] dragLayerBounds = new int[2]; - launcher.getDragLayer().getLocationOnScreen(dragLayerBounds); - // Translate from drag layer coordinates to screen coordinates. - int screenLeft = rectInDragLayer.left + dragLayerBounds[0]; - int screenTop = rectInDragLayer.top + dragLayerBounds[1]; - int screenRight = rectInDragLayer.right + dragLayerBounds[0]; - int screenBottom = rectInDragLayer.bottom + dragLayerBounds[1]; - - // This is the position of the view relative to the wallpaper, as expected by the - // local color extraction of the WallpaperManager. - // The coordinate system is such that, on the horizontal axis, each screen has a - // distinct range on the [0,1] segment. So if there are 3 screens, they will have the - // ranges [0, 1/3], [1/3, 2/3] and [2/3, 1]. The position on the subrange should be - // the position of the view relative to the screen. For the vertical axis, this is - // simply the location of the view relative to the screen. - // Translate from drag layer coordinates to screen coordinates - colorExtractionRectOut.left = (screenLeft / screenWidth + pageId) * relativeScreenWidth; - colorExtractionRectOut.right = (screenRight / screenWidth + pageId) * relativeScreenWidth; - colorExtractionRectOut.top = screenTop / screenHeight; - colorExtractionRectOut.bottom = screenBottom / screenHeight; - - if (colorExtractionRectOut.left < 0 - || colorExtractionRectOut.right > 1 - || colorExtractionRectOut.top < 0 - || colorExtractionRectOut.bottom > 1) { - colorExtractionRectOut.setEmpty(); - } - } -} diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java index 898ac255d5..11b856e266 100644 --- a/src/com/android/launcher3/util/Themes.java +++ b/src/com/android/launcher3/util/Themes.java @@ -21,6 +21,7 @@ import static android.app.WallpaperColors.HINT_SUPPORTS_DARK_THEME; import android.app.WallpaperManager; import android.content.Context; +import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.ColorMatrix; @@ -47,12 +48,16 @@ public class Themes { } public static int getActivityThemeRes(Context context, int wallpaperColorHints) { + Configuration configuration = context.getResources().getConfiguration(); + int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK; + boolean darkTheme = nightMode == Configuration.UI_MODE_NIGHT_YES; + boolean supportsDarkText = Utilities.ATLEAST_S && (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0; boolean isMainColorDark = Utilities.ATLEAST_S && (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0; - if (Utilities.isDarkTheme(context)) { + if (darkTheme) { return supportsDarkText ? R.style.AppTheme_Dark_DarkText : isMainColorDark ? R.style.AppTheme_Dark_DarkMainColor : R.style.AppTheme_Dark; } else { diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index 1ddd1ba89f..d49320b073 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -233,8 +233,15 @@ public class FloatingIconView extends FrameLayout implements outViewBounds.set(0, 0, v.getWidth(), v.getHeight()); } - Utilities.getBoundsForViewInDragLayer(launcher.getDragLayer(), v, outViewBounds, - ignoreTransform, outRect); + float[] points = new float[] {outViewBounds.left, outViewBounds.top, outViewBounds.right, + outViewBounds.bottom}; + Utilities.getDescendantCoordRelativeToAncestor(v, launcher.getDragLayer(), points, + false, ignoreTransform); + outRect.set( + Math.min(points[0], points[2]), + Math.min(points[1], points[3]), + Math.max(points[0], points[2]), + Math.max(points[1], points[3])); } /** diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 697c4531c2..620604a4d1 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -16,10 +16,6 @@ package com.android.launcher3.widget; -import static com.android.launcher3.Utilities.getBoundsForViewInDragLayer; -import static com.android.launcher3.Utilities.setRect; -import static com.android.launcher3.util.ColorExtractionUtils.getColorExtractionRect; - import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.res.Configuration; @@ -29,6 +25,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.os.Handler; import android.os.SystemClock; +import android.util.Log; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.view.LayoutInflater; @@ -98,11 +95,11 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView private RectF mLastLocationRegistered = null; @Nullable private AppWidgetHostViewDragListener mDragListener; - // Used to store the widget sizes in drag layer coordinates. + // Used to store the widget size during onLayout. private final Rect mCurrentWidgetSize = new Rect(); private final Rect mWidgetSizeAtDrag = new Rect(); - private final RectF mTempRectF = new RectF(); + private final boolean mIsRtl; private final Rect mEnforcedRectangle = new Rect(); private final float mEnforcedCornerRadius; private final ViewOutlineProvider mCornerRadiusEnforcementOutline = new ViewOutlineProvider() { @@ -132,6 +129,7 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView if (Utilities.ATLEAST_Q && Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) { setOnLightBackground(true); } + mIsRtl = Utilities.isRtl(context.getResources()); mColorExtractor = LocalColorExtractor.newInstance(getContext()); mColorExtractor.setListener(this); @@ -321,12 +319,13 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView mIsScrollable = checkScrollableRecursively(this); if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) { + mCurrentWidgetSize.left = left; + mCurrentWidgetSize.top = top; + mCurrentWidgetSize.right = right; + mCurrentWidgetSize.bottom = bottom; LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag(); - getBoundsForViewInDragLayer(mLauncher.getDragLayer(), this, mCurrentWidgetSize, true, - mTempRectF); - setRect(mTempRectF, mCurrentWidgetSize); - updateColorExtraction(mCurrentWidgetSize, - mWorkspace.getPageIndexForScreenId(info.screenId)); + int pageId = mWorkspace.getPageIndexForScreenId(info.screenId); + updateColorExtraction(mCurrentWidgetSize, pageId); } enforceRoundedCorners(); @@ -339,8 +338,8 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView } /** Handles a drag event occurred on a workspace page, {@code pageId}. */ - public void handleDrag(Rect rectInDragLayer, int pageId) { - mWidgetSizeAtDrag.set(rectInDragLayer); + public void handleDrag(Rect rect, int pageId) { + mWidgetSizeAtDrag.set(rect); updateColorExtraction(mWidgetSizeAtDrag, pageId); } @@ -352,14 +351,53 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView requestLayout(); } - /** - * @param rectInDragLayer Rect of widget in drag layer coordinates. - * @param pageId The workspace page the widget is on. - */ - private void updateColorExtraction(Rect rectInDragLayer, int pageId) { - getColorExtractionRect(mLauncher, pageId, rectInDragLayer, mTempRectF); - - if (mTempRectF.isEmpty()) { + private void updateColorExtraction(Rect widgetLocation, int pageId) { + // If the widget hasn't been measured and laid out, we cannot do this. + if (widgetLocation.isEmpty()) { + return; + } + int screenWidth = mLauncher.getDeviceProfile().widthPx; + int screenHeight = mLauncher.getDeviceProfile().heightPx; + int numScreens = mWorkspace.getNumPagesForWallpaperParallax(); + pageId = mIsRtl ? numScreens - pageId - 1 : pageId; + float relativeScreenWidth = 1f / numScreens; + float absoluteTop = widgetLocation.top; + float absoluteBottom = widgetLocation.bottom; + View v = this; + while (v.getParent() instanceof View) { + v = (View) v.getParent(); + if (v.getId() != R.id.launcher) { + break; + } + absoluteBottom += v.getTop(); + absoluteTop += v.getTop(); + } + float xOffset = 0; + View parentView = (View) getParent(); + // The layout depends on the orientation. + if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + int parentViewWidth = parentView == null ? 0 : parentView.getWidth(); + xOffset = screenWidth - mWorkspace.getPaddingRight() - parentViewWidth; + } else { + int parentViewPaddingLeft = parentView == null ? 0 : parentView.getPaddingLeft(); + xOffset = mWorkspace.getPaddingLeft() + parentViewPaddingLeft; + } + // This is the position of the widget relative to the wallpaper, as expected by the + // local color extraction of the WallpaperManager. + // The coordinate system is such that, on the horizontal axis, each screen has a + // distinct range on the [0,1] segment. So if there are 3 screens, they will have the + // ranges [0, 1/3], [1/3, 2/3] and [2/3, 1]. The position on the subrange should be + // the position of the widget relative to the screen. For the vertical axis, this is + // simply the location of the widget relative to the screen. + mTempRectF.left = ((widgetLocation.left + xOffset) / screenWidth + pageId) + * relativeScreenWidth; + mTempRectF.right = ((widgetLocation.right + xOffset) / screenWidth + pageId) + * relativeScreenWidth; + mTempRectF.top = absoluteTop / screenHeight; + mTempRectF.bottom = absoluteBottom / screenHeight; + if (mTempRectF.left < 0 || mTempRectF.right > 1 || mTempRectF.top < 0 + || mTempRectF.bottom > 1) { + Log.e(LOG_TAG, " Error, invalid relative position"); return; } if (!mTempRectF.equals(mLastLocationRegistered)) { diff --git a/src/com/android/launcher3/widget/LocalColorExtractor.java b/src/com/android/launcher3/widget/LocalColorExtractor.java index 2121bc288b..097158b072 100644 --- a/src/com/android/launcher3/widget/LocalColorExtractor.java +++ b/src/com/android/launcher3/widget/LocalColorExtractor.java @@ -43,10 +43,7 @@ public class LocalColorExtractor implements ResourceBasedOverride { void onColorsChanged(RectF rect, SparseIntArray extractedColors); } - /** - * Returns a new instance of the LocalColorExtractor. - */ - public static LocalColorExtractor newInstance(Context context) { + static LocalColorExtractor newInstance(Context context) { return Overrides.getObject(LocalColorExtractor.class, context.getApplicationContext(), R.string.local_colors_extraction_class); }