blob: a3d7bccae8918f1e25f86c1bdd9b21adfe456cd5 [file] [log] [blame]
John Spurlockaf8d6c42014-05-07 17:49:08 -04001/*
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
17package com.android.systemui.qs.tiles;
18
John Spurlock1e6eb172014-07-13 11:59:50 -040019import android.content.Context;
John Spurlockaf8d6c42014-05-07 17:49:08 -040020import android.content.Intent;
John Spurlockaf8d6c42014-05-07 17:49:08 -040021import android.provider.Settings;
John Spurlock1e6eb172014-07-13 11:59:50 -040022import android.util.Log;
John Spurlockaf8d6c42014-05-07 17:49:08 -040023import android.view.View;
John Spurlock1e6eb172014-07-13 11:59:50 -040024import android.view.View.OnAttachStateChangeListener;
25import android.view.ViewGroup;
John Spurlockaf8d6c42014-05-07 17:49:08 -040026
Chris Wren457a21c2015-05-06 17:50:34 -040027import com.android.internal.logging.MetricsLogger;
John Spurlockaf8d6c42014-05-07 17:49:08 -040028import com.android.systemui.R;
John Spurlock1e6eb172014-07-13 11:59:50 -040029import com.android.systemui.qs.QSDetailItems;
30import com.android.systemui.qs.QSDetailItems.Item;
John Spurlockaf8d6c42014-05-07 17:49:08 -040031import com.android.systemui.qs.QSTile;
32import com.android.systemui.statusbar.policy.CastController;
John Spurlock1e6eb172014-07-13 11:59:50 -040033import com.android.systemui.statusbar.policy.CastController.CastDevice;
John Spurlock657c62c2014-07-22 12:18:09 -040034import com.android.systemui.statusbar.policy.KeyguardMonitor;
John Spurlock1e6eb172014-07-13 11:59:50 -040035
36import java.util.LinkedHashMap;
37import java.util.Set;
John Spurlockaf8d6c42014-05-07 17:49:08 -040038
39/** Quick settings tile: Cast **/
40public class CastTile extends QSTile<QSTile.BooleanState> {
Jeff Brown18492622014-08-19 17:51:47 -070041 private static final Intent CAST_SETTINGS =
42 new Intent(Settings.ACTION_CAST_SETTINGS);
John Spurlockaf8d6c42014-05-07 17:49:08 -040043
44 private final CastController mController;
John Spurlock1e6eb172014-07-13 11:59:50 -040045 private final CastDetailAdapter mDetailAdapter;
John Spurlock657c62c2014-07-22 12:18:09 -040046 private final KeyguardMonitor mKeyguard;
47 private final Callback mCallback = new Callback();
John Spurlockaf8d6c42014-05-07 17:49:08 -040048
John Spurlockaf8d6c42014-05-07 17:49:08 -040049 public CastTile(Host host) {
50 super(host);
51 mController = host.getCastController();
John Spurlock1e6eb172014-07-13 11:59:50 -040052 mDetailAdapter = new CastDetailAdapter();
John Spurlock657c62c2014-07-22 12:18:09 -040053 mKeyguard = host.getKeyguardMonitor();
John Spurlock1e6eb172014-07-13 11:59:50 -040054 }
55
56 @Override
57 public DetailAdapter getDetailAdapter() {
58 return mDetailAdapter;
John Spurlockaf8d6c42014-05-07 17:49:08 -040059 }
60
61 @Override
62 protected BooleanState newTileState() {
63 return new BooleanState();
64 }
65
66 @Override
John Spurlockccb6b9a2014-05-17 15:54:40 -040067 public void setListening(boolean listening) {
John Spurlockaf8d6c42014-05-07 17:49:08 -040068 if (mController == null) return;
John Spurlock1e6eb172014-07-13 11:59:50 -040069 if (DEBUG) Log.d(TAG, "setListening " + listening);
John Spurlockccb6b9a2014-05-17 15:54:40 -040070 if (listening) {
71 mController.addCallback(mCallback);
John Spurlock657c62c2014-07-22 12:18:09 -040072 mKeyguard.addCallback(mCallback);
John Spurlockccb6b9a2014-05-17 15:54:40 -040073 } else {
John Spurlock1e6eb172014-07-13 11:59:50 -040074 mController.setDiscovering(false);
John Spurlockccb6b9a2014-05-17 15:54:40 -040075 mController.removeCallback(mCallback);
John Spurlock657c62c2014-07-22 12:18:09 -040076 mKeyguard.removeCallback(mCallback);
John Spurlockccb6b9a2014-05-17 15:54:40 -040077 }
John Spurlockaf8d6c42014-05-07 17:49:08 -040078 }
79
80 @Override
81 protected void handleUserSwitch(int newUserId) {
82 super.handleUserSwitch(newUserId);
83 if (mController == null) return;
84 mController.setCurrentUserId(newUserId);
85 }
86
87 @Override
John Spurlockaf8d6c42014-05-07 17:49:08 -040088 protected void handleClick() {
Chris Wren457a21c2015-05-06 17:50:34 -040089 super.handleClick();
John Spurlock1e6eb172014-07-13 11:59:50 -040090 showDetail(true);
John Spurlockaf8d6c42014-05-07 17:49:08 -040091 }
92
93 @Override
94 protected void handleUpdateState(BooleanState state, Object arg) {
John Spurlock657c62c2014-07-22 12:18:09 -040095 state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
John Spurlock1e6eb172014-07-13 11:59:50 -040096 state.label = mContext.getString(R.string.quick_settings_cast_title);
97 state.value = false;
Selim Cinek06d3bca2014-08-26 17:29:20 +020098 state.autoMirrorDrawable = false;
John Spurlock1e6eb172014-07-13 11:59:50 -040099 final Set<CastDevice> devices = mController.getCastDevices();
100 boolean connecting = false;
101 for (CastDevice device : devices) {
102 if (device.state == CastDevice.STATE_CONNECTED) {
103 state.value = true;
104 state.label = getDeviceName(device);
105 } else if (device.state == CastDevice.STATE_CONNECTING) {
106 connecting = true;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400107 }
108 }
John Spurlock1e6eb172014-07-13 11:59:50 -0400109 if (!state.value && connecting) {
110 state.label = mContext.getString(R.string.quick_settings_connecting);
111 }
John Spurlock2d695812014-10-30 13:25:21 -0400112 state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
113 : R.drawable.ic_qs_cast_off);
John Spurlock1e6eb172014-07-13 11:59:50 -0400114 mDetailAdapter.updateItems(devices);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400115 }
116
Selim Cinek4fda7b22014-08-18 22:07:25 +0200117 @Override
Chris Wren457a21c2015-05-06 17:50:34 -0400118 public int getMetricsCategory() {
119 return MetricsLogger.QS_CAST;
120 }
121
122 @Override
Selim Cinek4fda7b22014-08-18 22:07:25 +0200123 protected String composeChangeAnnouncement() {
124 if (!mState.value) {
125 // We only announce when it's turned off to avoid vocal overflow.
126 return mContext.getString(R.string.accessibility_casting_turned_off);
127 }
128 return null;
129 }
130
John Spurlock1e6eb172014-07-13 11:59:50 -0400131 private String getDeviceName(CastDevice device) {
132 return device.name != null ? device.name
133 : mContext.getString(R.string.quick_settings_cast_device_default_name);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400134 }
135
John Spurlock657c62c2014-07-22 12:18:09 -0400136 private final class Callback implements CastController.Callback, KeyguardMonitor.Callback {
John Spurlockaf8d6c42014-05-07 17:49:08 -0400137 @Override
John Spurlock1e6eb172014-07-13 11:59:50 -0400138 public void onCastDevicesChanged() {
139 refreshState();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400140 }
John Spurlock657c62c2014-07-22 12:18:09 -0400141
142 @Override
143 public void onKeyguardChanged() {
144 refreshState();
145 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400146 };
John Spurlock76c43b92014-05-13 21:10:51 -0400147
John Spurlock1e6eb172014-07-13 11:59:50 -0400148 private final class CastDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
149 private final LinkedHashMap<String, CastDevice> mVisibleOrder = new LinkedHashMap<>();
150
151 private QSDetailItems mItems;
152
John Spurlock76c43b92014-05-13 21:10:51 -0400153 @Override
John Spurlock1e6eb172014-07-13 11:59:50 -0400154 public int getTitle() {
155 return R.string.quick_settings_cast_title;
John Spurlock76c43b92014-05-13 21:10:51 -0400156 }
John Spurlock1e6eb172014-07-13 11:59:50 -0400157
158 @Override
159 public Boolean getToggleState() {
160 return null;
161 }
162
163 @Override
164 public Intent getSettingsIntent() {
Jeff Brown18492622014-08-19 17:51:47 -0700165 return CAST_SETTINGS;
John Spurlock1e6eb172014-07-13 11:59:50 -0400166 }
167
168 @Override
169 public void setToggleState(boolean state) {
170 // noop
171 }
172
173 @Override
Chris Wren457a21c2015-05-06 17:50:34 -0400174 public int getMetricsCategory() {
175 return MetricsLogger.QS_CAST_DETAILS;
176 }
177
178 @Override
John Spurlock1e6eb172014-07-13 11:59:50 -0400179 public View createDetailView(Context context, View convertView, ViewGroup parent) {
180 mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
181 mItems.setTagSuffix("Cast");
182 if (convertView == null) {
183 if (DEBUG) Log.d(TAG, "addOnAttachStateChangeListener");
184 mItems.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
185 @Override
186 public void onViewAttachedToWindow(View v) {
187 if (DEBUG) Log.d(TAG, "onViewAttachedToWindow");
188 }
189
190 @Override
191 public void onViewDetachedFromWindow(View v) {
192 if (DEBUG) Log.d(TAG, "onViewDetachedFromWindow");
193 mVisibleOrder.clear();
194 }
195 });
196 }
197 mItems.setEmptyState(R.drawable.ic_qs_cast_detail_empty,
198 R.string.quick_settings_cast_detail_empty_text);
199 mItems.setCallback(this);
200 updateItems(mController.getCastDevices());
201 mController.setDiscovering(true);
202 return mItems;
203 }
204
205 private void updateItems(Set<CastDevice> devices) {
206 if (mItems == null) return;
207 Item[] items = null;
208 if (devices != null && !devices.isEmpty()) {
209 // if we are connected, simply show that device
210 for (CastDevice device : devices) {
211 if (device.state == CastDevice.STATE_CONNECTED) {
212 final Item item = new Item();
213 item.icon = R.drawable.ic_qs_cast_on;
214 item.line1 = getDeviceName(device);
215 item.line2 = mContext.getString(R.string.quick_settings_connected);
216 item.tag = device;
217 item.canDisconnect = true;
218 items = new Item[] { item };
219 break;
220 }
221 }
222 // otherwise list all available devices, and don't move them around
223 if (items == null) {
224 for (CastDevice device : devices) {
225 mVisibleOrder.put(device.id, device);
226 }
227 items = new Item[devices.size()];
228 int i = 0;
229 for (String id : mVisibleOrder.keySet()) {
230 final CastDevice device = mVisibleOrder.get(id);
231 if (!devices.contains(device)) continue;
232 final Item item = new Item();
233 item.icon = R.drawable.ic_qs_cast_off;
234 item.line1 = getDeviceName(device);
235 if (device.state == CastDevice.STATE_CONNECTING) {
236 item.line2 = mContext.getString(R.string.quick_settings_connecting);
237 }
238 item.tag = device;
239 items[i++] = item;
240 }
241 }
242 }
243 mItems.setItems(items);
244 }
245
246 @Override
247 public void onDetailItemClick(Item item) {
248 if (item == null || item.tag == null) return;
249 final CastDevice device = (CastDevice) item.tag;
250 mController.startCasting(device);
251 }
252
253 @Override
254 public void onDetailItemDisconnect(Item item) {
255 if (item == null || item.tag == null) return;
John Spurlock78b8c8f2014-08-25 17:52:06 -0400256 final CastDevice device = (CastDevice) item.tag;
257 mController.stopCasting(device);
John Spurlock1e6eb172014-07-13 11:59:50 -0400258 }
259 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400260}