Merge "Make QS buttons squishy" into sc-v2-dev am: b19768ef82 am: 6a256fc113

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16058353

Change-Id: Idb5f7050f4cf0d726d995020c94319697fae8452
This commit is contained in:
Lucas Dupin
2021-10-27 16:49:01 +00:00
committed by Automerger Merge Worker
17 changed files with 239 additions and 28 deletions

View File

@@ -55,13 +55,14 @@ public interface QS extends FragmentBase {
/**
* Asks QS to update its presentation, according to {@code NotificationPanelViewController}.
*
* @param qsExpansionFraction How much each UI element in QS should be expanded (QQS to QS.)
* @param panelExpansionFraction Whats the expansion of the whole shade.
* @param headerTranslation How much we should vertically translate QS.
* @param squishinessFraction Fraction that affects tile height. 0 when collapsed,
* 1 when expanded.
*/
void setQsExpansion(float qsExpansionFraction, float panelExpansionFraction,
float headerTranslation);
float headerTranslation, float squishinessFraction);
void setHeaderListening(boolean listening);
void notifyCustomizeChanged();
void setContainerController(QSContainerController controller);

View File

@@ -23,6 +23,6 @@
<dimen name="widget_big_font_size">88dp</dimen>
<dimen name="qs_header_system_icons_area_height">0dp</dimen>
<dimen name="qs_panel_padding_top">0dp</dimen>
<dimen name="qs_panel_padding_top">@dimen/qqs_layout_margin_top</dimen>
</resources>

View File

@@ -63,7 +63,7 @@
android:id="@+id/qqs_footer_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginTop="@dimen/qqs_layout_margin_top"
android:layout_marginStart="@dimen/qs_footer_margin"
android:layout_marginEnd="@dimen/qs_footer_margin"
/>

View File

@@ -166,6 +166,11 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
updateListening();
}
@Override
public void setSquishinessFraction(float squishinessFraction) {
// No-op, paged layouts are not squishy.
}
private void updateListening() {
for (TileLayout tilePage : mPages) {
tilePage.setListening(tilePage.getParent() != null && mListening);

View File

@@ -316,8 +316,8 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
if (mQQSTileHeightAnimator == null) {
mQQSTileHeightAnimator = new HeightExpansionAnimator(this,
quickTileView.getHeight(), tileView.getHeight());
qqsTileHeight = quickTileView.getHeight();
quickTileView.getMeasuredHeight(), tileView.getMeasuredHeight());
qqsTileHeight = quickTileView.getMeasuredHeight();
}
mQQSTileHeightAnimator.addView(quickTileView);
@@ -380,7 +380,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
if (mOtherTilesExpandAnimator == null) {
mOtherTilesExpandAnimator =
new HeightExpansionAnimator(
this, qqsTileHeight, tileView.getHeight());
this, qqsTileHeight, tileView.getMeasuredHeight());
}
mOtherTilesExpandAnimator.addView(tileView);
tileView.setClipChildren(true);
@@ -658,7 +658,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
mTranslateWhileExpanding = shouldTranslate;
}
static class HeightExpansionAnimator {
private static class HeightExpansionAnimator {
private final List<View> mViews = new ArrayList<>();
private final ValueAnimator mAnimator;
private final TouchAnimator.Listener mListener;
@@ -673,9 +673,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
int height = (Integer) valueAnimator.getAnimatedValue();
for (int i = 0; i < viewCount; i++) {
View v = mViews.get(i);
v.setBottom(v.getTop() + height);
if (v instanceof HeightOverrideable) {
((HeightOverrideable) v).setHeightOverride(height);
} else {
v.setBottom(v.getTop() + height);
}
}
if (t == 0f) {
@@ -713,9 +714,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
final int viewsCount = mViews.size();
for (int i = 0; i < viewsCount; i++) {
View v = mViews.get(i);
v.setBottom(v.getTop() + v.getMeasuredHeight());
if (v instanceof HeightOverrideable) {
((HeightOverrideable) v).resetOverride();
} else {
v.setBottom(v.getTop() + v.getMeasuredHeight());
}
}
}

View File

@@ -81,6 +81,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private QSAnimator mQSAnimator;
private HeightListener mPanelView;
private QSSquishinessController mQSSquishinessController;
protected QuickStatusBarHeader mHeader;
protected NonInterceptingScrollView mQSPanelScrollView;
private QSDetail mQSDetail;
@@ -90,6 +91,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private QSFooter mFooter;
private float mLastQSExpansion = -1;
private float mLastPanelFraction;
private float mSquishinessFraction = 1;
private boolean mQsDisabled;
private ImageView mQsDragHandler;
@@ -210,6 +212,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter, mFalsingManager);
mQSAnimator = qsFragmentComponent.getQSAnimator();
mQSSquishinessController = qsFragmentComponent.getQSSquishinessController();
mQSCustomizerController = qsFragmentComponent.getQSCustomizerController();
mQSCustomizerController.init();
@@ -231,7 +234,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
boolean sizeChanged = (oldTop - oldBottom) != (top - bottom);
if (sizeChanged) {
setQsExpansion(mLastQSExpansion, mLastPanelFraction,
mLastHeaderTranslation);
mLastHeaderTranslation, mSquishinessFraction);
}
});
mQSPanelController.setUsingHorizontalLayoutChangeListener(
@@ -413,7 +416,8 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mQSAnimator.setShowCollapsedOnKeyguard(showCollapsed);
}
if (!showCollapsed && isKeyguardState()) {
setQsExpansion(mLastQSExpansion, mLastPanelFraction, 0);
setQsExpansion(mLastQSExpansion, mLastPanelFraction, 0,
mSquishinessFraction);
}
}
}
@@ -494,12 +498,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
updateShowCollapsedOnKeyguard();
}
mFullShadeProgress = progress;
setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation);
setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation,
isTransitioningToFullShade ? progress : mSquishinessFraction);
}
@Override
public void setQsExpansion(float expansion, float panelExpansionFraction,
float proposedTranslation) {
float proposedTranslation, float squishinessFraction) {
float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
float progress = mTransitioningToFullShade ? mFullShadeProgress : panelExpansionFraction;
setAlphaAnimationProgress(mInSplitShade ? progress : 1);
@@ -517,11 +522,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
if (expansion == mLastQSExpansion
&& mLastKeyguardAndExpanded == onKeyguardAndExpanded
&& mLastViewHeight == currentHeight
&& mLastHeaderTranslation == headerTranslation) {
&& mLastHeaderTranslation == headerTranslation
&& mSquishinessFraction == squishinessFraction) {
return;
}
mLastHeaderTranslation = headerTranslation;
mLastPanelFraction = panelExpansionFraction;
mSquishinessFraction = squishinessFraction;
mLastQSExpansion = expansion;
mLastKeyguardAndExpanded = onKeyguardAndExpanded;
mLastViewHeight = currentHeight;
@@ -557,6 +564,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
updateQsBounds();
if (mQSSquishinessController != null) {
mQSSquishinessController.setSquishiness(mSquishinessFraction);
}
if (mQSAnimator != null) {
mQSAnimator.setPosition(expansion);
}

View File

@@ -735,6 +735,11 @@ public class QSPanel extends LinearLayout implements Tunable {
/** */
void setListening(boolean listening, UiEventLogger uiEventLogger);
/**
* Sets a size modifier for the tile. Where 0 means collapsed, and 1 expanded.
*/
void setSquishinessFraction(float squishinessFraction);
/**
* Sets the minimum number of rows to show
*

View File

@@ -0,0 +1,64 @@
package com.android.systemui.qs
import android.view.ViewGroup
import com.android.systemui.qs.dagger.QSFragmentModule.QQS_FOOTER
import com.android.systemui.qs.dagger.QSScope
import com.android.systemui.qs.tileimpl.HeightOverrideable
import javax.inject.Inject
import javax.inject.Named
@QSScope
class QSSquishinessController @Inject constructor(
private val qsTileHost: QSTileHost,
@Named(QQS_FOOTER) private val qqsFooterActionsView: FooterActionsView,
private val qsAnimator: QSAnimator,
private val quickQSPanelController: QuickQSPanelController
) {
/**
* Fraction from 0 to 1, where 0 is collapsed and 1 expanded.
*/
var squishiness: Float = 1f
set(value) {
if (field == value) {
return
}
if ((field != 1f && value == 1f) || (field != 0f && value == 0f)) {
qsAnimator.requestAnimatorUpdate()
}
field = value
updateSquishiness()
}
/**
* Change the height of all tiles and repositions their siblings.
*/
private fun updateSquishiness() {
// Start by updating the height of all tiles
for (tile in qsTileHost.tiles) {
val tileView = quickQSPanelController.getTileView(tile)
(tileView as? HeightOverrideable)?.let {
it.squishinessFraction = squishiness
}
}
// Update tile positions in the layout
val tileLayout = quickQSPanelController.tileLayout as TileLayout
tileLayout.setSquishinessFraction(squishiness)
// Calculate how much we should move the footer
val tileHeightOffset = tileLayout.height - tileLayout.tilesHeight
val footerTopMargin = (qqsFooterActionsView.layoutParams as ViewGroup.MarginLayoutParams)
.topMargin
val nextTop = tileLayout.bottom - tileHeightOffset + footerTopMargin
val amountMoved = nextTop - qqsFooterActionsView.top
// Move the footer and other siblings (MediaPlayer)
(qqsFooterActionsView.parent as ViewGroup?)?.let { parent ->
val index = parent.indexOfChild(qqsFooterActionsView)
for (i in index until parent.childCount) {
parent.getChildAt(i).top += amountMoved
}
}
}
}

View File

@@ -41,6 +41,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
private int mMinRows = 1;
private int mMaxColumns = NO_MAX_COLUMNS;
protected int mResourceColumns;
private float mSquishinessFraction = 1f;
private int mLastTileBottom;
public TileLayout(Context context) {
this(context, null);
@@ -210,10 +212,11 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
return mMaxCellHeight;
}
protected void layoutTileRecords(int numRecords) {
private void layoutTileRecords(int numRecords) {
final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
int row = 0;
int column = 0;
mLastTileBottom = 0;
// Layout each QS tile.
final int tilesToLayout = Math.min(numRecords, mRows * mColumns);
@@ -228,7 +231,9 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
final int top = getRowTop(row);
final int left = getColumnStart(isRtl ? mColumns - column - 1 : column);
final int right = left + mCellWidth;
record.tileView.layout(left, top, right, top + record.tileView.getMeasuredHeight());
final int bottom = top + record.tileView.getMeasuredHeight();
record.tileView.layout(left, top, right, bottom);
mLastTileBottom = bottom;
}
}
@@ -238,7 +243,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
}
protected int getRowTop(int row) {
return row * (mCellHeight + mCellMarginVertical);
return (int) (row * (mCellHeight * mSquishinessFraction + mCellMarginVertical));
}
protected int getColumnStart(int column) {
@@ -264,4 +269,17 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
// up.
return Math.max(mColumns * mRows, 1);
}
public int getTilesHeight() {
return mLastTileBottom + getPaddingBottom();
}
@Override
public void setSquishinessFraction(float squishinessFraction) {
if (Float.compare(mSquishinessFraction, squishinessFraction) == 0) {
return;
}
mSquishinessFraction = squishinessFraction;
layoutTileRecords(mRecords.size());
}
}

View File

@@ -21,6 +21,7 @@ import com.android.systemui.qs.QSContainerImplController;
import com.android.systemui.qs.QSFooter;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.qs.QSSquishinessController;
import com.android.systemui.qs.QuickQSPanelController;
import com.android.systemui.qs.customize.QSCustomizerController;
@@ -57,4 +58,7 @@ public interface QSFragmentComponent {
/** Construct a {@link QSCustomizerController}. */
QSCustomizerController getQSCustomizerController();
/** Construct a {@link QSSquishinessController}. */
QSSquishinessController getQSSquishinessController();
}

View File

@@ -21,9 +21,8 @@ interface HeightOverrideable {
const val NO_OVERRIDE = -1
}
var heightOverride: Int
abstract var heightOverride: Int
abstract fun resetOverride()
fun resetOverride() {
heightOverride = NO_OVERRIDE
}
abstract var squishinessFraction: Float
}

View File

@@ -68,6 +68,18 @@ open class QSTileViewImpl @JvmOverloads constructor(
}
override var heightOverride: Int = HeightOverrideable.NO_OVERRIDE
set(value) {
if (field == value) return
field = value
updateHeight()
}
override var squishinessFraction: Float = 1f
set(value) {
if (field == value) return
field = value
updateHeight()
}
private val colorActive = Utils.getColorAttrDefaultColor(context,
com.android.internal.R.attr.colorAccentPrimary)
@@ -148,6 +160,11 @@ open class QSTileViewImpl @JvmOverloads constructor(
updateResources()
}
override fun resetOverride() {
heightOverride = HeightOverrideable.NO_OVERRIDE
updateHeight()
}
fun updateResources() {
FontSizeUtils.updateFontSize(label, R.dimen.qs_tile_text_size)
FontSizeUtils.updateFontSize(secondaryLabel, R.dimen.qs_tile_text_size)
@@ -218,9 +235,17 @@ open class QSTileViewImpl @JvmOverloads constructor(
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
super.onLayout(changed, l, t, r, b)
if (heightOverride != HeightOverrideable.NO_OVERRIDE) {
bottom = top + heightOverride
}
updateHeight()
}
private fun updateHeight() {
val actualHeight = (if (heightOverride != HeightOverrideable.NO_OVERRIDE) {
heightOverride
} else {
measuredHeight
} * squishinessFraction).toInt()
bottom = top + actualHeight
scrollY = (actualHeight - height) / 2
}
override fun updateAccessibilityOrder(previousView: View?): View {

View File

@@ -653,6 +653,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return 0f;
}
public float getNotificationSquishinessFraction() {
return mStackScrollAlgorithm.getNotificationSquishinessFraction(mAmbientState);
}
void reinflateViews() {
inflateFooterView();
inflateEmptyShadeView();

View File

@@ -1078,6 +1078,10 @@ public class NotificationStackScrollLayoutController {
mView.setOnStackYChanged(onStackYChanged);
}
public float getNotificationSquishinessFraction() {
return mView.getNotificationSquishinessFraction();
}
public float calculateAppearFractionBypass() {
return mView.calculateAppearFractionBypass();
}

View File

@@ -110,6 +110,15 @@ public class StackScrollAlgorithm {
getNotificationChildrenStates(algorithmState, ambientState);
}
/**
* How expanded or collapsed notifications are when pulling down the shade.
* @param ambientState Current ambient state.
* @return 0 when fully collapsed, 1 when expanded.
*/
public float getNotificationSquishinessFraction(AmbientState ambientState) {
return getExpansionFractionWithoutShelf(mTempAlgorithmState, ambientState);
}
private void resetChildViewStates() {
int numChildren = mHostView.getChildCount();
for (int i = 0; i < numChildren; i++) {
@@ -364,7 +373,6 @@ public class StackScrollAlgorithm {
final float stackHeight = ambientState.getStackHeight() - shelfHeight - scrimPadding;
final float stackEndHeight = ambientState.getStackEndHeight() - shelfHeight - scrimPadding;
return stackHeight / stackEndHeight;
}

View File

@@ -468,7 +468,6 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mPulsing;
private boolean mUserSetupComplete;
private int mQsNotificationTopPadding;
private boolean mHideIconsDuringLaunchAnimation = true;
private int mStackScrollerMeasuringPass;
private ArrayList<Consumer<ExpandableNotificationRow>>
@@ -2360,7 +2359,8 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateQsExpansion() {
if (mQs == null) return;
float qsExpansionFraction = computeQsExpansionFraction();
mQs.setQsExpansion(qsExpansionFraction, getExpandedFraction(), getHeaderTranslation());
mQs.setQsExpansion(qsExpansionFraction, getExpandedFraction(), getHeaderTranslation(),
mNotificationStackScrollLayoutController.getNotificationSquishinessFraction());
mMediaHierarchyManager.setQsExpansion(qsExpansionFraction);
int qsPanelBottomY = calculateQsBottomPosition(qsExpansionFraction);
mScrimController.setQsPosition(qsExpansionFraction, qsPanelBottomY);

View File

@@ -0,0 +1,62 @@
package com.android.systemui.qs
import android.testing.AndroidTestingRunner
import android.view.ViewGroup
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.tileimpl.QSTileViewImpl
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
@RunWith(AndroidTestingRunner::class)
@SmallTest
class QSSquishinessControllerTest : SysuiTestCase() {
@Mock private lateinit var qsTileHost: QSTileHost
@Mock private lateinit var qqsFooterActionsView: FooterActionsView
@Mock private lateinit var qqsFooterActionsViewLP: ViewGroup.MarginLayoutParams
@Mock private lateinit var qsAnimator: QSAnimator
@Mock private lateinit var quickQsPanelController: QuickQSPanelController
@Mock private lateinit var qstileView: QSTileViewImpl
@Mock private lateinit var qstile: QSTile
@Mock private lateinit var tileLayout: TileLayout
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
private lateinit var qsSquishinessController: QSSquishinessController
@Before
fun setup() {
qsSquishinessController = QSSquishinessController(qsTileHost, qqsFooterActionsView,
qsAnimator, quickQsPanelController)
`when`(qsTileHost.tiles).thenReturn(mutableListOf(qstile))
`when`(quickQsPanelController.getTileView(any())).thenReturn(qstileView)
`when`(quickQsPanelController.tileLayout).thenReturn(tileLayout)
`when`(qqsFooterActionsView.layoutParams).thenReturn(qqsFooterActionsViewLP)
}
@Test
fun setSquishiness_requestsAnimatorUpdate() {
qsSquishinessController.squishiness = 0.5f
verify(qsAnimator, never()).requestAnimatorUpdate()
qsSquishinessController.squishiness = 0f
verify(qsAnimator).requestAnimatorUpdate()
}
@Test
fun setSquishiness_updatesTiles() {
qsSquishinessController.squishiness = 0.5f
verify(qstileView).squishinessFraction = 0.5f
verify(tileLayout).setSquishinessFraction(0.5f)
}
}