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