diff --git a/quickstep/res/layout/scrim_view.xml b/quickstep/res/layout/scrim_view.xml index 2cc37f9cc4..3f2daf1d17 100644 --- a/quickstep/res/layout/scrim_view.xml +++ b/quickstep/res/layout/scrim_view.xml @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - - mLauncher.getStateManager().goToState(OVERVIEW, true, () -> { - mOverviewResistYAnim = AnimatorControllerWithResistance - .createRecentsResistanceFromOverviewAnim(mLauncher, null) - .createPlaybackController(); - mReachedOverview = true; - maybeSwipeInteractionToOverviewComplete(); - }))); + mLauncher.getStateManager().goToState(OVERVIEW, true, () -> { + mOverviewResistYAnim = AnimatorControllerWithResistance + .createRecentsResistanceFromOverviewAnim(mLauncher, null) + .createPlaybackController(); + mReachedOverview = true; + maybeSwipeInteractionToOverviewComplete(); + }))); mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener); mCurrentAnimation.dispatchOnCancel(); @@ -239,7 +239,7 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch private void goToOverviewOrHomeOnDragEnd(float velocity) { boolean goToHomeInsteadOfOverview = !mMotionPauseDetector.isPaused(); if (goToHomeInsteadOfOverview) { - new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL)) + new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(NORMAL)) .animateWithVelocity(velocity); } if (mReachedOverview) { @@ -275,17 +275,14 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch LauncherState fromState, LauncherState toState) { if (fromState == NORMAL && toState == ALL_APPS) { StateAnimationConfig builder = new StateAnimationConfig(); - // Fade in prediction icons quickly, then rest of all apps after reaching overview. - float progressToReachOverview = NORMAL.getVerticalProgress(mLauncher) - - OVERVIEW.getVerticalProgress(mLauncher); builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress( ACCEL, 0, - ALL_APPS_CONTENT_FADE_THRESHOLD)); + ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD)); builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress( ACCEL, - progressToReachOverview, - progressToReachOverview + ALL_APPS_CONTENT_FADE_THRESHOLD)); + ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD, + ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD)); // Get workspace out of the way quickly, to prepare for potential pause. builder.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL_3); @@ -294,15 +291,14 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch return builder; } else if (fromState == ALL_APPS && toState == NORMAL) { StateAnimationConfig builder = new StateAnimationConfig(); - // Keep all apps/predictions opaque until the very end of the transition. - float progressToReachOverview = OVERVIEW.getVerticalProgress(mLauncher); + builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress( DEACCEL, - progressToReachOverview - ALL_APPS_CONTENT_FADE_THRESHOLD, - progressToReachOverview)); + 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD, + 1 - ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD)); builder.setInterpolator(ANIM_ALL_APPS_HEADER_FADE, Interpolators.clampToProgress( DEACCEL, - 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, + 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD, 1)); return builder; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index 1af9685f4f..b8f9452f36 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -49,9 +49,15 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr private static final String TAG = "PortraitStatesTouchCtrl"; /** - * The progress at which all apps content will be fully visible when swiping up from overview. + * The progress at which all apps content will be fully visible. */ - protected static final float ALL_APPS_CONTENT_FADE_THRESHOLD = 0.08f; + protected static final float ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD = 0.8f; + + /** + * Minimum clamping progress for fading in all apps content + */ + protected static final float ALL_APPS_CONTENT_FADE_MIN_CLAMPING_THRESHOLD = 0.4f; + /** * The progress at which recents will begin fading out when swiping up from overview. @@ -116,14 +122,14 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr private StateAnimationConfig getNormalToAllAppsAnimation() { StateAnimationConfig builder = new StateAnimationConfig(); builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL, - 0, ALL_APPS_CONTENT_FADE_THRESHOLD)); + 0, ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD)); return builder; } private StateAnimationConfig getAllAppsToNormalAnimation() { StateAnimationConfig builder = new StateAnimationConfig(); builder.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(DEACCEL, - 1 - ALL_APPS_CONTENT_FADE_THRESHOLD, 1)); + 1 - ALL_APPS_CONTENT_FADE_MAX_CLAMPING_THRESHOLD, 1)); return builder; } @@ -135,7 +141,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr config = getNormalToAllAppsAnimation(); } else if (fromState == ALL_APPS && toState == NORMAL) { config = getAllAppsToNormalAnimation(); - } else { + } else { config = new StateAnimationConfig(); } return config; @@ -198,7 +204,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr * Whether the motion event is over the hotseat. * * @param launcher the launcher activity - * @param ev the event to check + * @param ev the event to check * @return true if the event is over the hotseat */ static boolean isTouchOverHotseat(Launcher launcher, MotionEvent ev) { diff --git a/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java b/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java new file mode 100644 index 0000000000..185080e51d --- /dev/null +++ b/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java @@ -0,0 +1,125 @@ +/* + * 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.quickstep.views; + +import static com.android.launcher3.LauncherState.OVERVIEW; +import static com.android.launcher3.anim.Interpolators.ACCEL; +import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.view.animation.Interpolator; + +import androidx.core.graphics.ColorUtils; + +import com.android.launcher3.BaseQuickstepLauncher; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Utilities; +import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.util.Themes; +import com.android.launcher3.views.ScrimView; + +/** + * Scrim used for all-apps background. uses interpolator to coordinate fade in with + * all-apps contents + * + * Note: ranges are inverted because progress goes from 1 to 0 for NORMAL->AllAPPS + */ +public class AllAppsScrimView extends ScrimView { + + private static final float TINT_DECAY_MULTIPLIER = .5f; + + //min progress for scrim to become visible + private static final float SCRIM_VISIBLE_THRESHOLD = .9f; + //max progress where scrim alpha animates. + private static final float SCRIM_SOLID_THRESHOLD = .5f; + private final Interpolator mScrimInterpolator = Interpolators.clampToProgress(ACCEL, + SCRIM_SOLID_THRESHOLD, + SCRIM_VISIBLE_THRESHOLD); + + // In transposed layout, we simply draw a flat color. + private boolean mDrawingFlatColor; + + private final int mEndAlpha; + private final Paint mPaint; + + private int mCurrentScrimColor; + private final int mTintColor; + + public AllAppsScrimView(Context context, AttributeSet attrs) { + super(context, attrs); + mMaxScrimAlpha = Math.round(OVERVIEW.getOverviewScrimAlpha(mLauncher) * 255); + mTintColor = Themes.getColorAccent(mContext); + + + mEndAlpha = Color.alpha(mEndScrim); + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + // Just assume the easiest UI for now, until we have the proper layout information. + mDrawingFlatColor = true; + } + + @Override + public void reInitUi() { + DeviceProfile dp = mLauncher.getDeviceProfile(); + mDrawingFlatColor = dp.isVerticalBarLayout(); + updateColors(); + updateSysUiColors(); + invalidate(); + } + + @Override + public void updateColors() { + super.updateColors(); + if (mDrawingFlatColor) { + return; + } + + if (mProgress >= 1) { + mCurrentScrimColor = 0; + } else { + float interpolationProgress = mScrimInterpolator.getInterpolation(mProgress); + // Note that these ranges and interpolators are inverted because progress goes 1 to 0. + int alpha = Math.round(Utilities.mapRange(interpolationProgress, mEndAlpha, 0)); + int color = ColorUtils.blendARGB(mEndScrim, mTintColor, + mProgress * TINT_DECAY_MULTIPLIER); + mCurrentScrimColor = setColorAlphaBound(color, alpha); + } + } + + @Override + protected void onDraw(Canvas canvas) { + if (mDrawingFlatColor) { + if (mCurrentFlatColor != 0) { + canvas.drawColor(mCurrentFlatColor); + } + return; + } + + if (Color.alpha(mCurrentScrimColor) == 0) { + return; + } else if (mProgress <= 0) { + canvas.drawColor(mCurrentScrimColor); + return; + } + + mPaint.setColor(mCurrentScrimColor); + canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint); + } +} diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java index 25ae055f71..deb674c4a0 100644 --- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java +++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java @@ -30,6 +30,7 @@ import android.content.Intent; import android.content.pm.LauncherApps; import android.content.pm.LauncherApps.AppUsageLimit; import android.graphics.Outline; +import android.graphics.Paint; import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; @@ -48,6 +49,7 @@ import androidx.annotation.StringRes; import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.systemui.shared.recents.model.Task; import java.time.Duration; @@ -297,4 +299,17 @@ public final class DigitalWellBeingToast { mBanner.setAlpha(alpha); } } + + void setBannerColorTint(int color, float amount) { + if (mBanner == null) { + return; + } + if (mBannerAlpha == 0 || amount == 0) { + mBanner.setLayerType(View.LAYER_TYPE_NONE, null); + } + Paint layerPaint = new Paint(); + layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount)); + mBanner.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint); + mBanner.setLayerPaint(layerPaint); + } } diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java index ed642df7b4..5b0ade0d17 100644 --- a/quickstep/src/com/android/quickstep/views/IconView.java +++ b/quickstep/src/com/android/quickstep/views/IconView.java @@ -21,6 +21,8 @@ import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.View; +import com.android.launcher3.Utilities; + /** * A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout * when the drawable changes. @@ -102,4 +104,16 @@ public class IconView extends View { setVisibility(INVISIBLE); } } + + /** + * Set the tint color of the icon, useful for scrimming or dimming. + * + * @param color to blend in. + * @param amount [0,1] 0 no tint, 1 full tint + */ + public void setIconColorTint(int color, float amount) { + if (mDrawable != null) { + mDrawable.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount)); + } + } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 327f5e6e92..b62a029964 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -3309,6 +3309,16 @@ public abstract class RecentsView - implements NavigationModeChangeListener { - - // If the progress is more than this, shelf follows the finger, otherwise it moves faster to - // cover the whole screen - private static final float SCRIM_CATCHUP_THRESHOLD = 0.2f; - - // Temporarily needed until android.R.attr.bottomDialogCornerRadius becomes public - private static final float BOTTOM_CORNER_RADIUS_RATIO = 2f; - - // In transposed layout, we simply draw a flat color. - private boolean mDrawingFlatColor; - - // For shelf mode - private final int mEndAlpha; - private final float mRadius; - private final int mMaxScrimAlpha; - private final Paint mPaint; - - // Mid point where the alpha changes - private int mMidAlpha; - private float mMidProgress; - - private Interpolator mBeforeMidProgressColorInterpolator = ACCEL; - private Interpolator mAfterMidProgressColorInterpolator = ACCEL; - - private float mShiftRange; - - private float mTopOffset; - private float mShelfTop; - private float mShelfTopAtThreshold; - - private int mShelfColor; - private int mRemainingScreenColor; - - private final Path mTempPath = new Path(); - private final Path mRemainingScreenPath = new Path(); - private boolean mRemainingScreenPathValid = false; - - private Mode mSysUINavigationMode; - - public ShelfScrimView(Context context, AttributeSet attrs) { - super(context, attrs); - mMaxScrimAlpha = Math.round(OVERVIEW.getOverviewScrimAlpha(mLauncher) * 255); - - mEndAlpha = Color.alpha(mEndScrim); - mRadius = BOTTOM_CORNER_RADIUS_RATIO * Themes.getDialogCornerRadius(context); - mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - - // Just assume the easiest UI for now, until we have the proper layout information. - mDrawingFlatColor = true; - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mRemainingScreenPathValid = false; - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - onNavigationModeChanged(SysUINavigationMode.INSTANCE.get(getContext()) - .addModeChangeListener(this)); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - SysUINavigationMode.INSTANCE.get(getContext()).removeModeChangeListener(this); - } - - @Override - public void onNavigationModeChanged(Mode newMode) { - mSysUINavigationMode = newMode; - // Note that these interpolators are inverted because progress goes 1 to 0. - if (mSysUINavigationMode == Mode.NO_BUTTON) { - // Show the shelf more quickly before reaching overview progress. - mBeforeMidProgressColorInterpolator = ACCEL_2; - mAfterMidProgressColorInterpolator = ACCEL; - } else { - mBeforeMidProgressColorInterpolator = ACCEL; - mAfterMidProgressColorInterpolator = Interpolators.clampToProgress(ACCEL, 0.5f, 1f); - } - } - - @Override - public void reInitUi() { - DeviceProfile dp = mLauncher.getDeviceProfile(); - mDrawingFlatColor = dp.isVerticalBarLayout(); - - if (!mDrawingFlatColor) { - mRemainingScreenPathValid = false; - mShiftRange = mLauncher.getAllAppsController().getShiftRange(); - - // Fade in all apps background quickly to distinguish from swiping from nav bar. - mMidAlpha = Themes.getAttrInteger(getContext(), R.attr.allAppsInterimScrimAlpha); - mMidProgress = 1 - (OverviewState.getDefaultSwipeHeight(mLauncher) - / mLauncher.getAllAppsController().getShiftRange()); - - mTopOffset = dp.getInsets().top; - mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset; - } - updateColors(); - updateSysUiColors(); - invalidate(); - } - - @Override - public void updateColors() { - super.updateColors(); - if (mDrawingFlatColor) { - return; - } - - if (mProgress >= SCRIM_CATCHUP_THRESHOLD) { - mShelfTop = mShiftRange * mProgress + mTopOffset; - } else { - mShelfTop = Utilities.mapRange(mProgress / SCRIM_CATCHUP_THRESHOLD, -mRadius, - mShelfTopAtThreshold); - } - - if (mProgress >= 1) { - mRemainingScreenColor = 0; - mShelfColor = 0; - } else if (mProgress >= mMidProgress) { - mRemainingScreenColor = 0; - - int alpha = Math.round(Utilities.mapToRange( - mProgress, mMidProgress, 1, mMidAlpha, 0, mBeforeMidProgressColorInterpolator)); - mShelfColor = setColorAlphaBound(mEndScrim, alpha); - } else { - // Note that these ranges and interpolators are inverted because progress goes 1 to 0. - int alpha = Math.round( - Utilities.mapToRange(mProgress, (float) 0, mMidProgress, (float) mEndAlpha, - (float) mMidAlpha, mAfterMidProgressColorInterpolator)); - mShelfColor = setColorAlphaBound(mEndScrim, alpha); - - int remainingScrimAlpha = Math.round( - Utilities.mapToRange(mProgress, (float) 0, mMidProgress, mMaxScrimAlpha, - (float) 0, LINEAR)); - mRemainingScreenColor = setColorAlphaBound(mScrimColor, remainingScrimAlpha); - } - } - - @Override - protected void updateSysUiColors() { - if (mDrawingFlatColor) { - super.updateSysUiColors(); - } else { - // Use a light system UI (dark icons) if all apps is behind at least half of the - // status bar. - boolean forceChange = mShelfTop <= mLauncher.getDeviceProfile().getInsets().top / 2f; - if (forceChange) { - mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark); - } else { - mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0); - } - } - } - - @Override - protected void onDraw(Canvas canvas) { - if (mDrawingFlatColor) { - if (mCurrentFlatColor != 0) { - canvas.drawColor(mCurrentFlatColor); - } - return; - } - - if (Color.alpha(mShelfColor) == 0) { - return; - } else if (mProgress <= 0) { - canvas.drawColor(mShelfColor); - return; - } - - int height = getHeight(); - int width = getWidth(); - // Draw the scrim over the remaining screen if needed. - if (mRemainingScreenColor != 0) { - if (!mRemainingScreenPathValid) { - mTempPath.reset(); - // Using a arbitrary '+10' in the bottom to avoid any left-overs at the - // corners due to rounding issues. - mTempPath.addRoundRect(0, height - mRadius, width, height + mRadius + 10, - mRadius, mRadius, Direction.CW); - mRemainingScreenPath.reset(); - mRemainingScreenPath.addRect(0, 0, width, height, Direction.CW); - mRemainingScreenPath.op(mTempPath, Op.DIFFERENCE); - } - - float offset = height - mRadius - mShelfTop; - canvas.translate(0, -offset); - mPaint.setColor(mRemainingScreenColor); - canvas.drawPath(mRemainingScreenPath, mPaint); - canvas.translate(0, offset); - } - - mPaint.setColor(mShelfColor); - canvas.drawRoundRect(0, mShelfTop, width, height + mRadius, mRadius, mRadius, mPaint); - } -} diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java index a46daf38fd..0b84bc92a1 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -249,9 +249,11 @@ public class TaskMenuView extends AbstractFloatingView { final Animator revealAnimator = createOpenCloseOutlineProvider() .createRevealAnimator(this, closing); revealAnimator.setInterpolator(Interpolators.DEACCEL); - mOpenCloseAnimator.play(revealAnimator); - mOpenCloseAnimator.play(ObjectAnimator.ofFloat(mTaskView.getThumbnail(), DIM_ALPHA, - closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA)); + mOpenCloseAnimator.playTogether(revealAnimator, + ObjectAnimator.ofFloat( + mTaskView.getThumbnail(), DIM_ALPHA, + closing ? 0 : TaskView.MAX_PAGE_SCRIM_ALPHA), + ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1)); mOpenCloseAnimator.addListener(new AnimationSuccessListener() { @Override public void onAnimationStart(Animator animation) { @@ -265,7 +267,6 @@ public class TaskMenuView extends AbstractFloatingView { } } }); - mOpenCloseAnimator.play(ObjectAnimator.ofFloat(this, ALPHA, closing ? 0 : 1)); mOpenCloseAnimator.setDuration(closing ? REVEAL_CLOSE_DURATION: REVEAL_OPEN_DURATION); mOpenCloseAnimator.start(); } diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index af62582418..685f725707 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -28,8 +28,6 @@ import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Paint; @@ -46,10 +44,10 @@ import android.view.Surface; import android.view.View; import androidx.annotation.RequiresApi; +import androidx.core.graphics.ColorUtils; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; @@ -67,10 +65,6 @@ import com.android.systemui.shared.recents.model.ThumbnailData; * A task in the Recents view. */ public class TaskThumbnailView extends View implements PluginListener { - - private static final ColorMatrix COLOR_MATRIX = new ColorMatrix(); - private static final ColorMatrix SATURATION_COLOR_MATRIX = new ColorMatrix(); - private static final MainThreadInitializedObject TEMP_PARAMS = new MainThreadInitializedObject<>(FullscreenDrawParams::new); @@ -89,11 +83,11 @@ public class TaskThumbnailView extends View implements PluginListener - * If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be black. + * If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be the + * extracted background color. + * */ public void setDimAlpha(float dimAlpha) { mDimAlpha = dimAlpha; @@ -359,15 +350,15 @@ public class TaskThumbnailView extends View implements PluginListener COLOR_TINT = + new FloatProperty("colorTint") { + @Override + public void setValue(TaskView taskView, float v) { + taskView.setColorTint(v); + } + + @Override + public Float get(TaskView taskView) { + return taskView.getColorTint(); + } + }; + private final OnAttachStateChangeListener mTaskMenuStateListener = new OnAttachStateChangeListener() { @Override @@ -314,6 +325,11 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private final float[] mIconCenterCoords = new float[2]; private final float[] mChipCenterCoords = new float[2]; + // Colored tint for the task view and all its supplementary views (like the task icon and well + // being banner. + private final int mTintingColor; + private float mTintAmount; + private boolean mIsClickableAsLiveTile = true; public TaskView(Context context) { @@ -375,6 +391,8 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams, mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx); setOutlineProvider(mOutlineProvider); + + mTintingColor = Themes.getColorBackgroundFloating(context); } /** @@ -722,7 +740,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { progress = 1 - progress; } mFocusTransitionProgress = progress; - mSnapshotView.setDimAlphaMultipler(0); float iconScalePercentage = (float) SCALE_ICON_DURATION / DIM_ANIM_DURATION; float lowerClamp = invert ? 1f - iconScalePercentage : 0; float upperClamp = invert ? 1 : iconScalePercentage; @@ -781,6 +798,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { setTranslationZ(0); setAlpha(mStableAlpha); setIconScaleAndDim(1); + setColorTint(0); } public void setStableAlpha(float parentAlpha) { @@ -1324,6 +1342,26 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { rv.initiateSplitSelect(this, splitPositionOption); } + private void setColorTint(float amount) { + mSnapshotView.setDimAlpha(amount); + mIconView.setIconColorTint(mTintingColor, amount); + mDigitalWellBeingToast.setBannerColorTint(mTintingColor, amount); + } + + private float getColorTint() { + return mTintAmount; + } + + /** + * Show the task view with a color tint (animates value). + */ + public void showColorTint(boolean enable) { + ObjectAnimator tintAnimator = ObjectAnimator.ofFloat( + this, COLOR_TINT, enable ? MAX_PAGE_SCRIM_ALPHA : 0); + tintAnimator.setAutoCancel(true); + tintAnimator.start(); + } + /** * We update and subsequently draw these in {@link #setFullscreenProgress(float)}. */ diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 1fccdf34a6..51dddab6f7 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -84,6 +84,7 @@ -26dp + 96dp 48dp 30dp 40dp diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index a29eab70d3..aea38a054b 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -147,6 +147,7 @@ public class DeviceProfile { public final int hotseatBarSidePaddingEndPx; // All apps + public int allAppsOpenVerticalTranslate; public int allAppsCellHeightPx; public int allAppsCellWidthPx; public int allAppsIconSizePx; @@ -248,6 +249,10 @@ public class DeviceProfile { : res.getDimensionPixelSize(R.dimen.dynamic_grid_left_right_margin); desiredWorkspaceLeftRightOriginalPx = desiredWorkspaceLeftRightMarginPx; + + allAppsOpenVerticalTranslate = res.getDimensionPixelSize( + R.dimen.all_apps_open_vertical_translate); + folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale); folderContentPaddingLeftRight = res.getDimensionPixelSize(R.dimen.folder_content_padding_left_right); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index f7cf66bf6a..ecaff7a2ad 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -994,7 +994,19 @@ public class Launcher extends StatefulActivity implements Launche } // When multiple pages are visible, show persistent page indicator mWorkspace.getPageIndicator().setShouldAutoHide(!state.hasFlag(FLAG_MULTI_PAGE)); + mPrevLauncherState = mStateManager.getCurrentStableState(); + if (mPrevLauncherState != state && ALL_APPS.equals(state) + // Making sure mAllAppsSessionLogId is null to avoid double logging. + && mAllAppsSessionLogId == null) { + // creates new instance ID since new all apps session is started. + mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId(); + getStatsLogManager() + .logger() + .log(FeatureFlags.ENABLE_DEVICE_SEARCH.get() + ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH + : LAUNCHER_ALLAPPS_ENTRY); + } } @Override @@ -1019,16 +1031,8 @@ public class Launcher extends StatefulActivity implements Launche getRotationHelper().setCurrentStateRequest(REQUEST_NONE); } - if (ALL_APPS.equals(state)) { - // creates new instance ID since new all apps session is started. - mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId(); - getStatsLogManager() - .logger() - .log(FeatureFlags.ENABLE_DEVICE_SEARCH.get() - ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH - : LAUNCHER_ALLAPPS_ENTRY); - } else if (ALL_APPS.equals(mPrevLauncherState) - // Check if mLogInstanceId is not null to make sure exit event is logged only once. + if (mPrevLauncherState != state && !ALL_APPS.equals(state) + // Making sure mAllAppsSessionLogId is not null to avoid double logging. && mAllAppsSessionLogId != null) { getStatsLogManager().logger().log(LAUNCHER_ALLAPPS_EXIT); mAllAppsSessionLogId = null; diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 8825710401..1776777934 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -37,6 +37,8 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.LightingColorFilter; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; @@ -64,6 +66,7 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.animation.Interpolator; +import androidx.core.graphics.ColorUtils; import androidx.core.os.BuildCompat; import com.android.launcher3.dragndrop.FolderAdaptiveIcon; @@ -732,6 +735,23 @@ public final class Utilities { } } + /** + * Make a color filter that blends a color into the destination based on a scalable amout. + * + * @param color to blend in. + * @param tintAmount [0-1] 0 no tinting, 1 full color. + * @return ColorFilter for tinting, or {@code null} if no filter is needed. + */ + public static ColorFilter makeColorTintingColorFilter(int color, float tintAmount) { + if (tintAmount == 0f) { + return null; + } + return new LightingColorFilter( + // This isn't blending in white, its making a multiplication mask for the base color + ColorUtils.blendARGB(Color.WHITE, 0, tintAmount), + ColorUtils.blendARGB(0, color, tintAmount)); + } + private static class FixedSizeEmptyDrawable extends ColorDrawable { private final int mSize; diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index db7fd3feca..a5852ba828 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -265,7 +265,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme List actions = getSupportedResizeActions(host, info); Rect pos = new Rect(); mLauncher.getDragLayer().getDescendantRectRelativeToSelf(host, pos); - ArrowPopup popup = OptionsPopupView.show(mLauncher, new RectF(pos), actions); + ArrowPopup popup = OptionsPopupView.show(mLauncher, new RectF(pos), actions, false); popup.requestFocus(); popup.setOnCloseCallback(host::requestFocus); return true; @@ -294,15 +294,17 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) { if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) || layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) { - actions.add(new OptionItem( - R.string.action_increase_width, R.drawable.ic_widget_width_increase, + actions.add(new OptionItem(mLauncher, + R.string.action_increase_width, + R.drawable.ic_widget_width_increase, IGNORE, v -> performResizeAction(R.string.action_increase_width, host, info))); } if (info.spanX > info.minSpanX && info.spanX > 1) { - actions.add(new OptionItem( - R.string.action_decrease_width, R.drawable.ic_widget_width_decrease, + actions.add(new OptionItem(mLauncher, + R.string.action_decrease_width, + R.drawable.ic_widget_width_decrease, IGNORE, v -> performResizeAction(R.string.action_decrease_width, host, info))); } @@ -311,15 +313,17 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) { if (layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1) || layout.isRegionVacant(info.cellX, info.cellY - 1, info.spanX, 1)) { - actions.add(new OptionItem( - R.string.action_increase_height, R.drawable.ic_widget_height_increase, + actions.add(new OptionItem(mLauncher, + R.string.action_increase_height, + R.drawable.ic_widget_height_increase, IGNORE, v -> performResizeAction(R.string.action_increase_height, host, info))); } if (info.spanY > info.minSpanY && info.spanY > 1) { - actions.add(new OptionItem( - R.string.action_decrease_height, R.drawable.ic_widget_height_decrease, + actions.add(new OptionItem(mLauncher, + R.string.action_decrease_height, + R.drawable.ic_widget_height_decrease, IGNORE, v -> performResizeAction(R.string.action_decrease_height, host, info))); } diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index f031136309..c21d7745ca 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -127,7 +127,7 @@ public class AllAppsTransitionController mProgress = progress; mScrimView.setProgress(progress); - mAppsView.setTranslationY(progress * mShiftRange); + mAppsView.setTranslationY(mProgress * mShiftRange); } public float getProgress() { diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java index 13ddc1244f..16ae2508ec 100644 --- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java @@ -72,8 +72,9 @@ public class LauncherAllAppsContainerView extends AllAppsContainerView { @Override public void setInsets(Rect insets) { super.setInsets(insets); - mLauncher.getAllAppsController() - .setScrollRangeDelta(mSearchUiManager.getScrollRangeDelta(insets)); + int allAppsStartingPositionY = mLauncher.getDeviceProfile().availableHeightPx + - mLauncher.getDeviceProfile().allAppsOpenVerticalTranslate; + mLauncher.getAllAppsController().setScrollRangeDelta(allAppsStartingPositionY); } @Override diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java index 941d3af797..924a392389 100644 --- a/src/com/android/launcher3/allapps/SearchUiManager.java +++ b/src/com/android/launcher3/allapps/SearchUiManager.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.allapps; -import android.graphics.Rect; import android.view.KeyEvent; import androidx.annotation.Nullable; @@ -43,11 +42,6 @@ public interface SearchUiManager { */ default void preDispatchKeyEvent(KeyEvent keyEvent) { }; - /** - * Returns the vertical shift for the all-apps view, so that it aligns with the hotseat. - */ - float getScrollRangeDelta(Rect insets); - /** * @return the edit text object */ diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java index c51bcf5bd4..a8185d6eba 100644 --- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java +++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java @@ -42,7 +42,6 @@ import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem; import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.allapps.AlphabeticalAppsList; import com.android.launcher3.allapps.SearchUiManager; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.search.SearchCallback; import java.util.ArrayList; @@ -209,16 +208,6 @@ public class AppsSearchContainerLayout extends ExtendedEditText requestLayout(); } - @Override - public float getScrollRangeDelta(Rect insets) { - if (mLauncher.getDeviceProfile().isVerticalBarLayout() - || FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { - return 0; - } else { - return insets.bottom + insets.top; - } - } - @Override public ExtendedEditText getEditText() { return this; diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 2889801a8b..a4372930be 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -317,7 +317,9 @@ public abstract class AbstractStateChangeTouchController Math.min(progress, 1) - endProgress) * durationMultiplier; } } - + if (targetState != mStartState) { + logReachedState(targetState); + } mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState)); ValueAnimator anim = mCurrentAnimation.getAnimationPlayer(); anim.setFloatValues(startProgress, endProgress); @@ -345,9 +347,6 @@ public abstract class AbstractStateChangeTouchController } protected void goToTargetState(LauncherState targetState) { - if (targetState != mStartState) { - logReachedState(targetState); - } if (!mLauncher.isInState(targetState)) { // If we're already in the target state, don't jump to it at the end of the animation in // case the user started interacting with it before the animation finished. diff --git a/src/com/android/launcher3/views/AccessibilityActionsView.java b/src/com/android/launcher3/views/AccessibilityActionsView.java index 0eacaa3009..1d136c3a9f 100644 --- a/src/com/android/launcher3/views/AccessibilityActionsView.java +++ b/src/com/android/launcher3/views/AccessibilityActionsView.java @@ -67,7 +67,7 @@ public class AccessibilityActionsView extends View implements StateListener mItemMap = new ArrayMap<>(); private RectF mTargetRect; + private boolean mShouldAddArrow; public OptionsPopupView(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -113,9 +116,13 @@ public class OptionsPopupView extends ArrowPopup return (type & TYPE_OPTIONS_POPUP) != 0; } + public void setShouldAddArrow(boolean shouldAddArrow) { + mShouldAddArrow = shouldAddArrow; + } + @Override protected boolean shouldAddArrow() { - return false; + return mShouldAddArrow; } @Override @@ -124,16 +131,17 @@ public class OptionsPopupView extends ArrowPopup } public static OptionsPopupView show( - Launcher launcher, RectF targetRect, List items) { + Launcher launcher, RectF targetRect, List items, boolean shouldAddArrow) { OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater() .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false); popup.mTargetRect = targetRect; + popup.setShouldAddArrow(shouldAddArrow); for (OptionItem item : items) { DeepShortcutView view = (DeepShortcutView) popup.inflateAndAdd(R.layout.system_shortcut, popup); - view.getIconView().setBackgroundResource(item.iconRes); - view.getBubbleText().setText(item.labelRes); + view.getIconView().setBackgroundDrawable(item.icon); + view.getBubbleText().setText(item.label); view.setOnClickListener(popup); view.setOnLongClickListener(popup); popup.mItemMap.put(view, item); @@ -154,7 +162,7 @@ public class OptionsPopupView extends ArrowPopup y = launcher.getDragLayer().getHeight() / 2; } RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize); - show(launcher, target, getOptions(launcher)); + show(launcher, target, getOptions(launcher), false); } /** @@ -162,11 +170,15 @@ public class OptionsPopupView extends ArrowPopup */ public static ArrayList getOptions(Launcher launcher) { ArrayList options = new ArrayList<>(); - options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting, + options.add(new OptionItem(launcher, + R.string.settings_button_text, + R.drawable.ic_setting, LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS, OptionsPopupView::startSettings)); if (!WidgetsModel.GO_DISABLE_WIDGETS) { - options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget, + options.add(new OptionItem(launcher, + R.string.widget_button_text, + R.drawable.ic_widget, LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS, OptionsPopupView::onWidgetsClicked)); } @@ -174,7 +186,9 @@ public class OptionsPopupView extends ArrowPopup R.string.styles_wallpaper_button_text : R.string.wallpaper_button_text; int resDrawable = Utilities.existsStyleWallpapers(launcher) ? R.drawable.ic_palette : R.drawable.ic_wallpaper; - options.add(new OptionItem(resString, resDrawable, + options.add(new OptionItem(launcher, + resString, + resDrawable, IGNORE, OptionsPopupView::startWallpaperPicker)); return options; @@ -241,15 +255,28 @@ public class OptionsPopupView extends ArrowPopup public static class OptionItem { + // Used to create AccessibilityNodeInfo in AccessibilityActionsView.java. public final int labelRes; - public final int iconRes; + + public final CharSequence label; + public final Drawable icon; public final EventEnum eventId; public final OnLongClickListener clickListener; - public OptionItem(int labelRes, int iconRes, EventEnum eventId, - OnLongClickListener clickListener) { + public OptionItem(Context context, int labelRes, int iconRes, EventEnum eventId, + OnLongClickListener clickListener) { this.labelRes = labelRes; - this.iconRes = iconRes; + this.label = context.getText(labelRes); + this.icon = ContextCompat.getDrawable(context, iconRes); + this.eventId = eventId; + this.clickListener = clickListener; + } + + public OptionItem(CharSequence label, Drawable icon, EventEnum eventId, + OnLongClickListener clickListener) { + this.labelRes = 0; + this.label = label; + this.icon = icon; this.eventId = eventId; this.clickListener = clickListener; } diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java index 7f0765becd..72926dde34 100644 --- a/src/com/android/launcher3/views/ScrimView.java +++ b/src/com/android/launcher3/views/ScrimView.java @@ -40,6 +40,7 @@ import com.android.launcher3.util.Themes; * Simple scrim which draws a flat color */ public class ScrimView extends View implements Insettable, OnChangeListener { + private static final float STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD = .1f; protected final T mLauncher; private final WallpaperColorInfo mWallpaperColorInfo; @@ -117,7 +118,7 @@ public class ScrimView extends View implements Insettable, O protected void updateSysUiColors() { // Use a light system UI (dark icons) if all apps is behind at least half of the // status bar. - boolean forceChange = mProgress <= 0.1f; + boolean forceChange = mProgress <= STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD; if (forceChange) { mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark); } else {