summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java4
-rw-r--r--packages/SystemUI/res/drawable/qs_tile_background.xml23
-rw-r--r--packages/SystemUI/res/drawable/qs_tile_background_shape.xml21
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java170
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFragment.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt104
16 files changed, 357 insertions, 58 deletions
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
index 53f7e44bc25a..ca1320448726 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTileView.java
@@ -50,4 +50,8 @@ public abstract class QSTileView extends LinearLayout {
public abstract void onStateChanged(State state);
public abstract int getDetailY();
+
+ public View getLabelContainer() {
+ return null;
+ }
}
diff --git a/packages/SystemUI/res/drawable/qs_tile_background.xml b/packages/SystemUI/res/drawable/qs_tile_background.xml
new file mode 100644
index 000000000000..265f575fc99c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_tile_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask"
+ android:drawable="@drawable/qs_tile_background_shape" />
+ <item android:id="@id/background"
+ android:drawable="@drawable/qs_tile_background_shape"/>
+</ripple> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_tile_background_shape.xml b/packages/SystemUI/res/drawable/qs_tile_background_shape.xml
new file mode 100644
index 000000000000..f6b68347124e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_tile_background_shape.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/qs_corner_radius" />
+ <solid android:color="#FFFFFF" />
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 885cd254a1ea..2062104be2df 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -512,6 +512,7 @@
<!-- The size of the gesture span needed to activate the "pull" notification expansion -->
<dimen name="pull_span_min">25dp</dimen>
+ <dimen name="qs_corner_radius">14dp</dimen>
<dimen name="qs_tile_height">96dp</dimen>
<!--notification_side_paddings + notification_content_margin_start - (qs_quick_tile_size - qs_tile_background_size) / 2 -->
<dimen name="qs_tile_layout_margin_side">18dp</dimen>
@@ -528,6 +529,8 @@
<dimen name="qs_tile_margin_top">0dp</dimen>
<dimen name="qs_tile_icon_background_stroke_width">-1dp</dimen>
<dimen name="qs_tile_background_size">44dp</dimen>
+ <dimen name="qs_icon_size">20dp</dimen>
+ <dimen name="qs_label_container_margin">10dp</dimen>
<dimen name="qs_quick_tile_size">48dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index fe76668ab68b..b8823e148e68 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,6 +14,8 @@
package com.android.systemui.qs;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
import android.util.Log;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
@@ -35,6 +37,7 @@ import com.android.systemui.tuner.TunerService.Tunable;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -77,6 +80,9 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
// This animates fading of SecurityFooter and media divider
private TouchAnimator mAllPagesDelayedAnimator;
private TouchAnimator mBrightnessAnimator;
+ private HeightExpansionAnimator mQQSTileHeightAnimator;
+ private HeightExpansionAnimator mOtherTilesExpandAnimator;
+
private boolean mNeedsAnimatorUpdate = false;
private boolean mOnKeyguard;
@@ -161,7 +167,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
@Override
public void onViewAttachedToWindow(View v) {
mTunerService.addTunable(this, ALLOW_FANCY_ANIMATION,
- MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
+ MOVE_FULL_ROWS);
}
@Override
@@ -179,9 +185,6 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
}
} else if (MOVE_FULL_ROWS.equals(key)) {
mFullRows = TunerService.parseIntegerSwitch(newValue, true);
- } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
- mNumQuickTiles = QuickQSPanel.parseNumTiles(newValue);
- clearAnimationState();
}
updateAnimators();
}
@@ -209,6 +212,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
clearAnimationState();
mAllViews.clear();
mQuickQsViews.clear();
+ mQQSTileHeightAnimator = null;
+ mOtherTilesExpandAnimator = null;
+
+ mNumQuickTiles = mQuickQsPanel.getNumQuickTiles();
QSTileLayout tileLayout = mQsPanelController.getTileLayout();
mAllViews.add((View) tileLayout);
@@ -218,6 +225,9 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
+ mQs.getHeader().getPaddingBottom();
firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
+ boolean qsSideLabelsEnabled = mFeatureFlags.isQSLabelsEnabled();
+ int qqsTileHeight = 0;
+
for (QSTile tile : tiles) {
QSTileView tileView = mQsPanelController.getTileView(tile);
if (tileView == null) {
@@ -237,22 +247,47 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
getRelativePosition(loc1, quickTileView.getIcon().getIconView(), view);
getRelativePosition(loc2, tileIcon, view);
final int xDiff = loc2[0] - loc1[0];
- final int yDiff = loc2[1] - loc1[1];
-
+ int yDiff = loc2[1] - loc1[1];
if (count < tileLayout.getNumVisibleTiles()) {
+ getRelativePosition(loc1, quickTileView, view);
+ getRelativePosition(loc2, tileView, view);
+ int yOffset = qsSideLabelsEnabled ? loc2[1] - loc1[1] : 0;
// Move the quick tile right from its location to the new one.
- translationXBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
- translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
-
- // Counteract the parent translation on the tile. So we have a static base to
- // animate the label position off from.
- //firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+ View v = qsSideLabelsEnabled ? quickTileView.getIcon() : quickTileView;
+ translationXBuilder.addFloat(v, "translationX", 0, xDiff);
+ translationYBuilder.addFloat(v, "translationY", 0, yDiff - yOffset);
+ mAllViews.add(v);
// Move the real tile from the quick tile position to its final
// location.
- translationXBuilder.addFloat(tileView, "translationX", -xDiff, 0);
- translationYBuilder.addFloat(tileView, "translationY", -yDiff, 0);
+ v = qsSideLabelsEnabled ? tileIcon : tileView;
+ translationXBuilder.addFloat(v, "translationX", -xDiff, 0);
+ translationYBuilder.addFloat(v, "translationY", -yDiff + yOffset, 0);
+
+ if (qsSideLabelsEnabled) {
+ translationYBuilder.addFloat(quickTileView, "translationY", 0, yOffset);
+ translationYBuilder.addFloat(tileView, "translationY", -yOffset, 0);
+
+ if (mQQSTileHeightAnimator == null) {
+ mQQSTileHeightAnimator = new HeightExpansionAnimator(this,
+ quickTileView.getHeight(), tileView.getHeight());
+ qqsTileHeight = quickTileView.getHeight();
+ }
+
+ mQQSTileHeightAnimator.addView(quickTileView);
+ View qqsLabelContainer = quickTileView.getLabelContainer();
+ View qsLabelContainer = tileView.getLabelContainer();
+
+ getRelativePosition(loc1, qqsLabelContainer, view);
+ getRelativePosition(loc2, qsLabelContainer, view);
+ yDiff = loc2[1] - loc1[1] - yOffset;
+
+ translationYBuilder.addFloat(qqsLabelContainer, "translationY", 0, yDiff);
+ translationYBuilder.addFloat(qsLabelContainer, "translationY", -yDiff, 0);
+ mAllViews.add(qqsLabelContainer);
+ mAllViews.add(qsLabelContainer);
+ }
} else { // These tiles disappear when expanding
firstPageBuilder.addFloat(quickTileView, "alpha", 1, 0);
@@ -265,7 +300,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
translationX);
}
- if (mFeatureFlags.isQSLabelsEnabled()) {
+ if (qsSideLabelsEnabled) {
mQuickQsViews.add(tileView);
} else {
mQuickQsViews.add(tileView.getIconWithBackground());
@@ -278,9 +313,29 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
mAllViews.add(tileIcon);
} else {
- firstPageBuilder.addFloat(tileView, "alpha", 0, 1);
- firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
+ if (!qsSideLabelsEnabled) {
+ firstPageBuilder.addFloat(tileView, "alpha", 0, 1);
+ firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
+ } else {
+ // Pretend there's a corresponding QQS tile (for the position) that we are
+ // expanding from.
+ SideLabelTileLayout qqsLayout =
+ (SideLabelTileLayout) mQuickQsPanel.getTileLayout();
+ getRelativePosition(loc1, qqsLayout, view);
+ getRelativePosition(loc2, tileView, view);
+ int diff = loc2[1] - (loc1[1] + qqsLayout.getPhantomTopPosition(count));
+ translationYBuilder.addFloat(tileView, "translationY", -diff, 0);
+ if (mOtherTilesExpandAnimator == null) {
+ mOtherTilesExpandAnimator =
+ new HeightExpansionAnimator(
+ this, qqsTileHeight, tileView.getHeight());
+ }
+ mOtherTilesExpandAnimator.addView(tileView);
+ tileView.setClipChildren(true);
+ tileView.setClipToPadding(true);
+ }
}
+
mAllViews.add(tileView);
count++;
}
@@ -303,7 +358,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
.build();
// Fade in the tiles/labels as we reach the final position.
Builder builder = new Builder()
- .setStartDelay(EXPANDED_TILE_DELAY)
+ .setStartDelay(qsSideLabelsEnabled ? 0 : EXPANDED_TILE_DELAY)
.addFloat(tileLayout, "alpha", 0, 1);
mFirstPageDelayedAnimator = builder.build();
@@ -331,6 +386,12 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
translationYBuilder.setInterpolator(interpolatorBuilder.getYInterpolator());
mTranslationXAnimator = translationXBuilder.build();
mTranslationYAnimator = translationYBuilder.build();
+ if (mQQSTileHeightAnimator != null) {
+ mQQSTileHeightAnimator.setInterpolator(interpolatorBuilder.getYInterpolator());
+ }
+ if (mOtherTilesExpandAnimator != null) {
+ mOtherTilesExpandAnimator.setInterpolator(interpolatorBuilder.getYInterpolator());
+ }
}
mNonfirstPageAnimator = new TouchAnimator.Builder()
.addFloat(mQuickQsPanel, "alpha", 1, 0)
@@ -404,6 +465,12 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
if (mBrightnessAnimator != null) {
mBrightnessAnimator.setPosition(position);
}
+ if (mQQSTileHeightAnimator != null) {
+ mQQSTileHeightAnimator.setPosition(position);
+ }
+ if (mOtherTilesExpandAnimator != null) {
+ mOtherTilesExpandAnimator.setPosition(position);
+ }
} else {
mNonfirstPageAnimator.setPosition(position);
mNonfirstPageDelayedAnimator.setPosition(position);
@@ -446,6 +513,16 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
v.setAlpha(1);
v.setTranslationX(0);
v.setTranslationY(0);
+ if (v instanceof SideLabelTileLayout) {
+ ((SideLabelTileLayout) v).setClipChildren(false);
+ ((SideLabelTileLayout) v).setClipToPadding(false);
+ }
+ }
+ if (mQQSTileHeightAnimator != null) {
+ mQQSTileHeightAnimator.resetViewsHeights();
+ }
+ if (mOtherTilesExpandAnimator != null) {
+ mOtherTilesExpandAnimator.resetViewsHeights();
}
final int N2 = mQuickQsViews.size();
for (int i = 0; i < N2; i++) {
@@ -483,4 +560,61 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
updateAnimators();
setCurrentPosition();
};
+
+ static class HeightExpansionAnimator {
+ private final List<View> mViews = new ArrayList<>();
+ private final ValueAnimator mAnimator;
+ private final TouchAnimator.Listener mListener;
+
+ private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
+ new ValueAnimator.AnimatorUpdateListener() {
+ float mLastT = -1;
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ float t = valueAnimator.getAnimatedFraction();
+ if (t == 0f) {
+ mListener.onAnimationAtStart();
+ } else if (t == 1f) {
+ mListener.onAnimationAtEnd();
+ } else if (mLastT <= 0 || mLastT == 1) {
+ mListener.onAnimationStarted();
+ }
+ mLastT = t;
+ final int viewCount = mViews.size();
+ int height = (Integer) valueAnimator.getAnimatedValue();
+ for (int i = 0; i < viewCount; i++) {
+ View v = mViews.get(i);
+ v.setBottom(v.getTop() + height);
+ }
+ }
+ };
+
+ HeightExpansionAnimator(TouchAnimator.Listener listener, int startHeight, int endHeight) {
+ mListener = listener;
+ mAnimator = ValueAnimator.ofInt(startHeight, endHeight);
+ mAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ mAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ mAnimator.addUpdateListener(mUpdateListener);
+ }
+
+ void addView(View v) {
+ mViews.add(v);
+ }
+
+ void setInterpolator(TimeInterpolator interpolator) {
+ mAnimator.setInterpolator(interpolator);
+ }
+
+ void setPosition(float position) {
+ mAnimator.setCurrentFraction(position);
+ }
+
+ void resetViewsHeights() {
+ final int viewsCount = mViews.size();
+ for (int i = 0; i < viewsCount; i++) {
+ View v = mViews.get(i);
+ v.setBottom(v.getTop() + v.getMeasuredHeight());
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index ed308ae1ac6c..7c9f0b082d8f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -430,6 +430,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
mQSPanelController.setRevealExpansion(expansion);
mQSPanelController.getTileLayout().setExpansion(expansion);
+ mQuickQSPanelController.getTileLayout().setExpansion(expansion);
mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
if (fullyCollapsed) {
mQSPanelScrollView.setScrollY(0);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index ff9b9120c6e1..c794a2121cc2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -315,7 +315,7 @@ public class QSPanel extends LinearLayout implements Tunable {
int tileBg = getResources().getDimensionPixelSize(R.dimen.qs_tile_background_size);
mFooterMarginStartHorizontal = getResources().getDimensionPixelSize(
R.dimen.qs_footer_horizontal_margin);
- mVisualTilePadding = (int) ((tileSize - tileBg) / 2.0f);
+ mVisualTilePadding = mSideLabels ? 0 : (int) ((tileSize - tileBg) / 2.0f);
updatePadding();
updatePageIndicator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index f51d7ef381ee..8f99a9e9c1be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -348,6 +348,7 @@ public class QuickQSPanel extends QSPanel {
}
static class QQSSideLabelTileLayout extends SideLabelTileLayout {
+
QQSSideLabelTileLayout(Context context) {
super(context, null);
setClipChildren(false);
@@ -361,6 +362,7 @@ public class QuickQSPanel extends QSPanel {
@Override
public boolean updateResources() {
+ mCellHeightResId = R.dimen.qs_quick_tile_size;
boolean b = super.updateResources();
mMaxAllowedRows = 2;
return b;
@@ -379,5 +381,38 @@ public class QuickQSPanel extends QSPanel {
updateMaxRows(10000, mRecords.size());
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+
+ @Override
+ public void setListening(boolean listening, UiEventLogger uiEventLogger) {
+ boolean startedListening = !mListening && listening;
+ super.setListening(listening, uiEventLogger);
+ if (startedListening) {
+ // getNumVisibleTiles() <= mRecords.size()
+ for (int i = 0; i < getNumVisibleTiles(); i++) {
+ QSTile tile = mRecords.get(i).tile;
+ uiEventLogger.logWithInstanceId(QSEvent.QQS_TILE_VISIBLE, 0,
+ tile.getMetricsSpec(), tile.getInstanceId());
+ }
+ }
+ }
+
+ @Override
+ public void setExpansion(float expansion) {
+ if (expansion > 0f && expansion < 1f) {
+ return;
+ }
+ boolean selected = expansion == 0f;
+ // Expansion == 0f is when QQS is fully showing (as opposed to 1f, which is QS). At this
+ // point we want them to be selected so the tiles will marquee (but not at other points
+ // of expansion.
+ // We set it as not important while we change this, so setting each tile as selected
+ // will not cause them to announce themselves until the user has actually selected the
+ // item.
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).setSelected(selected);
+ }
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 671f8f7dd2d1..fee56b984ecc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -99,7 +99,7 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
break;
}
}
- super.setTiles(tiles, !mQSLabelFlag);
+ super.setTiles(tiles, /* collapsedView */ true);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
index 52f111e7ab48..0ebadfd2fa11 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
@@ -33,4 +33,15 @@ open class SideLabelTileLayout(
override fun isFull(): Boolean {
return mRecords.size >= maxTiles()
}
+
+ /**
+ * Return the position from the top of the layout of the tile with this index.
+ *
+ * This will return a position even for indices that go beyond [maxTiles], continuing the rows
+ * beyond that.
+ */
+ fun getPhantomTopPosition(index: Int): Int {
+ val row = index / mColumns
+ return getRowTop(row)
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index c1ce4a577dda..9e0aa5ad78b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -25,6 +25,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
protected int mColumns;
protected int mCellWidth;
+ protected int mCellHeightResId = R.dimen.qs_tile_height;
protected int mCellHeight;
protected int mMaxCellHeight;
protected int mCellMarginHorizontal;
@@ -118,7 +119,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
final Resources res = mContext.getResources();
mResourceColumns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
updateColumns();
- mMaxCellHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height);
+ mMaxCellHeight = mContext.getResources().getDimensionPixelSize(mCellHeightResId);
mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
@@ -235,7 +236,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
layoutTileRecords(mRecords.size());
}
- private int getRowTop(int row) {
+ protected int getRowTop(int row) {
return row * (mCellHeight + mCellMarginVertical) + mCellMarginTop;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
index f8c0dd4239d9..7977b4904a7d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileViewHorizontal.kt
@@ -14,7 +14,7 @@ import com.android.systemui.qs.tileimpl.QSTileViewHorizontal
class CustomizeTileViewHorizontal(
context: Context,
icon: QSIconView
-) : QSTileViewHorizontal(context, icon),
+) : QSTileViewHorizontal(context, icon, collapsed = false),
TileAdapter.CustomizeView {
private var showAppLabel = false
@@ -27,6 +27,7 @@ class CustomizeTileViewHorizontal(
override fun handleStateChanged(state: QSTile.State) {
super.handleStateChanged(state)
+ mShowRippleEffect = false
mSecondLine.visibility = if (showAppLabel) View.VISIBLE else View.GONE
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 9e5fe732cd0c..29b9e64d1659 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -248,10 +248,10 @@ public class QSFactoryImpl implements QSFactory {
public QSTileView createTileView(QSTile tile, boolean collapsedView) {
Context context = new ContextThemeWrapper(mQsHostLazy.get().getContext(), R.style.qs_theme);
QSIconView icon = tile.createTileView(context);
- if (collapsedView) {
+ if (mSideLabels) {
+ return new QSTileViewHorizontal(context, icon, collapsedView);
+ } else if (collapsedView) {
return new QSTileBaseView(context, icon, collapsedView);
- } else if (mSideLabels) {
- return new QSTileViewHorizontal(context, icon);
} else {
return new com.android.systemui.qs.tileimpl.QSTileView(context, icon);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 33ca7d6bafd8..a45b131902c8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -58,13 +58,13 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView {
private static final int ICON_MASK_ID = com.android.internal.R.string.config_icon_mask;
protected final Handler mHandler = new H();
private final int[] mLocInScreen = new int[2];
- private final FrameLayout mIconFrame;
+ protected final FrameLayout mIconFrame;
protected QSIconView mIcon;
protected RippleDrawable mRipple;
protected Drawable mTileBackground;
private String mAccessibilityClass;
private boolean mTileState;
- private boolean mCollapsedView;
+ protected boolean mCollapsedView;
protected boolean mShowRippleEffect = true;
private float mStrokeWidthActive;
private float mStrokeWidthInactive;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
index b59326ae56d5..c7ed89ba49b1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileView.java
@@ -26,6 +26,8 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.settingslib.Utils;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
@@ -116,7 +118,8 @@ public class QSTileView extends QSTileBaseView {
}
}
- private boolean shouldLabelBeSingleLine() {
+ protected boolean shouldLabelBeSingleLine() {
+ if (mCollapsedView) return true;
if (mLabel.getLineCount() > mMaxLabelLines) {
return true;
} else if (!TextUtils.isEmpty(mSecondLine.getText())
@@ -138,14 +141,14 @@ public class QSTileView extends QSTileBaseView {
} else {
labelColor = mColorLabelUnavailable;
}
- mLabel.setTextColor(labelColor);
+ changeLabelColor(labelColor);
mState = state.state;
mLabel.setText(state.label);
}
if (!Objects.equals(mSecondLine.getText(), state.secondaryLabel)) {
mSecondLine.setText(state.secondaryLabel);
- mSecondLine.setVisibility(TextUtils.isEmpty(state.secondaryLabel) ? View.GONE
- : View.VISIBLE);
+ mSecondLine.setVisibility(TextUtils.isEmpty(state.secondaryLabel) || mCollapsedView
+ ? View.GONE : View.VISIBLE);
}
boolean dualTarget = mDualTargetAllowed && state.dualTarget;
handleExpand(dualTarget);
@@ -160,6 +163,10 @@ public class QSTileView extends QSTileBaseView {
mPadLock.setVisibility(state.disabledByPolicy ? View.VISIBLE : View.GONE);
}
+ protected void changeLabelColor(ColorStateList color) {
+ mLabel.setTextColor(color);
+ }
+
protected void handleExpand(boolean dualTarget) {
mExpandIndicator.setVisibility(dualTarget ? View.VISIBLE : View.GONE);
mExpandSpace.setVisibility(dualTarget ? View.VISIBLE : View.GONE);
@@ -178,4 +185,10 @@ public class QSTileView extends QSTileBaseView {
public TextView getAppLabel() {
return mSecondLine;
}
+
+ @Nullable
+ @Override
+ public View getLabelContainer() {
+ return mLabelContainer;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
index 328c2c353a29..32285cf797e4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewHorizontal.kt
@@ -21,8 +21,7 @@ import android.content.Context
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.drawable.Drawable
-import android.graphics.drawable.ShapeDrawable
-import android.graphics.drawable.shapes.RoundRectShape
+import android.graphics.drawable.RippleDrawable
import android.service.quicksettings.Tile.STATE_ACTIVE
import android.view.Gravity
import android.widget.LinearLayout
@@ -32,25 +31,31 @@ import com.android.systemui.plugins.qs.QSIconView
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState
-// Placeholder
-private const val CORNER_RADIUS = 40f
-private val RADII = (1..8).map { CORNER_RADIUS }.toFloatArray()
-
open class QSTileViewHorizontal(
context: Context,
- icon: QSIconView
-) : QSTileView(context, icon, false) {
+ icon: QSIconView,
+ collapsed: Boolean
+) : QSTileView(context, icon, collapsed) {
- protected var backgroundDrawable: ShapeDrawable? = null
+ protected var colorBackgroundDrawable: Drawable? = null
private var paintColor = Color.WHITE
private var paintAnimator: ValueAnimator? = null
+ private var labelAnimator: ValueAnimator? = null
init {
orientation = HORIZONTAL
+ gravity = Gravity.CENTER_VERTICAL or Gravity.START
mDualTargetAllowed = false
+ val padding = context.resources.getDimensionPixelSize(R.dimen.qs_tile_side_label_padding)
+ setPadding(padding, paddingTop, padding, paddingBottom)
+
mBg.setImageDrawable(null)
+ mIconFrame.removeAllViews()
+ removeView(mIconFrame)
+ val iconSize = context.resources.getDimensionPixelSize(R.dimen.qs_icon_size)
+ addView(mIcon, 0, LayoutParams(iconSize, iconSize))
+
mColorLabelActive = ColorStateList.valueOf(getColorForState(getContext(), STATE_ACTIVE))
- mMaxLabelLines = 3
}
override fun createLabel() {
@@ -61,65 +66,112 @@ open class QSTileViewHorizontal(
removeRule(RelativeLayout.ALIGN_PARENT_TOP)
}
}
+ mLabelContainer.setPadding(0, 0, 0, 0)
+ (mLabelContainer.layoutParams as MarginLayoutParams).apply {
+ marginStart = context.resources.getDimensionPixelSize(R.dimen.qs_label_container_margin)
+ }
mLabel.gravity = Gravity.START
mLabel.textDirection = TEXT_DIRECTION_LOCALE
mSecondLine.gravity = Gravity.START
mSecondLine.textDirection = TEXT_DIRECTION_LOCALE
- val padding = context.resources.getDimensionPixelSize(R.dimen.qs_tile_side_label_padding)
- mLabelContainer.setPaddingRelative(0, padding, padding, padding)
+
(mLabelContainer.layoutParams as LayoutParams).gravity =
Gravity.CENTER_VERTICAL or Gravity.START
+ if (mCollapsedView) {
+ mSecondLine.visibility = GONE
+ }
+ }
+
+ override fun shouldLabelBeSingleLine(): Boolean {
+ return true
}
override fun updateRippleSize() {
}
override fun newTileBackground(): Drawable? {
- backgroundDrawable = ShapeDrawable(RoundRectShape(RADII, null, null))
- return backgroundDrawable
+ val ripple = mContext.getDrawable(R.drawable.qs_tile_background) as RippleDrawable
+ colorBackgroundDrawable = ripple.findDrawableByLayerId(R.id.background)
+ return ripple
}
override fun setClickable(clickable: Boolean) {
super.setClickable(clickable)
- background = mTileBackground
+ background = if (clickable && mShowRippleEffect) {
+ mTileBackground
+ } else {
+ colorBackgroundDrawable
+ }
}
override fun handleStateChanged(state: QSTile.State) {
super.handleStateChanged(state)
- mSecondLine.setTextColor(mLabel.textColors)
mLabelContainer.background = null
val allowAnimations = animationsEnabled() && paintColor != Color.WHITE
val newColor = getCircleColor(state.state)
if (allowAnimations) {
- animateToNewState(newColor)
+ animateBackground(newColor)
} else {
if (newColor != paintColor) {
- clearAnimator()
- backgroundDrawable?.setTintList(ColorStateList.valueOf(newColor))
+ clearBackgroundAnimator()
+ colorBackgroundDrawable?.setTintList(ColorStateList.valueOf(newColor))?.also {
+ paintColor = newColor
+ }
paintColor = newColor
}
}
}
- private fun animateToNewState(newColor: Int) {
- if (newColor != paintColor) {
- clearAnimator()
- paintAnimator = ValueAnimator.ofArgb(paintColor, newColor)
+ private fun animateBackground(newBackgroundColor: Int) {
+ if (newBackgroundColor != paintColor) {
+ clearBackgroundAnimator()
+ paintAnimator = ValueAnimator.ofArgb(paintColor, newBackgroundColor)
.setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
addUpdateListener { animation: ValueAnimator ->
val c = animation.animatedValue as Int
- backgroundDrawable?.setTintList(ColorStateList.valueOf(c))
- paintColor = c
+ colorBackgroundDrawable?.setTintList(ColorStateList.valueOf(c))?.also {
+ paintColor = c
+ }
}
start()
}
}
}
- private fun clearAnimator() {
+ override fun changeLabelColor(color: ColorStateList) {
+ val allowAnimations = animationsEnabled()
+ val currentColor = mLabel.textColors.defaultColor
+ if (currentColor != color.defaultColor) {
+ clearLabelAnimator()
+ if (allowAnimations) {
+ labelAnimator = ValueAnimator.ofArgb(currentColor, color.defaultColor)
+ .setDuration(QSIconViewImpl.QS_ANIM_LENGTH).apply {
+ addUpdateListener {
+ setLabelsColor(ColorStateList.valueOf(it.animatedValue as Int))
+ }
+ start()
+ }
+ } else {
+ setLabelsColor(color)
+ }
+ }
+ }
+
+ private fun setLabelsColor(color: ColorStateList) {
+ mLabel.setTextColor(color)
+ if (!mCollapsedView) {
+ mSecondLine.setTextColor(color)
+ }
+ }
+
+ private fun clearBackgroundAnimator() {
paintAnimator?.cancel()?.also { paintAnimator = null }
}
+ private fun clearLabelAnimator() {
+ labelAnimator?.cancel()?.also { labelAnimator = null }
+ }
+
override fun handleExpand(dualTarget: Boolean) {}
} \ No newline at end of file