Loading quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java +72 −10 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.quickstep.views; import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS; import static android.view.Gravity.BOTTOM; import static android.view.Gravity.CENTER_HORIZONTAL; import static com.android.launcher3.Utilities.prefixTextWithIcon; import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR; Loading @@ -27,6 +29,7 @@ import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.pm.LauncherApps.AppUsageLimit; import android.graphics.Outline; import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; Loading @@ -35,6 +38,9 @@ import android.os.Build; import android.os.UserHandle; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.widget.FrameLayout; import android.widget.TextView; import androidx.annotation.StringRes; Loading @@ -61,6 +67,10 @@ public final class DigitalWellBeingToast { private Task mTask; private boolean mHasLimit; private long mAppRemainingTimeMs; private View mBanner; private ViewOutlineProvider mOldBannerOutlineProvider; private float mBannerOffsetPercentage; private float mBannerAlpha = 1f; public DigitalWellBeingToast(BaseDraggingActivity activity, TaskView taskView) { mActivity = activity; Loading @@ -68,18 +78,10 @@ public final class DigitalWellBeingToast { mLauncherApps = activity.getSystemService(LauncherApps.class); } private void setTaskFooter(View view) { View oldFooter = mTaskView.setFooter(TaskView.INDEX_DIGITAL_WELLBEING_TOAST, view); if (oldFooter != null) { oldFooter.setOnClickListener(null); mActivity.getViewCache().recycleView(R.layout.digital_wellbeing_toast, oldFooter); } } private void setNoLimit() { mHasLimit = false; mTaskView.setContentDescription(mTask.titleDescription); setTaskFooter(null); replaceBanner(null); mAppRemainingTimeMs = 0; } Loading @@ -90,7 +92,7 @@ public final class DigitalWellBeingToast { mActivity, mTaskView); toast.setText(prefixTextWithIcon(mActivity, R.drawable.ic_hourglass_top, getText())); toast.setOnClickListener(this::openAppUsageSettings); setTaskFooter(toast); replaceBanner(toast); mTaskView.setContentDescription( getContentDescriptionForTask(mTask, appUsageLimitTimeMs, appRemainingTimeMs)); Loading Loading @@ -233,4 +235,64 @@ public final class DigitalWellBeingToast { getText(appRemainingTimeMs)) : task.titleDescription; } private void replaceBanner(View view) { resetOldBanner(); setBanner(view); } private void resetOldBanner() { if (mBanner != null) { mBanner.setOutlineProvider(mOldBannerOutlineProvider); mTaskView.removeView(mBanner); mBanner.setOnClickListener(null); mActivity.getViewCache().recycleView(R.layout.digital_wellbeing_toast, mBanner); } } private void setBanner(View view) { mBanner = view; if (view != null) { setupAndAddBanner(); setBannerOutline(); } } private void setupAndAddBanner() { FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mBanner.getLayoutParams(); layoutParams.gravity = BOTTOM | CENTER_HORIZONTAL; layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams) mTaskView.getThumbnail().getLayoutParams()).bottomMargin; mBanner.setTranslationY(mBannerOffsetPercentage * mBanner.getHeight()); mBanner.setAlpha(mBannerAlpha); mTaskView.addView(mBanner); } private void setBannerOutline() { mOldBannerOutlineProvider = mBanner.getOutlineProvider(); mBanner.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { mOldBannerOutlineProvider.getOutline(view, outline); outline.offset(0, -Math.round(view.getTranslationY())); } }); mBanner.setClipToOutline(true); } void updateBannerOffset(float offsetPercentage) { if (mBanner != null && mBannerOffsetPercentage != offsetPercentage) { mBannerOffsetPercentage = offsetPercentage; mBanner.setTranslationY(offsetPercentage * mBanner.getHeight()); mBanner.invalidateOutline(); } } void updateBannerAlpha(float alpha) { if (mBanner != null && mBannerAlpha != alpha) { mBannerAlpha = alpha; mBanner.setAlpha(alpha); } } } quickstep/src/com/android/quickstep/views/TaskView.java +5 −149 Original line number Diff line number Diff line Loading @@ -42,7 +42,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; Loading Loading @@ -193,12 +192,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private boolean mEndQuickswitchCuj; // Order in which the footers appear. Lower order appear below higher order. public static final int INDEX_DIGITAL_WELLBEING_TOAST = 0; private final FooterWrapper[] mFooters = new FooterWrapper[2]; private float mFooterVerticalOffset = 0; private float mFooterAlpha = 1; private int mStackHeight; private View mContextualChipWrapper; private View mContextualChip; private final float[] mIconCenterCoords = new float[2]; Loading Loading @@ -342,7 +335,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { if (mContextualChipWrapper != null) { mContextualChipWrapper.setAlpha(comp(modalness)); } updateFooterVerticalOffset(mFooterVerticalOffset); mDigitalWellBeingToast.updateBannerOffset(modalness); } public TaskMenuView getMenuView() { Loading Loading @@ -564,7 +557,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mContextualChip.setScaleX(scale); mContextualChip.setScaleY(scale); } updateFooterVerticalOffset(1.0f - scale); mDigitalWellBeingToast.updateBannerOffset(1f - scale); } public void setIconScaleAnimStartProgress(float startProgress) { Loading Loading @@ -636,12 +629,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mSnapshotView.setDimAlpha(curveInterpolation * MAX_PAGE_SCRIM_ALPHA); setCurveScale(curveScaleForCurveInterpolation); mFooterAlpha = Utilities.boundToRange(1.0f - 2 * scrollState.linearInterpolation, 0f, 1f); for (FooterWrapper footer : mFooters) { if (footer != null) { footer.mView.setAlpha(mFooterAlpha); } } float dwbBannerAlpha = Utilities.boundToRange(1.0f - 2 * scrollState.linearInterpolation, 0f, 1f); mDigitalWellBeingToast.updateBannerAlpha(dwbBannerAlpha); if (mMenuView != null) { PagedOrientationHandler pagedOrientationHandler = getPagedOrientationHandler(); Loading @@ -653,57 +643,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } } /** * Sets the footer at the specific index and returns the previously set footer. */ public View setFooter(int index, View view) { View oldFooter = null; // If the footer are is already collapsed, do not animate entry boolean shouldAnimateEntry = mFooterVerticalOffset <= 0; if (mFooters[index] != null) { oldFooter = mFooters[index].mView; mFooters[index].release(); removeView(oldFooter); // If we are replacing an existing footer, do not animate entry shouldAnimateEntry = false; } if (view != null) { int indexToAdd = getChildCount(); for (int i = index - 1; i >= 0; i--) { if (mFooters[i] != null) { indexToAdd = indexOfChild(mFooters[i].mView); break; } } addView(view, indexToAdd); LayoutParams layoutParams = (LayoutParams) view.getLayoutParams(); layoutParams.gravity = BOTTOM | CENTER_HORIZONTAL; layoutParams.bottomMargin = ((MarginLayoutParams) mSnapshotView.getLayoutParams()).bottomMargin; view.setAlpha(mFooterAlpha); mFooters[index] = new FooterWrapper(view); if (shouldAnimateEntry) { mFooters[index].animateEntry(); } } else { mFooters[index] = null; } mStackHeight = 0; for (FooterWrapper footer : mFooters) { if (footer != null) { footer.setVerticalShift(mStackHeight); mStackHeight += footer.mExpectedHeight; } } return oldFooter; } /** * Sets the contextual chip. * Loading Loading @@ -777,24 +716,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight()); setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT); } mStackHeight = 0; for (FooterWrapper footer : mFooters) { if (footer != null) { mStackHeight += footer.mView.getHeight(); } } updateFooterVerticalOffset(0); } private void updateFooterVerticalOffset(float offset) { mFooterVerticalOffset = offset; for (FooterWrapper footer : mFooters) { if (footer != null) { footer.updateFooterOffset(); } } } public static float getCurveScaleForInterpolation(float linearInterpolation) { Loading Loading @@ -857,71 +778,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } } private class FooterWrapper extends ViewOutlineProvider { final View mView; final ViewOutlineProvider mOldOutlineProvider; final ViewOutlineProvider mDelegate; final int mExpectedHeight; final int mOldPaddingBottom; int mAnimationOffset = 0; int mEntryAnimationOffset = 0; public FooterWrapper(View view) { mView = view; mOldOutlineProvider = view.getOutlineProvider(); mDelegate = mOldOutlineProvider == null ? ViewOutlineProvider.BACKGROUND : mOldOutlineProvider; mExpectedHeight = getExpectedViewHeight(view); mOldPaddingBottom = view.getPaddingBottom(); if (mOldOutlineProvider != null) { view.setOutlineProvider(this); view.setClipToOutline(true); } } public void setVerticalShift(int shift) { mView.setPadding(mView.getPaddingLeft(), mView.getPaddingTop(), mView.getPaddingRight(), mOldPaddingBottom + shift); } @Override public void getOutline(View view, Outline outline) { mDelegate.getOutline(view, outline); outline.offset(0, -mAnimationOffset - mEntryAnimationOffset); } void updateFooterOffset() { float offset = Utilities.or(mFooterVerticalOffset, mModalness); mAnimationOffset = Math.round(mStackHeight * offset); mView.setTranslationY(mAnimationOffset + mEntryAnimationOffset + mCurrentFullscreenParams.mCurrentDrawnInsets.bottom + mCurrentFullscreenParams.mCurrentDrawnInsets.top); mView.invalidateOutline(); } void release() { mView.setOutlineProvider(mOldOutlineProvider); setVerticalShift(0); } void animateEntry() { ValueAnimator animator = ValueAnimator.ofFloat(0, 1); animator.addUpdateListener(anim -> { float factor = 1 - anim.getAnimatedFraction(); int totalShift = mExpectedHeight + mView.getPaddingBottom() - mOldPaddingBottom; mEntryAnimationOffset = Math.round(factor * totalShift); updateFooterOffset(); }); animator.setDuration(100); animator.start(); } } private int getExpectedViewHeight(View view) { int expectedHeight; int h = view.getLayoutParams().height; Loading Loading
quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java +72 −10 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.quickstep.views; import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS; import static android.view.Gravity.BOTTOM; import static android.view.Gravity.CENTER_HORIZONTAL; import static com.android.launcher3.Utilities.prefixTextWithIcon; import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR; Loading @@ -27,6 +29,7 @@ import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.pm.LauncherApps.AppUsageLimit; import android.graphics.Outline; import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; Loading @@ -35,6 +38,9 @@ import android.os.Build; import android.os.UserHandle; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.widget.FrameLayout; import android.widget.TextView; import androidx.annotation.StringRes; Loading @@ -61,6 +67,10 @@ public final class DigitalWellBeingToast { private Task mTask; private boolean mHasLimit; private long mAppRemainingTimeMs; private View mBanner; private ViewOutlineProvider mOldBannerOutlineProvider; private float mBannerOffsetPercentage; private float mBannerAlpha = 1f; public DigitalWellBeingToast(BaseDraggingActivity activity, TaskView taskView) { mActivity = activity; Loading @@ -68,18 +78,10 @@ public final class DigitalWellBeingToast { mLauncherApps = activity.getSystemService(LauncherApps.class); } private void setTaskFooter(View view) { View oldFooter = mTaskView.setFooter(TaskView.INDEX_DIGITAL_WELLBEING_TOAST, view); if (oldFooter != null) { oldFooter.setOnClickListener(null); mActivity.getViewCache().recycleView(R.layout.digital_wellbeing_toast, oldFooter); } } private void setNoLimit() { mHasLimit = false; mTaskView.setContentDescription(mTask.titleDescription); setTaskFooter(null); replaceBanner(null); mAppRemainingTimeMs = 0; } Loading @@ -90,7 +92,7 @@ public final class DigitalWellBeingToast { mActivity, mTaskView); toast.setText(prefixTextWithIcon(mActivity, R.drawable.ic_hourglass_top, getText())); toast.setOnClickListener(this::openAppUsageSettings); setTaskFooter(toast); replaceBanner(toast); mTaskView.setContentDescription( getContentDescriptionForTask(mTask, appUsageLimitTimeMs, appRemainingTimeMs)); Loading Loading @@ -233,4 +235,64 @@ public final class DigitalWellBeingToast { getText(appRemainingTimeMs)) : task.titleDescription; } private void replaceBanner(View view) { resetOldBanner(); setBanner(view); } private void resetOldBanner() { if (mBanner != null) { mBanner.setOutlineProvider(mOldBannerOutlineProvider); mTaskView.removeView(mBanner); mBanner.setOnClickListener(null); mActivity.getViewCache().recycleView(R.layout.digital_wellbeing_toast, mBanner); } } private void setBanner(View view) { mBanner = view; if (view != null) { setupAndAddBanner(); setBannerOutline(); } } private void setupAndAddBanner() { FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mBanner.getLayoutParams(); layoutParams.gravity = BOTTOM | CENTER_HORIZONTAL; layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams) mTaskView.getThumbnail().getLayoutParams()).bottomMargin; mBanner.setTranslationY(mBannerOffsetPercentage * mBanner.getHeight()); mBanner.setAlpha(mBannerAlpha); mTaskView.addView(mBanner); } private void setBannerOutline() { mOldBannerOutlineProvider = mBanner.getOutlineProvider(); mBanner.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { mOldBannerOutlineProvider.getOutline(view, outline); outline.offset(0, -Math.round(view.getTranslationY())); } }); mBanner.setClipToOutline(true); } void updateBannerOffset(float offsetPercentage) { if (mBanner != null && mBannerOffsetPercentage != offsetPercentage) { mBannerOffsetPercentage = offsetPercentage; mBanner.setTranslationY(offsetPercentage * mBanner.getHeight()); mBanner.invalidateOutline(); } } void updateBannerAlpha(float alpha) { if (mBanner != null && mBannerAlpha != alpha) { mBannerAlpha = alpha; mBanner.setAlpha(alpha); } } }
quickstep/src/com/android/quickstep/views/TaskView.java +5 −149 Original line number Diff line number Diff line Loading @@ -42,7 +42,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; Loading Loading @@ -193,12 +192,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private boolean mEndQuickswitchCuj; // Order in which the footers appear. Lower order appear below higher order. public static final int INDEX_DIGITAL_WELLBEING_TOAST = 0; private final FooterWrapper[] mFooters = new FooterWrapper[2]; private float mFooterVerticalOffset = 0; private float mFooterAlpha = 1; private int mStackHeight; private View mContextualChipWrapper; private View mContextualChip; private final float[] mIconCenterCoords = new float[2]; Loading Loading @@ -342,7 +335,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { if (mContextualChipWrapper != null) { mContextualChipWrapper.setAlpha(comp(modalness)); } updateFooterVerticalOffset(mFooterVerticalOffset); mDigitalWellBeingToast.updateBannerOffset(modalness); } public TaskMenuView getMenuView() { Loading Loading @@ -564,7 +557,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mContextualChip.setScaleX(scale); mContextualChip.setScaleY(scale); } updateFooterVerticalOffset(1.0f - scale); mDigitalWellBeingToast.updateBannerOffset(1f - scale); } public void setIconScaleAnimStartProgress(float startProgress) { Loading Loading @@ -636,12 +629,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mSnapshotView.setDimAlpha(curveInterpolation * MAX_PAGE_SCRIM_ALPHA); setCurveScale(curveScaleForCurveInterpolation); mFooterAlpha = Utilities.boundToRange(1.0f - 2 * scrollState.linearInterpolation, 0f, 1f); for (FooterWrapper footer : mFooters) { if (footer != null) { footer.mView.setAlpha(mFooterAlpha); } } float dwbBannerAlpha = Utilities.boundToRange(1.0f - 2 * scrollState.linearInterpolation, 0f, 1f); mDigitalWellBeingToast.updateBannerAlpha(dwbBannerAlpha); if (mMenuView != null) { PagedOrientationHandler pagedOrientationHandler = getPagedOrientationHandler(); Loading @@ -653,57 +643,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } } /** * Sets the footer at the specific index and returns the previously set footer. */ public View setFooter(int index, View view) { View oldFooter = null; // If the footer are is already collapsed, do not animate entry boolean shouldAnimateEntry = mFooterVerticalOffset <= 0; if (mFooters[index] != null) { oldFooter = mFooters[index].mView; mFooters[index].release(); removeView(oldFooter); // If we are replacing an existing footer, do not animate entry shouldAnimateEntry = false; } if (view != null) { int indexToAdd = getChildCount(); for (int i = index - 1; i >= 0; i--) { if (mFooters[i] != null) { indexToAdd = indexOfChild(mFooters[i].mView); break; } } addView(view, indexToAdd); LayoutParams layoutParams = (LayoutParams) view.getLayoutParams(); layoutParams.gravity = BOTTOM | CENTER_HORIZONTAL; layoutParams.bottomMargin = ((MarginLayoutParams) mSnapshotView.getLayoutParams()).bottomMargin; view.setAlpha(mFooterAlpha); mFooters[index] = new FooterWrapper(view); if (shouldAnimateEntry) { mFooters[index].animateEntry(); } } else { mFooters[index] = null; } mStackHeight = 0; for (FooterWrapper footer : mFooters) { if (footer != null) { footer.setVerticalShift(mStackHeight); mStackHeight += footer.mExpectedHeight; } } return oldFooter; } /** * Sets the contextual chip. * Loading Loading @@ -777,24 +716,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { SYSTEM_GESTURE_EXCLUSION_RECT.get(0).set(0, 0, getWidth(), getHeight()); setSystemGestureExclusionRects(SYSTEM_GESTURE_EXCLUSION_RECT); } mStackHeight = 0; for (FooterWrapper footer : mFooters) { if (footer != null) { mStackHeight += footer.mView.getHeight(); } } updateFooterVerticalOffset(0); } private void updateFooterVerticalOffset(float offset) { mFooterVerticalOffset = offset; for (FooterWrapper footer : mFooters) { if (footer != null) { footer.updateFooterOffset(); } } } public static float getCurveScaleForInterpolation(float linearInterpolation) { Loading Loading @@ -857,71 +778,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } } private class FooterWrapper extends ViewOutlineProvider { final View mView; final ViewOutlineProvider mOldOutlineProvider; final ViewOutlineProvider mDelegate; final int mExpectedHeight; final int mOldPaddingBottom; int mAnimationOffset = 0; int mEntryAnimationOffset = 0; public FooterWrapper(View view) { mView = view; mOldOutlineProvider = view.getOutlineProvider(); mDelegate = mOldOutlineProvider == null ? ViewOutlineProvider.BACKGROUND : mOldOutlineProvider; mExpectedHeight = getExpectedViewHeight(view); mOldPaddingBottom = view.getPaddingBottom(); if (mOldOutlineProvider != null) { view.setOutlineProvider(this); view.setClipToOutline(true); } } public void setVerticalShift(int shift) { mView.setPadding(mView.getPaddingLeft(), mView.getPaddingTop(), mView.getPaddingRight(), mOldPaddingBottom + shift); } @Override public void getOutline(View view, Outline outline) { mDelegate.getOutline(view, outline); outline.offset(0, -mAnimationOffset - mEntryAnimationOffset); } void updateFooterOffset() { float offset = Utilities.or(mFooterVerticalOffset, mModalness); mAnimationOffset = Math.round(mStackHeight * offset); mView.setTranslationY(mAnimationOffset + mEntryAnimationOffset + mCurrentFullscreenParams.mCurrentDrawnInsets.bottom + mCurrentFullscreenParams.mCurrentDrawnInsets.top); mView.invalidateOutline(); } void release() { mView.setOutlineProvider(mOldOutlineProvider); setVerticalShift(0); } void animateEntry() { ValueAnimator animator = ValueAnimator.ofFloat(0, 1); animator.addUpdateListener(anim -> { float factor = 1 - anim.getAnimatedFraction(); int totalShift = mExpectedHeight + mView.getPaddingBottom() - mOldPaddingBottom; mEntryAnimationOffset = Math.round(factor * totalShift); updateFooterOffset(); }); animator.setDuration(100); animator.start(); } } private int getExpectedViewHeight(View view) { int expectedHeight; int h = view.getLayoutParams().height; Loading