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