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