QS: Make user switcher expand when users don't fit
Also updates the switcher to match the latest redlines. Bug: 16406694 Change-Id: Ibf44ed9ea2ef4e3c467724eb4c79f1df5b3e49f4
This commit is contained in:
@@ -17,6 +17,9 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -14,39 +14,43 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@drawable/qs_detail_background"
|
||||
android:padding="16dp" >
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/button1"
|
||||
style="@style/QSBorderlessButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="88dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:text="@string/quick_settings_done"
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/button2"
|
||||
style="@style/QSBorderlessButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:minWidth="132dp"
|
||||
android:layout_toStartOf="@android:id/button1"
|
||||
android:text="@string/quick_settings_more_settings"
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@android:id/content"
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@android:id/button1" />
|
||||
android:background="@drawable/qs_detail_background"
|
||||
android:paddingBottom="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
</RelativeLayout>
|
||||
<FrameLayout
|
||||
android:id="@android:id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingEnd="16dp"
|
||||
android:gravity="end">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/button2"
|
||||
style="@style/QSBorderlessButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:minWidth="132dp"
|
||||
android:text="@string/quick_settings_more_settings"
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/button1"
|
||||
style="@style/QSBorderlessButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="88dp"
|
||||
android:text="@string/quick_settings_done"
|
||||
android:textAppearance="@style/TextAppearance.QS.DetailButton" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -17,7 +17,10 @@
|
||||
<!-- extends FrameLayout -->
|
||||
<com.android.systemui.qs.QSDetailItems xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" >
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/list"
|
||||
|
||||
@@ -16,14 +16,12 @@
|
||||
~ limitations under the License
|
||||
-->
|
||||
|
||||
<!-- GridView -->
|
||||
<!-- PseudoGridView -->
|
||||
<com.android.systemui.qs.tiles.UserDetailView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:sysui="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:verticalSpacing="4dp"
|
||||
android:horizontalSpacing="4dp"
|
||||
android:numColumns="3"
|
||||
android:listSelector="@drawable/ripple_drawable">
|
||||
|
||||
</com.android.systemui.qs.tiles.UserDetailView>
|
||||
sysui:verticalSpacing="4dp"
|
||||
sysui:horizontalSpacing="4dp"
|
||||
style="@style/UserDetailView" />
|
||||
@@ -25,16 +25,17 @@
|
||||
android:orientation="vertical"
|
||||
android:gravity="top|center_horizontal"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="20dp"
|
||||
android:minHeight="112dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:background="@drawable/ripple_drawable"
|
||||
systemui:activatedFontFamily="sans-serif-medium">
|
||||
|
||||
<com.android.systemui.statusbar.phone.UserAvatarView
|
||||
android:id="@+id/user_picture"
|
||||
android:layout_width="@dimen/max_avatar_size"
|
||||
android:layout_height="@dimen/max_avatar_size"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
systemui:frameWidth="2dp"
|
||||
systemui:framePadding="6dp"
|
||||
systemui:activeFrameColor="@color/current_user_border_color"/>
|
||||
|
||||
@@ -34,4 +34,8 @@
|
||||
<item name="android:layout_height">@dimen/search_panel_scrim_height</item>
|
||||
<item name="android:layout_gravity">bottom</item>
|
||||
</style>
|
||||
|
||||
<style name="UserDetailView">
|
||||
<item name="numColumns">4</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -67,5 +67,10 @@
|
||||
<declare-styleable name="DateView">
|
||||
<attr name="datePattern" format="string" />
|
||||
</declare-styleable>
|
||||
<declare-styleable name="PseudoGridView">
|
||||
<attr name="numColumns" format="integer" />
|
||||
<attr name="verticalSpacing" format="dimension" />
|
||||
<attr name="horizontalSpacing" format="dimension" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
|
||||
|
||||
@@ -289,4 +289,8 @@
|
||||
<item name="android:layout_height">@dimen/search_panel_scrim_height</item>
|
||||
<item name="android:layout_gravity">bottom</item>
|
||||
</style>
|
||||
|
||||
<style name="UserDetailView">
|
||||
<item name="numColumns">3</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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
|
||||
*/
|
||||
|
||||
package com.android.systemui.qs;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.DataSetObserver;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* A view that arranges it's children in a grid with a fixed number of evenly spaced columns.
|
||||
*
|
||||
* {@see android.widget.GridView}
|
||||
*/
|
||||
public class PseudoGridView extends ViewGroup {
|
||||
|
||||
private int mNumColumns = 3;
|
||||
private int mVerticalSpacing;
|
||||
private int mHorizontalSpacing;
|
||||
|
||||
public PseudoGridView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PseudoGridView);
|
||||
|
||||
final int N = a.getIndexCount();
|
||||
for (int i = 0; i < N; i++) {
|
||||
int attr = a.getIndex(i);
|
||||
switch (attr) {
|
||||
case R.styleable.PseudoGridView_numColumns:
|
||||
mNumColumns = a.getInt(attr, 3);
|
||||
break;
|
||||
case R.styleable.PseudoGridView_verticalSpacing:
|
||||
mVerticalSpacing = a.getDimensionPixelSize(attr, 0);
|
||||
break;
|
||||
case R.styleable.PseudoGridView_horizontalSpacing:
|
||||
mHorizontalSpacing = a.getDimensionPixelSize(attr, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
if (widthMode == MeasureSpec.UNSPECIFIED) {
|
||||
throw new UnsupportedOperationException("Needs a maximum width");
|
||||
}
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
|
||||
int childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns;
|
||||
int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
|
||||
int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
int totalHeight = 0;
|
||||
int children = getChildCount();
|
||||
int rows = (children + mNumColumns - 1) / mNumColumns;
|
||||
for (int row = 0; row < rows; row++) {
|
||||
int startOfRow = row * mNumColumns;
|
||||
int endOfRow = Math.min(startOfRow + mNumColumns, children);
|
||||
int maxHeight = 0;
|
||||
for (int i = startOfRow; i < endOfRow; i++) {
|
||||
View child = getChildAt(i);
|
||||
child.measure(childWidthSpec, childHeightSpec);
|
||||
maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
|
||||
}
|
||||
int maxHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
|
||||
for (int i = startOfRow; i < endOfRow; i++) {
|
||||
View child = getChildAt(i);
|
||||
child.measure(childWidthSpec, maxHeightSpec);
|
||||
}
|
||||
totalHeight += maxHeight;
|
||||
if (row > 0) {
|
||||
totalHeight += mVerticalSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
setMeasuredDimension(width, getDefaultSize(totalHeight, heightMeasureSpec));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
int children = getChildCount();
|
||||
int rows = (children + mNumColumns - 1) / mNumColumns;
|
||||
int y = 0;
|
||||
for (int row = 0; row < rows; row++) {
|
||||
int x = 0;
|
||||
int maxHeight = 0;
|
||||
int startOfRow = row * mNumColumns;
|
||||
int endOfRow = Math.min(startOfRow + mNumColumns, children);
|
||||
for (int i = startOfRow; i < endOfRow; i++) {
|
||||
View child = getChildAt(i);
|
||||
int width = child.getMeasuredWidth();
|
||||
int height = child.getMeasuredHeight();
|
||||
child.layout(x, y, x + width, y + height);
|
||||
maxHeight = Math.max(maxHeight, height);
|
||||
x += width + mHorizontalSpacing;
|
||||
}
|
||||
y += maxHeight;
|
||||
if (row > 0) {
|
||||
y += mVerticalSpacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridges between a ViewGroup and a BaseAdapter.
|
||||
* <p>
|
||||
* Usage: {@code ViewGroupAdapterBridge.link(viewGroup, adapter)}
|
||||
* <br />
|
||||
* After this call, the ViewGroup's children will be provided by the adapter.
|
||||
*/
|
||||
public static class ViewGroupAdapterBridge extends DataSetObserver {
|
||||
|
||||
private final WeakReference<ViewGroup> mViewGroup;
|
||||
private final BaseAdapter mAdapter;
|
||||
private boolean mReleased;
|
||||
|
||||
public static void link(ViewGroup viewGroup, BaseAdapter adapter) {
|
||||
new ViewGroupAdapterBridge(viewGroup, adapter);
|
||||
}
|
||||
|
||||
private ViewGroupAdapterBridge(ViewGroup viewGroup, BaseAdapter adapter) {
|
||||
mViewGroup = new WeakReference<>(viewGroup);
|
||||
mAdapter = adapter;
|
||||
mReleased = false;
|
||||
mAdapter.registerDataSetObserver(this);
|
||||
refresh();
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
if (mReleased) {
|
||||
return;
|
||||
}
|
||||
ViewGroup viewGroup = mViewGroup.get();
|
||||
if (viewGroup == null) {
|
||||
release();
|
||||
return;
|
||||
}
|
||||
final int childCount = viewGroup.getChildCount();
|
||||
final int adapterCount = mAdapter.getCount();
|
||||
final int N = Math.max(childCount, adapterCount);
|
||||
for (int i = 0; i < N; i++) {
|
||||
if (i < adapterCount) {
|
||||
View oldView = null;
|
||||
if (i < childCount) {
|
||||
oldView = viewGroup.getChildAt(i);
|
||||
}
|
||||
View newView = mAdapter.getView(i, oldView, viewGroup);
|
||||
if (oldView == null) {
|
||||
// We ran out of existing views. Add it at the end.
|
||||
viewGroup.addView(newView);
|
||||
} else if (oldView != newView) {
|
||||
// We couldn't rebind the view. Replace it.
|
||||
viewGroup.removeViewAt(i);
|
||||
viewGroup.addView(newView, i);
|
||||
}
|
||||
} else {
|
||||
int lastIndex = viewGroup.getChildCount() - 1;
|
||||
viewGroup.removeViewAt(lastIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged() {
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInvalidated() {
|
||||
release();
|
||||
}
|
||||
|
||||
private void release() {
|
||||
if (!mReleased) {
|
||||
mReleased = true;
|
||||
mAdapter.unregisterDataSetObserver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,8 +326,11 @@ public class QSPanel extends ViewGroup {
|
||||
if (mFooter.hasFooter()) {
|
||||
h += mFooter.getView().getHeight();
|
||||
}
|
||||
mDetail.measure(exactly(width), exactly(h));
|
||||
setMeasuredDimension(width, h);
|
||||
mDetail.measure(exactly(width), MeasureSpec.UNSPECIFIED);
|
||||
if (mDetail.getMeasuredHeight() < h) {
|
||||
mDetail.measure(exactly(width), exactly(h));
|
||||
}
|
||||
setMeasuredDimension(width, Math.max(h, mDetail.getMeasuredHeight()));
|
||||
}
|
||||
|
||||
private static int exactly(int size) {
|
||||
|
||||
@@ -17,45 +17,24 @@
|
||||
package com.android.systemui.qs.tiles;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.qs.PseudoGridView;
|
||||
import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.GridView;
|
||||
|
||||
/**
|
||||
* Quick settings detail view for user switching.
|
||||
*/
|
||||
public class UserDetailView extends GridView {
|
||||
public class UserDetailView extends PseudoGridView {
|
||||
|
||||
public UserDetailView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
private Adapter mAdapter;
|
||||
|
||||
public UserDetailView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, android.R.attr.gridViewStyle);
|
||||
}
|
||||
|
||||
public UserDetailView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public UserDetailView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
|
||||
setOnItemClickListener(new OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
UserSwitcherController.UserRecord tag =
|
||||
(UserSwitcherController.UserRecord) view.getTag();
|
||||
((Adapter)getAdapter()).switchTo(tag);
|
||||
}
|
||||
});
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public static UserDetailView inflate(Context context, ViewGroup parent, boolean attach) {
|
||||
@@ -64,10 +43,12 @@ public class UserDetailView extends GridView {
|
||||
}
|
||||
|
||||
public void createAndSetAdapter(UserSwitcherController controller) {
|
||||
setAdapter(new Adapter(mContext, controller));
|
||||
mAdapter = new Adapter(mContext, controller);
|
||||
ViewGroupAdapterBridge.link(this, mAdapter);
|
||||
}
|
||||
|
||||
public static class Adapter extends UserSwitcherController.BaseUserAdapter {
|
||||
public static class Adapter extends UserSwitcherController.BaseUserAdapter
|
||||
implements OnClickListener {
|
||||
|
||||
private Context mContext;
|
||||
|
||||
@@ -81,6 +62,9 @@ public class UserDetailView extends GridView {
|
||||
UserSwitcherController.UserRecord item = getItem(position);
|
||||
UserDetailItemView v = UserDetailItemView.convertOrInflate(
|
||||
mContext, convertView, parent);
|
||||
if (v != convertView) {
|
||||
v.setOnClickListener(this);
|
||||
}
|
||||
String name = getName(mContext, item);
|
||||
if (item.picture == null) {
|
||||
v.bind(name, getDrawable(mContext, item));
|
||||
@@ -91,5 +75,12 @@ public class UserDetailView extends GridView {
|
||||
v.setTag(item);
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
UserSwitcherController.UserRecord tag =
|
||||
(UserSwitcherController.UserRecord) view.getTag();
|
||||
switchTo(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,12 +465,12 @@ public class UserSwitcherController {
|
||||
|
||||
@Override
|
||||
public View createDetailView(Context context, View convertView, ViewGroup parent) {
|
||||
UserDetailView v;
|
||||
if (!(convertView instanceof UserDetailView)) {
|
||||
convertView = UserDetailView.inflate(context, parent, false);
|
||||
}
|
||||
UserDetailView v = (UserDetailView) convertView;
|
||||
if (v.getAdapter() == null) {
|
||||
v = UserDetailView.inflate(context, parent, false);
|
||||
v.createAndSetAdapter(UserSwitcherController.this);
|
||||
} else {
|
||||
v = (UserDetailView) convertView;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user