From bd294477091949d75b1f9d3cfef749ad80607c99 Mon Sep 17 00:00:00 2001 From: Mike Schneider Date: Sun, 11 Sep 2022 21:01:09 +0200 Subject: [PATCH 1/2] Implement brightness slider unfurl in QQS->QS translation according to spec. The main issue was that the brightness slider needed to have a set of different translations applied, with incompatible interpolators. This change simplifies the implementation to avoid the need for these different translations, ultimately solving the root cause of the issue. Some background on this change: - the mTranslateWhileExpanding is not used anymore - it was only set to true in split-shade mode, but then the expansion progress is always (hardcoded to 1) [http://cs/android-internal/frameworks/base/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java;l=2438-2441;rcl=21c205b93846470b2c4786361fe59e404a95ed6a], thus the animator never produces a translationY != 0. Thus removed it. - The mQSTileLayoutTranslatorAnimator is undoing the motion applied in [QSFragment](http://cs/android/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java;l=658;rcl=bbf0913e49af9615a0d9bf84835fe1725812f78e). The exception to this is the expanded-shade-edge-swipe-down on lock-screen, where QSAnimator would not compensate, since the animator gets [pinned to 1](http://cs/android/frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java;l=654;rcl=bbf0913e49af9615a0d9bf84835fe1725812f78e). Now, just applying the motion in this case. This eliminates the implicit dependency between the two places, AND more importantly, removes the need to compensate for the motion with a linear interpolator. Bug: 203537805 Bug: 243261680 Test: Manual on phone and tablet (split shade) Change-Id: I85cef48fc9e695d32e67fa35b2a49f01c10b5293 --- .../com/android/systemui/qs/QSAnimator.java | 85 ++++++++++--------- .../com/android/systemui/qs/QSFragment.java | 7 +- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index 920f4634abe22..e1289a61d45d0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -99,7 +99,7 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener // slider, as well as animating the alpha of the QS tile layout (as we are tracking QQS tiles) @Nullable private TouchAnimator mFirstPageAnimator; - // TranslationX animator for QQS/QS tiles + // TranslationX animator for QQS/QS tiles. Only used on the first page! private TouchAnimator mTranslationXAnimator; // TranslationY animator for QS tiles (and their components) in the first page private TouchAnimator mTranslationYAnimator; @@ -107,13 +107,14 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener private TouchAnimator mQQSTranslationYAnimator; // Animates alpha of permanent views (QS tile layout, QQS tiles) when not in first page private TouchAnimator mNonfirstPageAlphaAnimator; - // TranslatesY the QS Tile layout using QS.getHeightDiff() - private TouchAnimator mQSTileLayoutTranslatorAnimator; // This animates fading of media player private TouchAnimator mAllPagesDelayedAnimator; - // Animator for brightness slider(s) + // Brightness slider translation driver, uses mQSExpansionPathInterpolator.yInterpolator @Nullable - private TouchAnimator mBrightnessAnimator; + private TouchAnimator mBrightnessTranslationAnimator; + // Brightness slider opacity driver. Uses linear interpolator. + @Nullable + private TouchAnimator mBrightnessOpacityAnimator; // Animator for Footer actions in QQS private TouchAnimator mQQSFooterActionsAnimator; // Height animator for QQS tiles (height changing from QQS size to QS size) @@ -137,7 +138,6 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener private final QSTileHost mHost; private final Executor mExecutor; private boolean mShowCollapsedOnKeyguard; - private boolean mTranslateWhileExpanding; private int mQQSTop; private int[] mTmpLoc1 = new int[2]; @@ -298,13 +298,6 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener QSTileLayout tileLayout = mQsPanelController.getTileLayout(); mAllViews.add((View) tileLayout); - int heightDiff = mQs.getHeightDiff(); - if (!mTranslateWhileExpanding) { - heightDiff *= SHORT_PARALLAX_AMOUNT; - } - mQSTileLayoutTranslatorAnimator = new Builder() - .addFloat(tileLayout, "translationY", heightDiff, 0) - .build(); mLastQQSTileHeight = 0; @@ -407,12 +400,7 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener mAnimatedQsViews.add(tileView); mAllViews.add(quickTileView); mAllViews.add(quickTileView.getSecondaryLabel()); - } else if (isIconInAnimatedRow(count)) { - - firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0); - - mAllViews.add(tileIcon); - } else { + } else if (!isIconInAnimatedRow(count)) { // Pretend there's a corresponding QQS tile (for the position) that we are // expanding from. SideLabelTileLayout qqsLayout = @@ -442,7 +430,7 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener } } - animateBrightnessSlider(firstPageBuilder); + animateBrightnessSlider(); mFirstPageAnimator = firstPageBuilder // Fade in the tiles/labels as we reach the final position. @@ -568,7 +556,9 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener return new Pair<>(animator, builder.build()); } - private void animateBrightnessSlider(Builder firstPageBuilder) { + private void animateBrightnessSlider() { + mBrightnessTranslationAnimator = null; + mBrightnessOpacityAnimator = null; View qsBrightness = mQsPanelController.getBrightnessView(); View qqsBrightness = mQuickQSPanelController.getBrightnessView(); if (qqsBrightness != null && qqsBrightness.getVisibility() == View.VISIBLE) { @@ -576,25 +566,45 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener mAnimatedQsViews.add(qsBrightness); mAllViews.add(qqsBrightness); int translationY = getRelativeTranslationY(qsBrightness, qqsBrightness); - mBrightnessAnimator = new Builder() + mBrightnessTranslationAnimator = new Builder() // we need to animate qs brightness even if animation will not be visible, // as we might start from sliderScaleY set to 0.3 if device was in collapsed QS // portrait orientation before .addFloat(qsBrightness, "sliderScaleY", 0.3f, 1) .addFloat(qqsBrightness, "translationY", 0, translationY) + .setInterpolator(mQSExpansionPathInterpolator.getYInterpolator()) .build(); } else if (qsBrightness != null) { - firstPageBuilder.addFloat(qsBrightness, "translationY", - qsBrightness.getMeasuredHeight() * 0.5f, 0); - mBrightnessAnimator = new Builder() + // The brightness slider's visible bottom edge must maintain a constant margin from the + // QS tiles during transition. Thus the slider must (1) perform the same vertical + // translation as the tiles, and (2) compensate for the slider scaling. + + // For (1), compute the distance via the vertical distance between QQS and QS tile + // layout top. + View quickSettingsRootView = mQs.getView(); + View qsTileLayout = (View) mQsPanelController.getTileLayout(); + View qqsTileLayout = (View) mQuickQSPanelController.getTileLayout(); + getRelativePosition(mTmpLoc1, qsTileLayout, quickSettingsRootView); + getRelativePosition(mTmpLoc2, qqsTileLayout, quickSettingsRootView); + int tileMovement = mTmpLoc2[1] - mTmpLoc1[1]; + + // For (2), the slider scales to the vertical center, so compensate with half the + // height at full collapse. + float scaleCompensation = qsBrightness.getMeasuredHeight() * 0.5f; + mBrightnessTranslationAnimator = new Builder() + .addFloat(qsBrightness, "translationY", scaleCompensation + tileMovement, 0) + .addFloat(qsBrightness, "sliderScaleY", 0, 1) + .setInterpolator(mQSExpansionPathInterpolator.getYInterpolator()) + .build(); + + // While the slider's position and unfurl is animated throughouth the motion, the + // fade in happens independently. + mBrightnessOpacityAnimator = new Builder() .addFloat(qsBrightness, "alpha", 0, 1) - .addFloat(qsBrightness, "sliderScaleY", 0.3f, 1) - .setInterpolator(Interpolators.ALPHA_IN) - .setStartDelay(0.3f) + .setStartDelay(0.2f) + .setEndDelay(1 - 0.5f) .build(); mAllViews.add(qsBrightness); - } else { - mBrightnessAnimator = null; } } @@ -676,11 +686,13 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener if (mQQSTileHeightAnimator != null) { mQQSTileHeightAnimator.setPosition(position); } - mQSTileLayoutTranslatorAnimator.setPosition(position); mQQSTranslationYAnimator.setPosition(position); mAllPagesDelayedAnimator.setPosition(position); - if (mBrightnessAnimator != null) { - mBrightnessAnimator.setPosition(position); + if (mBrightnessOpacityAnimator != null) { + mBrightnessOpacityAnimator.setPosition(position); + } + if (mBrightnessTranslationAnimator != null) { + mBrightnessTranslationAnimator.setPosition(position); } if (mQQSFooterActionsAnimator != null) { mQQSFooterActionsAnimator.setPosition(position); @@ -774,13 +786,6 @@ public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener setCurrentPosition(); }; - /** - * True whe QS will be pulled from the top, false when it will be clipped. - */ - public void setTranslateWhileExpanding(boolean shouldTranslate) { - mTranslateWhileExpanding = shouldTranslate; - } - private static class HeightExpansionAnimator { private final List mViews = new ArrayList<>(); private final ValueAnimator mAnimator; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 90fa94c8435a0..7b27cf45979f1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -573,7 +573,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca @Override public void setInSplitShade(boolean inSplitShade) { mInSplitShade = inSplitShade; - mQSAnimator.setTranslateWhileExpanding(inSplitShade); updateShowCollapsedOnKeyguard(); updateQsState(); } @@ -669,7 +668,11 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca mQSPanelController.setRevealExpansion(expansion); mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation); mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation); - mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff); + + float qsScrollViewTranslation = + onKeyguard && !mShowCollapsedOnKeyguard ? panelTranslationY : 0; + mQSPanelScrollView.setTranslationY(qsScrollViewTranslation); + if (fullyCollapsed) { mQSPanelScrollView.setScrollY(0); } From f1fd806271a7c74cbf719ddfa696092d00b9a7ea Mon Sep 17 00:00:00 2001 From: Mike Schneider Date: Mon, 12 Sep 2022 23:07:57 +0200 Subject: [PATCH 2/2] Reduce brightness-slider bottom margin to 16dp, as per spec https://www.figma.com/file/8Q7oe3QpvXNGpg2k61YvAt/Shade?node-id=5508%3A162185 Bug: 203537805 Test: Manually, shared updated screenshot with designer Change-Id: Ibf05654cd9fd494f74a4661768d5ec5585e98a3d --- packages/SystemUI/res/values/dimens.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 8089bb1bf9245..e0264c30eeece 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -520,7 +520,7 @@ @dimen/qs_tile_margin_horizontal 4dp 8dp - 24dp + 16dp 16dp 24dp