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 android.content.Context;
20 import android.content.res.Configuration;
21 import android.graphics.drawable.Drawable;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.Message;
25 import android.text.TextUtils;
26 import android.util.AttributeSet;
27 import android.util.Log;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 import android.view.ViewGroup;
31 import android.widget.FrameLayout;
32 import android.widget.ImageView;
33 import android.widget.LinearLayout;
34 import android.widget.TextView;
35 
36 import com.android.systemui.FontSizeUtils;
37 import com.android.systemui.R;
38 
39 /**
40  * Quick settings common detail view with line items.
41  */
42 public class QSDetailItems extends FrameLayout {
43     private static final String TAG = "QSDetailItems";
44     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
45 
46     private final Context mContext;
47     private final H mHandler = new H();
48 
49     private String mTag;
50     private Callback mCallback;
51     private boolean mItemsVisible = true;
52     private LinearLayout mItems;
53     private View mEmpty;
54     private View mMinHeightSpacer;
55     private TextView mEmptyText;
56     private ImageView mEmptyIcon;
57     private int mMaxItems;
58 
QSDetailItems(Context context, AttributeSet attrs)59     public QSDetailItems(Context context, AttributeSet attrs) {
60         super(context, attrs);
61         mContext = context;
62         mTag = TAG;
63     }
64 
convertOrInflate(Context context, View convert, ViewGroup parent)65     public static QSDetailItems convertOrInflate(Context context, View convert, ViewGroup parent) {
66         if (convert instanceof QSDetailItems) {
67             return (QSDetailItems) convert;
68         }
69         return (QSDetailItems) LayoutInflater.from(context).inflate(R.layout.qs_detail_items,
70                 parent, false);
71     }
72 
73     @Override
onFinishInflate()74     protected void onFinishInflate() {
75         super.onFinishInflate();
76         mItems = (LinearLayout) findViewById(android.R.id.list);
77         mItems.setVisibility(GONE);
78         mEmpty = findViewById(android.R.id.empty);
79         mEmpty.setVisibility(GONE);
80         mEmptyText = (TextView) mEmpty.findViewById(android.R.id.title);
81         mEmptyIcon = (ImageView) mEmpty.findViewById(android.R.id.icon);
82         mMinHeightSpacer = findViewById(R.id.min_height_spacer);
83 
84         // By default, a detail item view has fixed size.
85         mMaxItems = getResources().getInteger(
86                 R.integer.quick_settings_detail_max_item_count);
87         setMinHeightInItems(mMaxItems);
88     }
89 
90     @Override
onConfigurationChanged(Configuration newConfig)91     protected void onConfigurationChanged(Configuration newConfig) {
92         super.onConfigurationChanged(newConfig);
93         FontSizeUtils.updateFontSize(mEmptyText, R.dimen.qs_detail_empty_text_size);
94         int count = mItems.getChildCount();
95         for (int i = 0; i < count; i++) {
96             View item = mItems.getChildAt(i);
97             FontSizeUtils.updateFontSize(item, android.R.id.title,
98                     R.dimen.qs_detail_item_primary_text_size);
99             FontSizeUtils.updateFontSize(item, android.R.id.summary,
100                     R.dimen.qs_detail_item_secondary_text_size);
101         }
102     }
103 
setTagSuffix(String suffix)104     public void setTagSuffix(String suffix) {
105         mTag = TAG + "." + suffix;
106     }
107 
setEmptyState(int icon, int text)108     public void setEmptyState(int icon, int text) {
109         mEmptyIcon.setImageResource(icon);
110         mEmptyText.setText(text);
111     }
112 
113     /**
114      * Set the minimum height of this detail view, in item count.
115      */
setMinHeightInItems(int minHeightInItems)116     public void setMinHeightInItems(int minHeightInItems) {
117         ViewGroup.LayoutParams lp = mMinHeightSpacer.getLayoutParams();
118         lp.height = minHeightInItems * getResources().getDimensionPixelSize(
119                 R.dimen.qs_detail_item_height);
120         mMinHeightSpacer.setLayoutParams(lp);
121     }
122 
123     @Override
onAttachedToWindow()124     protected void onAttachedToWindow() {
125         super.onAttachedToWindow();
126         if (DEBUG) Log.d(mTag, "onAttachedToWindow");
127     }
128 
129     @Override
onDetachedFromWindow()130     protected void onDetachedFromWindow() {
131         super.onDetachedFromWindow();
132         if (DEBUG) Log.d(mTag, "onDetachedFromWindow");
133         mCallback = null;
134     }
135 
setCallback(Callback callback)136     public void setCallback(Callback callback) {
137         mHandler.removeMessages(H.SET_CALLBACK);
138         mHandler.obtainMessage(H.SET_CALLBACK, callback).sendToTarget();
139     }
140 
setItems(Item[] items)141     public void setItems(Item[] items) {
142         mHandler.removeMessages(H.SET_ITEMS);
143         mHandler.obtainMessage(H.SET_ITEMS, items).sendToTarget();
144     }
145 
setItemsVisible(boolean visible)146     public void setItemsVisible(boolean visible) {
147         mHandler.removeMessages(H.SET_ITEMS_VISIBLE);
148         mHandler.obtainMessage(H.SET_ITEMS_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
149     }
150 
handleSetCallback(Callback callback)151     private void handleSetCallback(Callback callback) {
152         mCallback = callback;
153     }
154 
handleSetItems(Item[] items)155     private void handleSetItems(Item[] items) {
156         final int itemCount = items != null ? Math.min(items.length, mMaxItems) : 0;
157         mEmpty.setVisibility(itemCount == 0 ? VISIBLE : GONE);
158         mItems.setVisibility(itemCount == 0 ? GONE : VISIBLE);
159         for (int i = mItems.getChildCount() - 1; i >= itemCount; i--) {
160             mItems.removeViewAt(i);
161         }
162         for (int i = 0; i < itemCount; i++) {
163             bind(items[i], mItems.getChildAt(i));
164         }
165     }
166 
handleSetItemsVisible(boolean visible)167     private void handleSetItemsVisible(boolean visible) {
168         if (mItemsVisible == visible) return;
169         mItemsVisible = visible;
170         for (int i = 0; i < mItems.getChildCount(); i++) {
171             mItems.getChildAt(i).setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
172         }
173     }
174 
bind(final Item item, View view)175     private void bind(final Item item, View view) {
176         if (view == null) {
177             view = LayoutInflater.from(mContext).inflate(R.layout.qs_detail_item, this, false);
178             mItems.addView(view);
179         }
180         view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
181         final ImageView iv = (ImageView) view.findViewById(android.R.id.icon);
182         iv.setImageResource(item.icon);
183         iv.getOverlay().clear();
184         if (item.overlay != null) {
185             item.overlay.setBounds(0, 0, item.overlay.getIntrinsicWidth(),
186                     item.overlay.getIntrinsicHeight());
187             iv.getOverlay().add(item.overlay);
188         }
189         final TextView title = (TextView) view.findViewById(android.R.id.title);
190         title.setText(item.line1);
191         final TextView summary = (TextView) view.findViewById(android.R.id.summary);
192         final boolean twoLines = !TextUtils.isEmpty(item.line2);
193         title.setMaxLines(twoLines ? 1 : 2);
194         summary.setVisibility(twoLines ? VISIBLE : GONE);
195         summary.setText(twoLines ? item.line2 : null);
196         view.setOnClickListener(new OnClickListener() {
197             @Override
198             public void onClick(View v) {
199                 if (mCallback != null) {
200                     mCallback.onDetailItemClick(item);
201                 }
202             }
203         });
204         final ImageView disconnect = (ImageView) view.findViewById(android.R.id.icon2);
205         disconnect.setVisibility(item.canDisconnect ? VISIBLE : GONE);
206         disconnect.setOnClickListener(new OnClickListener() {
207             @Override
208             public void onClick(View v) {
209                 if (mCallback != null) {
210                     mCallback.onDetailItemDisconnect(item);
211                 }
212             }
213         });
214     }
215 
216     private class H extends Handler {
217         private static final int SET_ITEMS = 1;
218         private static final int SET_CALLBACK = 2;
219         private static final int SET_ITEMS_VISIBLE = 3;
220 
H()221         public H() {
222             super(Looper.getMainLooper());
223         }
224 
225         @Override
handleMessage(Message msg)226         public void handleMessage(Message msg) {
227             if (msg.what == SET_ITEMS) {
228                 handleSetItems((Item[]) msg.obj);
229             } else if (msg.what == SET_CALLBACK) {
230                 handleSetCallback((QSDetailItems.Callback) msg.obj);
231             } else if (msg.what == SET_ITEMS_VISIBLE) {
232                 handleSetItemsVisible(msg.arg1 != 0);
233             }
234         }
235     }
236 
237     public static class Item {
238         public int icon;
239         public Drawable overlay;
240         public CharSequence line1;
241         public CharSequence line2;
242         public Object tag;
243         public boolean canDisconnect;
244     }
245 
246     public interface Callback {
onDetailItemClick(Item item)247         void onDetailItemClick(Item item);
onDetailItemDisconnect(Item item)248         void onDetailItemDisconnect(Item item);
249     }
250 }
251