Skip to content

Commit 1940892

Browse files
committed
QS: Make user switcher expand when users don't fit
Also updates the switcher to match the latest redlines. Bug: 16406694 Change-Id: Ibf44ed9ea2ef4e3c467724eb4c79f1df5b3e49f4
1 parent dd06d04 commit 1940892

12 files changed

Lines changed: 296 additions & 76 deletions

File tree

packages/SystemUI/res/layout/data_usage.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
1818
android:layout_width="match_parent"
1919
android:layout_height="wrap_content"
20+
android:paddingTop="16dp"
21+
android:paddingStart="16dp"
22+
android:paddingEnd="16dp"
2023
android:orientation="vertical" >
2124

2225
<TextView

packages/SystemUI/res/layout/qs_detail.xml

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,43 @@
1414
See the License for the specific language governing permissions and
1515
limitations under the License.
1616
-->
17-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
18-
android:layout_width="match_parent"
19-
android:layout_height="match_parent"
20-
android:background="@drawable/qs_detail_background"
21-
android:padding="16dp" >
22-
23-
<TextView
24-
android:id="@android:id/button1"
25-
style="@style/QSBorderlessButton"
26-
android:layout_width="wrap_content"
27-
android:layout_height="wrap_content"
28-
android:minWidth="88dp"
29-
android:layout_alignParentBottom="true"
30-
android:layout_alignParentEnd="true"
31-
android:text="@string/quick_settings_done"
32-
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
33-
34-
<TextView
35-
android:id="@android:id/button2"
36-
style="@style/QSBorderlessButton"
37-
android:layout_width="wrap_content"
38-
android:layout_height="wrap_content"
39-
android:layout_alignParentBottom="true"
40-
android:layout_marginEnd="8dp"
41-
android:minWidth="132dp"
42-
android:layout_toStartOf="@android:id/button1"
43-
android:text="@string/quick_settings_more_settings"
44-
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
45-
46-
<FrameLayout
47-
android:id="@android:id/content"
17+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
4818
android:layout_width="match_parent"
4919
android:layout_height="match_parent"
50-
android:layout_above="@android:id/button1" />
20+
android:background="@drawable/qs_detail_background"
21+
android:paddingBottom="16dp"
22+
android:orientation="vertical">
23+
24+
<FrameLayout
25+
android:id="@android:id/content"
26+
android:layout_width="match_parent"
27+
android:layout_height="0dp"
28+
android:layout_weight="1" />
29+
30+
<LinearLayout
31+
android:layout_width="match_parent"
32+
android:layout_height="wrap_content"
33+
android:paddingEnd="16dp"
34+
android:gravity="end">
35+
36+
<TextView
37+
android:id="@android:id/button2"
38+
style="@style/QSBorderlessButton"
39+
android:layout_width="wrap_content"
40+
android:layout_height="wrap_content"
41+
android:layout_marginEnd="8dp"
42+
android:minWidth="132dp"
43+
android:text="@string/quick_settings_more_settings"
44+
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
45+
46+
<TextView
47+
android:id="@android:id/button1"
48+
style="@style/QSBorderlessButton"
49+
android:layout_width="wrap_content"
50+
android:layout_height="wrap_content"
51+
android:minWidth="88dp"
52+
android:text="@string/quick_settings_done"
53+
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
5154

52-
</RelativeLayout>
55+
</LinearLayout>
56+
</LinearLayout>

packages/SystemUI/res/layout/qs_detail_items.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
<!-- extends FrameLayout -->
1818
<com.android.systemui.qs.QSDetailItems xmlns:android="http://schemas.android.com/apk/res/android"
1919
android:layout_width="match_parent"
20-
android:layout_height="match_parent" >
20+
android:layout_height="match_parent"
21+
android:paddingTop="16dp"
22+
android:paddingStart="16dp"
23+
android:paddingEnd="16dp">
2124

2225
<LinearLayout
2326
android:id="@android:id/list"

packages/SystemUI/res/layout/qs_user_detail.xml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@
1616
~ limitations under the License
1717
-->
1818

19-
<!-- GridView -->
19+
<!-- PseudoGridView -->
2020
<com.android.systemui.qs.tiles.UserDetailView
2121
xmlns:android="http://schemas.android.com/apk/res/android"
22+
xmlns:sysui="http://schemas.android.com/apk/res-auto"
2223
android:layout_width="match_parent"
2324
android:layout_height="match_parent"
24-
android:verticalSpacing="4dp"
25-
android:horizontalSpacing="4dp"
26-
android:numColumns="3"
27-
android:listSelector="@drawable/ripple_drawable">
28-
29-
</com.android.systemui.qs.tiles.UserDetailView>
25+
sysui:verticalSpacing="4dp"
26+
sysui:horizontalSpacing="4dp"
27+
style="@style/UserDetailView" />

packages/SystemUI/res/layout/qs_user_detail_item.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,17 @@
2525
android:orientation="vertical"
2626
android:gravity="top|center_horizontal"
2727
android:paddingTop="16dp"
28-
android:paddingBottom="20dp"
28+
android:minHeight="112dp"
2929
android:clipChildren="false"
3030
android:clipToPadding="false"
31+
android:background="@drawable/ripple_drawable"
3132
systemui:activatedFontFamily="sans-serif-medium">
3233

3334
<com.android.systemui.statusbar.phone.UserAvatarView
3435
android:id="@+id/user_picture"
3536
android:layout_width="@dimen/max_avatar_size"
3637
android:layout_height="@dimen/max_avatar_size"
37-
android:layout_marginBottom="12dp"
38+
android:layout_marginBottom="10dp"
3839
systemui:frameWidth="2dp"
3940
systemui:framePadding="6dp"
4041
systemui:activeFrameColor="@color/current_user_border_color"/>

packages/SystemUI/res/values-sw600dp/styles.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,8 @@
3434
<item name="android:layout_height">@dimen/search_panel_scrim_height</item>
3535
<item name="android:layout_gravity">bottom</item>
3636
</style>
37+
38+
<style name="UserDetailView">
39+
<item name="numColumns">4</item>
40+
</style>
3741
</resources>

packages/SystemUI/res/values/attrs.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,5 +67,10 @@
6767
<declare-styleable name="DateView">
6868
<attr name="datePattern" format="string" />
6969
</declare-styleable>
70+
<declare-styleable name="PseudoGridView">
71+
<attr name="numColumns" format="integer" />
72+
<attr name="verticalSpacing" format="dimension" />
73+
<attr name="horizontalSpacing" format="dimension" />
74+
</declare-styleable>
7075
</resources>
7176

packages/SystemUI/res/values/styles.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,4 +289,8 @@
289289
<item name="android:layout_height">@dimen/search_panel_scrim_height</item>
290290
<item name="android:layout_gravity">bottom</item>
291291
</style>
292+
293+
<style name="UserDetailView">
294+
<item name="numColumns">3</item>
295+
</style>
292296
</resources>
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright (C) 2014 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License
15+
*/
16+
17+
package com.android.systemui.qs;
18+
19+
import com.android.systemui.R;
20+
21+
import android.content.Context;
22+
import android.content.res.TypedArray;
23+
import android.database.DataSetObserver;
24+
import android.util.AttributeSet;
25+
import android.view.View;
26+
import android.view.ViewGroup;
27+
import android.widget.BaseAdapter;
28+
29+
import java.lang.ref.WeakReference;
30+
31+
/**
32+
* A view that arranges it's children in a grid with a fixed number of evenly spaced columns.
33+
*
34+
* {@see android.widget.GridView}
35+
*/
36+
public class PseudoGridView extends ViewGroup {
37+
38+
private int mNumColumns = 3;
39+
private int mVerticalSpacing;
40+
private int mHorizontalSpacing;
41+
42+
public PseudoGridView(Context context, AttributeSet attrs) {
43+
super(context, attrs);
44+
45+
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PseudoGridView);
46+
47+
final int N = a.getIndexCount();
48+
for (int i = 0; i < N; i++) {
49+
int attr = a.getIndex(i);
50+
switch (attr) {
51+
case R.styleable.PseudoGridView_numColumns:
52+
mNumColumns = a.getInt(attr, 3);
53+
break;
54+
case R.styleable.PseudoGridView_verticalSpacing:
55+
mVerticalSpacing = a.getDimensionPixelSize(attr, 0);
56+
break;
57+
case R.styleable.PseudoGridView_horizontalSpacing:
58+
mHorizontalSpacing = a.getDimensionPixelSize(attr, 0);
59+
break;
60+
}
61+
}
62+
63+
a.recycle();
64+
}
65+
66+
@Override
67+
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
68+
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
69+
if (widthMode == MeasureSpec.UNSPECIFIED) {
70+
throw new UnsupportedOperationException("Needs a maximum width");
71+
}
72+
int width = MeasureSpec.getSize(widthMeasureSpec);
73+
74+
int childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns;
75+
int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
76+
int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
77+
int totalHeight = 0;
78+
int children = getChildCount();
79+
int rows = (children + mNumColumns - 1) / mNumColumns;
80+
for (int row = 0; row < rows; row++) {
81+
int startOfRow = row * mNumColumns;
82+
int endOfRow = Math.min(startOfRow + mNumColumns, children);
83+
int maxHeight = 0;
84+
for (int i = startOfRow; i < endOfRow; i++) {
85+
View child = getChildAt(i);
86+
child.measure(childWidthSpec, childHeightSpec);
87+
maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
88+
}
89+
int maxHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
90+
for (int i = startOfRow; i < endOfRow; i++) {
91+
View child = getChildAt(i);
92+
child.measure(childWidthSpec, maxHeightSpec);
93+
}
94+
totalHeight += maxHeight;
95+
if (row > 0) {
96+
totalHeight += mVerticalSpacing;
97+
}
98+
}
99+
100+
setMeasuredDimension(width, getDefaultSize(totalHeight, heightMeasureSpec));
101+
}
102+
103+
@Override
104+
protected void onLayout(boolean changed, int l, int t, int r, int b) {
105+
int children = getChildCount();
106+
int rows = (children + mNumColumns - 1) / mNumColumns;
107+
int y = 0;
108+
for (int row = 0; row < rows; row++) {
109+
int x = 0;
110+
int maxHeight = 0;
111+
int startOfRow = row * mNumColumns;
112+
int endOfRow = Math.min(startOfRow + mNumColumns, children);
113+
for (int i = startOfRow; i < endOfRow; i++) {
114+
View child = getChildAt(i);
115+
int width = child.getMeasuredWidth();
116+
int height = child.getMeasuredHeight();
117+
child.layout(x, y, x + width, y + height);
118+
maxHeight = Math.max(maxHeight, height);
119+
x += width + mHorizontalSpacing;
120+
}
121+
y += maxHeight;
122+
if (row > 0) {
123+
y += mVerticalSpacing;
124+
}
125+
}
126+
}
127+
128+
/**
129+
* Bridges between a ViewGroup and a BaseAdapter.
130+
* <p>
131+
* Usage: {@code ViewGroupAdapterBridge.link(viewGroup, adapter)}
132+
* <br />
133+
* After this call, the ViewGroup's children will be provided by the adapter.
134+
*/
135+
public static class ViewGroupAdapterBridge extends DataSetObserver {
136+
137+
private final WeakReference<ViewGroup> mViewGroup;
138+
private final BaseAdapter mAdapter;
139+
private boolean mReleased;
140+
141+
public static void link(ViewGroup viewGroup, BaseAdapter adapter) {
142+
new ViewGroupAdapterBridge(viewGroup, adapter);
143+
}
144+
145+
private ViewGroupAdapterBridge(ViewGroup viewGroup, BaseAdapter adapter) {
146+
mViewGroup = new WeakReference<>(viewGroup);
147+
mAdapter = adapter;
148+
mReleased = false;
149+
mAdapter.registerDataSetObserver(this);
150+
refresh();
151+
}
152+
153+
private void refresh() {
154+
if (mReleased) {
155+
return;
156+
}
157+
ViewGroup viewGroup = mViewGroup.get();
158+
if (viewGroup == null) {
159+
release();
160+
return;
161+
}
162+
final int childCount = viewGroup.getChildCount();
163+
final int adapterCount = mAdapter.getCount();
164+
final int N = Math.max(childCount, adapterCount);
165+
for (int i = 0; i < N; i++) {
166+
if (i < adapterCount) {
167+
View oldView = null;
168+
if (i < childCount) {
169+
oldView = viewGroup.getChildAt(i);
170+
}
171+
View newView = mAdapter.getView(i, oldView, viewGroup);
172+
if (oldView == null) {
173+
// We ran out of existing views. Add it at the end.
174+
viewGroup.addView(newView);
175+
} else if (oldView != newView) {
176+
// We couldn't rebind the view. Replace it.
177+
viewGroup.removeViewAt(i);
178+
viewGroup.addView(newView, i);
179+
}
180+
} else {
181+
int lastIndex = viewGroup.getChildCount() - 1;
182+
viewGroup.removeViewAt(lastIndex);
183+
}
184+
}
185+
}
186+
187+
@Override
188+
public void onChanged() {
189+
refresh();
190+
}
191+
192+
@Override
193+
public void onInvalidated() {
194+
release();
195+
}
196+
197+
private void release() {
198+
if (!mReleased) {
199+
mReleased = true;
200+
mAdapter.unregisterDataSetObserver(this);
201+
}
202+
}
203+
}
204+
}

packages/SystemUI/src/com/android/systemui/qs/QSPanel.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,11 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
326326
if (mFooter.hasFooter()) {
327327
h += mFooter.getView().getHeight();
328328
}
329-
mDetail.measure(exactly(width), exactly(h));
330-
setMeasuredDimension(width, h);
329+
mDetail.measure(exactly(width), MeasureSpec.UNSPECIFIED);
330+
if (mDetail.getMeasuredHeight() < h) {
331+
mDetail.measure(exactly(width), exactly(h));
332+
}
333+
setMeasuredDimension(width, Math.max(h, mDetail.getMeasuredHeight()));
331334
}
332335

333336
private static int exactly(int size) {

0 commit comments

Comments
 (0)