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