2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.systemui.qs.tiles;
19 import android.bluetooth.BluetoothAdapter;
20 import android.bluetooth.BluetoothDevice;
21 import android.bluetooth.BluetoothProfile;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.provider.Settings;
25 import android.text.TextUtils;
26 import android.view.View;
27 import android.view.ViewGroup;
28 import android.widget.Button;
29 import android.widget.Switch;
31 import com.android.internal.logging.MetricsLogger;
32 import com.android.internal.logging.MetricsProto.MetricsEvent;
33 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
34 import com.android.systemui.R;
35 import com.android.systemui.qs.QSDetailItems;
36 import com.android.systemui.qs.QSDetailItems.Item;
37 import com.android.systemui.qs.QSTile;
38 import com.android.systemui.statusbar.policy.BluetoothController;
40 import java.util.ArrayList;
41 import java.util.Collection;
43 /** Quick settings tile: Bluetooth **/
44 public class BluetoothTile extends QSTile<QSTile.BooleanState> {
45 private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
47 private final BluetoothController mController;
48 private final BluetoothDetailAdapter mDetailAdapter;
50 public BluetoothTile(Host host) {
52 mController = host.getBluetoothController();
53 mDetailAdapter = new BluetoothDetailAdapter();
57 public DetailAdapter getDetailAdapter() {
58 return mDetailAdapter;
62 public BooleanState newTileState() {
63 return new BooleanState();
67 public void setListening(boolean listening) {
69 mController.addStateChangedCallback(mCallback);
71 mController.removeStateChangedCallback(mCallback);
76 protected void handleSecondaryClick() {
77 // Secondary clicks are header clicks, just toggle.
78 final boolean isEnabled = (Boolean)mState.value;
79 MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
80 mController.setBluetoothEnabled(!isEnabled);
84 public Intent getLongClickIntent() {
85 return new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
89 protected void handleClick() {
90 if (!mController.canConfigBluetooth()) {
91 mHost.startActivityDismissingKeyguard(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
97 mController.setBluetoothEnabled(true);
102 public CharSequence getTileLabel() {
103 return mContext.getString(R.string.quick_settings_bluetooth_label);
107 protected void handleUpdateState(BooleanState state, Object arg) {
108 final boolean enabled = mController.isBluetoothEnabled();
109 final boolean connected = mController.isBluetoothConnected();
110 final boolean connecting = mController.isBluetoothConnecting();
111 state.value = enabled;
112 state.autoMirrorDrawable = false;
113 state.minimalContentDescription =
114 mContext.getString(R.string.accessibility_quick_settings_bluetooth);
118 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected);
119 state.label = mController.getLastDeviceName();
120 state.contentDescription = mContext.getString(
121 R.string.accessibility_bluetooth_name, state.label);
122 state.minimalContentDescription = state.minimalContentDescription + ","
123 + state.contentDescription;
124 } else if (connecting) {
125 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connecting);
126 state.contentDescription = mContext.getString(
127 R.string.accessibility_quick_settings_bluetooth_connecting);
128 state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
129 state.minimalContentDescription = state.minimalContentDescription + ","
130 + state.contentDescription;
132 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
133 state.contentDescription = mContext.getString(
134 R.string.accessibility_quick_settings_bluetooth_on) + ","
135 + mContext.getString(R.string.accessibility_not_connected);
136 state.minimalContentDescription = state.minimalContentDescription + ","
137 + mContext.getString(R.string.accessibility_not_connected);
139 if (TextUtils.isEmpty(state.label)) {
140 state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
143 state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_off);
144 state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
145 state.contentDescription = mContext.getString(
146 R.string.accessibility_quick_settings_bluetooth_off);
149 CharSequence bluetoothName = state.label;
151 bluetoothName = state.dualLabelContentDescription = mContext.getString(
152 R.string.accessibility_bluetooth_name, state.label);
154 state.dualLabelContentDescription = bluetoothName;
155 state.contentDescription = state.contentDescription + "," + mContext.getString(
156 R.string.accessibility_quick_settings_open_settings, getTileLabel());
157 state.expandedAccessibilityClassName = Button.class.getName();
158 state.minimalAccessibilityClassName = Switch.class.getName();
162 public int getMetricsCategory() {
163 return MetricsEvent.QS_BLUETOOTH;
167 protected String composeChangeAnnouncement() {
169 return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_on);
171 return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_off);
176 public boolean isAvailable() {
177 return mController.isBluetoothSupported();
180 private final BluetoothController.Callback mCallback = new BluetoothController.Callback() {
182 public void onBluetoothStateChange(boolean enabled) {
187 public void onBluetoothDevicesChanged() {
188 mUiHandler.post(new Runnable() {
191 mDetailAdapter.updateItems();
198 private final class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
199 private QSDetailItems mItems;
202 public CharSequence getTitle() {
203 return mContext.getString(R.string.quick_settings_bluetooth_label);
207 public Boolean getToggleState() {
212 public boolean getToggleEnabled() {
213 return mController.getBluetoothState() == BluetoothAdapter.STATE_OFF
214 || mController.getBluetoothState() == BluetoothAdapter.STATE_ON;
218 public Intent getSettingsIntent() {
219 return BLUETOOTH_SETTINGS;
223 public void setToggleState(boolean state) {
224 MetricsLogger.action(mContext, MetricsEvent.QS_BLUETOOTH_TOGGLE, state);
225 mController.setBluetoothEnabled(state);
230 public int getMetricsCategory() {
231 return MetricsEvent.QS_BLUETOOTH_DETAILS;
235 public View createDetailView(Context context, View convertView, ViewGroup parent) {
236 mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
237 mItems.setTagSuffix("Bluetooth");
238 mItems.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
239 R.string.quick_settings_bluetooth_detail_empty_text);
240 mItems.setCallback(this);
242 setItemsVisible(mState.value);
246 public void setItemsVisible(boolean visible) {
247 if (mItems == null) return;
248 mItems.setItemsVisible(visible);
251 private void updateItems() {
252 if (mItems == null) return;
253 ArrayList<Item> items = new ArrayList<Item>();
254 final Collection<CachedBluetoothDevice> devices = mController.getDevices();
255 if (devices != null) {
256 for (CachedBluetoothDevice device : devices) {
257 if (device.getBondState() == BluetoothDevice.BOND_NONE) continue;
258 final Item item = new Item();
259 item.icon = R.drawable.ic_qs_bluetooth_on;
260 item.line1 = device.getName();
261 int state = device.getMaxConnectionState();
262 if (state == BluetoothProfile.STATE_CONNECTED) {
263 item.icon = R.drawable.ic_qs_bluetooth_connected;
264 item.line2 = mContext.getString(R.string.quick_settings_connected);
265 item.canDisconnect = true;
266 } else if (state == BluetoothProfile.STATE_CONNECTING) {
267 item.icon = R.drawable.ic_qs_bluetooth_connecting;
268 item.line2 = mContext.getString(R.string.quick_settings_connecting);
274 mItems.setItems(items.toArray(new Item[items.size()]));
278 public void onDetailItemClick(Item item) {
279 if (item == null || item.tag == null) return;
280 final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
281 if (device != null && device.getMaxConnectionState()
282 == BluetoothProfile.STATE_DISCONNECTED) {
283 mController.connect(device);
288 public void onDetailItemDisconnect(Item item) {
289 if (item == null || item.tag == null) return;
290 final CachedBluetoothDevice device = (CachedBluetoothDevice) item.tag;
291 if (device != null) {
292 mController.disconnect(device);