BluetoothTile.java revision 0ed01deb2fc99603a33f968044703a740673c7b3
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
17package com.android.systemui.qs.tiles;
18
19import android.content.Context;
20import android.content.Intent;
21import android.provider.Settings;
22import android.text.TextUtils;
23import android.view.View;
24import android.view.ViewGroup;
25
26import com.android.systemui.R;
27import com.android.systemui.qs.QSDetailItems;
28import com.android.systemui.qs.QSDetailItems.Item;
29import com.android.systemui.qs.QSTile;
30import com.android.systemui.statusbar.policy.BluetoothController;
31import com.android.systemui.statusbar.policy.BluetoothController.PairedDevice;
32
33import java.util.Set;
34
35/** Quick settings tile: Bluetooth **/
36public class BluetoothTile extends QSTile<QSTile.BooleanState>  {
37    private static final Intent BLUETOOTH_SETTINGS = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
38
39    private final BluetoothController mController;
40    private final BluetoothDetailAdapter mDetailAdapter;
41
42    public BluetoothTile(Host host) {
43        super(host);
44        mController = host.getBluetoothController();
45        mDetailAdapter = new BluetoothDetailAdapter();
46    }
47
48    @Override
49    public boolean supportsDualTargets() {
50        return true;
51    }
52
53    @Override
54    public DetailAdapter getDetailAdapter() {
55        return mDetailAdapter;
56    }
57
58    @Override
59    protected BooleanState newTileState() {
60        return new BooleanState();
61    }
62
63    @Override
64    public void setListening(boolean listening) {
65        if (listening) {
66            mController.addStateChangedCallback(mCallback);
67        } else {
68            mController.removeStateChangedCallback(mCallback);
69        }
70    }
71
72    @Override
73    protected void handleClick() {
74        final boolean isEnabled = (Boolean)mState.value;
75        mController.setBluetoothEnabled(!isEnabled);
76    }
77
78    @Override
79    protected void handleSecondaryClick() {
80        if (!mState.value) {
81            mState.value = true;
82            mController.setBluetoothEnabled(true);
83        }
84        showDetail(true);
85    }
86
87    @Override
88    protected void handleUpdateState(BooleanState state, Object arg) {
89        final boolean supported = mController.isBluetoothSupported();
90        final boolean enabled = mController.isBluetoothEnabled();
91        final boolean connected = mController.isBluetoothConnected();
92        final boolean connecting = mController.isBluetoothConnecting();
93        state.visible = supported;
94        state.value = enabled;
95        state.autoMirrorDrawable = false;
96        if (enabled) {
97            state.label = null;
98            if (connected) {
99                state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected);
100                state.contentDescription = mContext.getString(
101                        R.string.accessibility_quick_settings_bluetooth_connected);
102                state.label = mController.getLastDeviceName();
103            } else if (connecting) {
104                state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connecting);
105                state.contentDescription = mContext.getString(
106                        R.string.accessibility_quick_settings_bluetooth_connecting);
107                state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
108            } else {
109                state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
110                state.contentDescription = mContext.getString(
111                        R.string.accessibility_quick_settings_bluetooth_on);
112            }
113            if (TextUtils.isEmpty(state.label)) {
114                state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
115            }
116        } else {
117            state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_off);
118            state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
119            state.contentDescription = mContext.getString(
120                    R.string.accessibility_quick_settings_bluetooth_off);
121        }
122
123        String bluetoothName = state.label;
124        if (connected) {
125            bluetoothName = state.dualLabelContentDescription = mContext.getString(
126                    R.string.accessibility_bluetooth_name, state.label);
127        }
128        state.dualLabelContentDescription = bluetoothName;
129    }
130
131    @Override
132    protected String composeChangeAnnouncement() {
133        if (mState.value) {
134            return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_on);
135        } else {
136            return mContext.getString(R.string.accessibility_quick_settings_bluetooth_changed_off);
137        }
138    }
139
140    private final BluetoothController.Callback mCallback = new BluetoothController.Callback() {
141        @Override
142        public void onBluetoothStateChange(boolean enabled, boolean connecting) {
143            refreshState();
144        }
145        @Override
146        public void onBluetoothPairedDevicesChanged() {
147            mUiHandler.post(new Runnable() {
148                @Override
149                public void run() {
150                    mDetailAdapter.updateItems();
151                }
152            });
153            refreshState();
154        }
155    };
156
157    private final class BluetoothDetailAdapter implements DetailAdapter, QSDetailItems.Callback {
158        private QSDetailItems mItems;
159
160        @Override
161        public int getTitle() {
162            return R.string.quick_settings_bluetooth_label;
163        }
164
165        @Override
166        public Boolean getToggleState() {
167            return mState.value;
168        }
169
170        @Override
171        public Intent getSettingsIntent() {
172            return BLUETOOTH_SETTINGS;
173        }
174
175        @Override
176        public void setToggleState(boolean state) {
177            mController.setBluetoothEnabled(state);
178            showDetail(false);
179        }
180
181        @Override
182        public View createDetailView(Context context, View convertView, ViewGroup parent) {
183            mItems = QSDetailItems.convertOrInflate(context, convertView, parent);
184            mItems.setTagSuffix("Bluetooth");
185            mItems.setEmptyState(R.drawable.ic_qs_bluetooth_detail_empty,
186                    R.string.quick_settings_bluetooth_detail_empty_text);
187            mItems.setCallback(this);
188            mItems.setMinHeightInItems(0);
189            updateItems();
190            setItemsVisible(mState.value);
191            return mItems;
192        }
193
194        public void setItemsVisible(boolean visible) {
195            if (mItems == null) return;
196            mItems.setItemsVisible(visible);
197        }
198
199        private void updateItems() {
200            if (mItems == null) return;
201            Item[] items = null;
202            final Set<PairedDevice> devices = mController.getPairedDevices();
203            if (devices != null) {
204                items = new Item[devices.size()];
205                int i = 0;
206                for (PairedDevice device : devices) {
207                    final Item item = new Item();
208                    item.icon = R.drawable.ic_qs_bluetooth_on;
209                    item.line1 = device.name;
210                    if (device.state == PairedDevice.STATE_CONNECTED) {
211                        item.icon = R.drawable.ic_qs_bluetooth_connected;
212                        item.line2 = mContext.getString(R.string.quick_settings_connected);
213                        item.canDisconnect = true;
214                    } else if (device.state == PairedDevice.STATE_CONNECTING) {
215                        item.icon = R.drawable.ic_qs_bluetooth_connecting;
216                        item.line2 = mContext.getString(R.string.quick_settings_connecting);
217                    }
218                    item.tag = device;
219                    items[i++] = item;
220                }
221            }
222            mItems.setItems(items);
223        }
224
225        @Override
226        public void onDetailItemClick(Item item) {
227            if (item == null || item.tag == null) return;
228            final PairedDevice device = (PairedDevice) item.tag;
229            if (device != null && device.state == PairedDevice.STATE_DISCONNECTED) {
230                mController.connect(device);
231            }
232        }
233
234        @Override
235        public void onDetailItemDisconnect(Item item) {
236            if (item == null || item.tag == null) return;
237            final PairedDevice device = (PairedDevice) item.tag;
238            if (device != null) {
239                mController.disconnect(device);
240            }
241        }
242    }
243}
244