blob: 36d24b370b00e0b99f598fbb8d126f6f37f0377b [file] [log] [blame]
John Spurlockaf8d6c42014-05-07 17:49:08 -04001/*
2 * Copyright (C) 2008 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.statusbar.policy;
18
Sudheer Shankab6fc9312016-01-27 19:59:03 +000019import android.app.ActivityManager;
John Spurlockaf8d6c42014-05-07 17:49:08 -040020import android.bluetooth.BluetoothAdapter;
John Spurlockaf8d6c42014-05-07 17:49:08 -040021import android.content.Context;
Jason Monk744cf642015-05-19 12:04:41 -040022import android.os.Handler;
Jason Monk4ae97d32014-12-17 10:14:33 -050023import android.os.Looper;
Jason Monk744cf642015-05-19 12:04:41 -040024import android.os.Message;
Sudheer Shankab6fc9312016-01-27 19:59:03 +000025import android.os.UserHandle;
26import android.os.UserManager;
John Spurlock486b78e2014-07-07 08:37:56 -040027import android.util.Log;
John Spurlockaf8d6c42014-05-07 17:49:08 -040028
Jason Monkbe3c5db2015-02-04 13:00:55 -050029import com.android.settingslib.bluetooth.BluetoothCallback;
30import com.android.settingslib.bluetooth.CachedBluetoothDevice;
31import com.android.settingslib.bluetooth.LocalBluetoothManager;
Jason Monk6a73e632017-03-17 11:08:30 -040032import com.android.systemui.Dependency;
John Spurlock486b78e2014-07-07 08:37:56 -040033
34import java.io.FileDescriptor;
35import java.io.PrintWriter;
John Spurlockaf8d6c42014-05-07 17:49:08 -040036import java.util.ArrayList;
Jason Monkbe3c5db2015-02-04 13:00:55 -050037import java.util.Collection;
John Spurlockaf8d6c42014-05-07 17:49:08 -040038
Jason Monkbe3c5db2015-02-04 13:00:55 -050039public class BluetoothControllerImpl implements BluetoothController, BluetoothCallback,
40 CachedBluetoothDevice.Callback {
John Spurlock486b78e2014-07-07 08:37:56 -040041 private static final String TAG = "BluetoothController";
42 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
Jason Monk4ae97d32014-12-17 10:14:33 -050043
Jason Monkbe3c5db2015-02-04 13:00:55 -050044 private final LocalBluetoothManager mLocalBluetoothManager;
Sudheer Shankab6fc9312016-01-27 19:59:03 +000045 private final UserManager mUserManager;
46 private final int mCurrentUser;
Jason Monk4ae97d32014-12-17 10:14:33 -050047
John Spurlockd1c86e22014-06-01 00:04:53 -040048 private boolean mEnabled;
Jason Monka7d92b62015-05-27 10:20:37 -040049 private int mConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
Jason Monkbe3c5db2015-02-04 13:00:55 -050050 private CachedBluetoothDevice mLastDevice;
John Spurlockaf8d6c42014-05-07 17:49:08 -040051
Jason Monk744cf642015-05-19 12:04:41 -040052 private final H mHandler = new H();
Jason Monkfac25382016-07-19 14:13:37 -040053 private int mState;
Jason Monk744cf642015-05-19 12:04:41 -040054
Jason Monk4ae97d32014-12-17 10:14:33 -050055 public BluetoothControllerImpl(Context context, Looper bgLooper) {
Jason Monk6a73e632017-03-17 11:08:30 -040056 mLocalBluetoothManager = Dependency.get(LocalBluetoothManager.class);
Jason Monkbe3c5db2015-02-04 13:00:55 -050057 if (mLocalBluetoothManager != null) {
Jason Monk744cf642015-05-19 12:04:41 -040058 mLocalBluetoothManager.getEventManager().setReceiverHandler(new Handler(bgLooper));
Jason Monkbe3c5db2015-02-04 13:00:55 -050059 mLocalBluetoothManager.getEventManager().registerCallback(this);
60 onBluetoothStateChanged(
61 mLocalBluetoothManager.getBluetoothAdapter().getBluetoothState());
John Spurlockaf8d6c42014-05-07 17:49:08 -040062 }
Sudheer Shankab6fc9312016-01-27 19:59:03 +000063 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
64 mCurrentUser = ActivityManager.getCurrentUser();
65 }
66
67 @Override
68 public boolean canConfigBluetooth() {
69 return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_BLUETOOTH,
70 UserHandle.of(mCurrentUser));
John Spurlockaf8d6c42014-05-07 17:49:08 -040071 }
72
John Spurlock486b78e2014-07-07 08:37:56 -040073 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
74 pw.println("BluetoothController state:");
Jason Monkbe3c5db2015-02-04 13:00:55 -050075 pw.print(" mLocalBluetoothManager="); pw.println(mLocalBluetoothManager);
Jason Monk09389a92015-05-19 16:06:52 -040076 if (mLocalBluetoothManager == null) {
77 return;
78 }
John Spurlock486b78e2014-07-07 08:37:56 -040079 pw.print(" mEnabled="); pw.println(mEnabled);
Jason Monka7d92b62015-05-27 10:20:37 -040080 pw.print(" mConnectionState="); pw.println(stateToString(mConnectionState));
John Spurlock486b78e2014-07-07 08:37:56 -040081 pw.print(" mLastDevice="); pw.println(mLastDevice);
Adrian Roosa4b54862016-06-17 14:28:27 -070082 pw.print(" mCallbacks.size="); pw.println(mHandler.mCallbacks.size());
Jason Monkbe3c5db2015-02-04 13:00:55 -050083 pw.println(" Bluetooth Devices:");
84 for (CachedBluetoothDevice device :
85 mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()) {
86 pw.println(" " + getDeviceString(device));
John Spurlock486b78e2014-07-07 08:37:56 -040087 }
88 }
89
Jason Monka7d92b62015-05-27 10:20:37 -040090 private static String stateToString(int state) {
91 switch (state) {
92 case BluetoothAdapter.STATE_CONNECTED:
93 return "CONNECTED";
94 case BluetoothAdapter.STATE_CONNECTING:
95 return "CONNECTING";
96 case BluetoothAdapter.STATE_DISCONNECTED:
97 return "DISCONNECTED";
98 case BluetoothAdapter.STATE_DISCONNECTING:
99 return "DISCONNECTING";
100 }
101 return "UNKNOWN(" + state + ")";
102 }
103
Jason Monkbe3c5db2015-02-04 13:00:55 -0500104 private String getDeviceString(CachedBluetoothDevice device) {
105 return device.getName() + " " + device.getBondState() + " " + device.isConnected();
John Spurlock486b78e2014-07-07 08:37:56 -0400106 }
107
Jason Monka7d92b62015-05-27 10:20:37 -0400108 @Override
Jason Monk88529052016-11-04 13:29:58 -0400109 public void addCallback(Callback cb) {
Adrian Roosa4b54862016-06-17 14:28:27 -0700110 mHandler.obtainMessage(H.MSG_ADD_CALLBACK, cb).sendToTarget();
Jason Monk744cf642015-05-19 12:04:41 -0400111 mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400112 }
113
114 @Override
Jason Monk88529052016-11-04 13:29:58 -0400115 public void removeCallback(Callback cb) {
Adrian Roosa4b54862016-06-17 14:28:27 -0700116 mHandler.obtainMessage(H.MSG_REMOVE_CALLBACK, cb).sendToTarget();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400117 }
118
119 @Override
120 public boolean isBluetoothEnabled() {
Jason Monkbe3c5db2015-02-04 13:00:55 -0500121 return mEnabled;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400122 }
123
124 @Override
Jason Monkfac25382016-07-19 14:13:37 -0400125 public int getBluetoothState() {
126 return mState;
127 }
128
129 @Override
John Spurlockaf8d6c42014-05-07 17:49:08 -0400130 public boolean isBluetoothConnected() {
Jason Monka7d92b62015-05-27 10:20:37 -0400131 return mConnectionState == BluetoothAdapter.STATE_CONNECTED;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400132 }
133
134 @Override
John Spurlockd1c86e22014-06-01 00:04:53 -0400135 public boolean isBluetoothConnecting() {
Jason Monka7d92b62015-05-27 10:20:37 -0400136 return mConnectionState == BluetoothAdapter.STATE_CONNECTING;
John Spurlockd1c86e22014-06-01 00:04:53 -0400137 }
138
139 @Override
John Spurlockaf8d6c42014-05-07 17:49:08 -0400140 public void setBluetoothEnabled(boolean enabled) {
Jason Monkbe3c5db2015-02-04 13:00:55 -0500141 if (mLocalBluetoothManager != null) {
142 mLocalBluetoothManager.getBluetoothAdapter().setBluetoothEnabled(enabled);
John Spurlockaf8d6c42014-05-07 17:49:08 -0400143 }
144 }
145
146 @Override
147 public boolean isBluetoothSupported() {
Jason Monkbe3c5db2015-02-04 13:00:55 -0500148 return mLocalBluetoothManager != null;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400149 }
150
John Spurlock486b78e2014-07-07 08:37:56 -0400151 @Override
Jason Monkbe3c5db2015-02-04 13:00:55 -0500152 public void connect(final CachedBluetoothDevice device) {
153 if (mLocalBluetoothManager == null || device == null) return;
154 device.connect(true);
John Spurlock486b78e2014-07-07 08:37:56 -0400155 }
156
157 @Override
Jason Monkbe3c5db2015-02-04 13:00:55 -0500158 public void disconnect(CachedBluetoothDevice device) {
159 if (mLocalBluetoothManager == null || device == null) return;
160 device.disconnect();
John Spurlockaf8d6c42014-05-07 17:49:08 -0400161 }
162
163 @Override
John Spurlockd1c86e22014-06-01 00:04:53 -0400164 public String getLastDeviceName() {
Jason Monkbe3c5db2015-02-04 13:00:55 -0500165 return mLastDevice != null ? mLastDevice.getName() : null;
John Spurlockaf8d6c42014-05-07 17:49:08 -0400166 }
167
Jason Monkbe3c5db2015-02-04 13:00:55 -0500168 @Override
169 public Collection<CachedBluetoothDevice> getDevices() {
170 return mLocalBluetoothManager != null
171 ? mLocalBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy()
172 : null;
Jason Monk4630c892014-12-08 16:36:16 -0500173 }
174
Jason Monkbe3c5db2015-02-04 13:00:55 -0500175 private void updateConnected() {
Jason Monk90970562015-06-19 10:04:49 -0400176 // Make sure our connection state is up to date.
177 int state = mLocalBluetoothManager.getBluetoothAdapter().getConnectionState();
Jason Monk6a73e632017-03-17 11:08:30 -0400178 if (mLastDevice != null && !mLastDevice.isConnected()) {
179 // Clear out last device if no longer connected.
180 mLastDevice = null;
Jason Monk90970562015-06-19 10:04:49 -0400181 }
Jason Monk6a73e632017-03-17 11:08:30 -0400182 // If any of the devices are in a higher state than the adapter, move the adapter into
183 // that state.
Jason Monkbe3c5db2015-02-04 13:00:55 -0500184 for (CachedBluetoothDevice device : getDevices()) {
Jason Monk6a73e632017-03-17 11:08:30 -0400185 int maxDeviceState = device.getMaxConnectionState();
186 if (maxDeviceState > state) {
187 state = maxDeviceState;
188 }
189 if (mLastDevice == null && device.isConnected()) {
190 // Set as last connected device only if we don't have one.
John Spurlock486b78e2014-07-07 08:37:56 -0400191 mLastDevice = device;
John Spurlock486b78e2014-07-07 08:37:56 -0400192 }
John Spurlock486b78e2014-07-07 08:37:56 -0400193 }
Jason Monk6a73e632017-03-17 11:08:30 -0400194
195 if (mLastDevice == null && state == BluetoothAdapter.STATE_CONNECTED) {
Jason Monkbba73172015-08-12 16:17:34 -0400196 // If somehow we think we are connected, but have no connected devices, we aren't
197 // connected.
Jason Monk6a73e632017-03-17 11:08:30 -0400198 state = BluetoothAdapter.STATE_DISCONNECTED;
199 }
200 if (state != mConnectionState) {
201 mConnectionState = state;
Jason Monkbba73172015-08-12 16:17:34 -0400202 mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
203 }
John Spurlock486b78e2014-07-07 08:37:56 -0400204 }
205
Jason Monkbe3c5db2015-02-04 13:00:55 -0500206 @Override
207 public void onBluetoothStateChanged(int bluetoothState) {
Jason Monkfac25382016-07-19 14:13:37 -0400208 mEnabled = bluetoothState == BluetoothAdapter.STATE_ON
209 || bluetoothState == BluetoothAdapter.STATE_TURNING_ON;
210 mState = bluetoothState;
Jason Monk744cf642015-05-19 12:04:41 -0400211 mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
John Spurlock486b78e2014-07-07 08:37:56 -0400212 }
213
Jason Monkbe3c5db2015-02-04 13:00:55 -0500214 @Override
215 public void onScanningStateChanged(boolean started) {
216 // Don't care.
217 }
Jason Monk4ae97d32014-12-17 10:14:33 -0500218
Jason Monkbe3c5db2015-02-04 13:00:55 -0500219 @Override
220 public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
221 cachedDevice.registerCallback(this);
222 updateConnected();
Jason Monk744cf642015-05-19 12:04:41 -0400223 mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
Jason Monkbe3c5db2015-02-04 13:00:55 -0500224 }
Jason Monk4ae97d32014-12-17 10:14:33 -0500225
Jason Monkbe3c5db2015-02-04 13:00:55 -0500226 @Override
227 public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
228 updateConnected();
Jason Monk744cf642015-05-19 12:04:41 -0400229 mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
Jason Monkbe3c5db2015-02-04 13:00:55 -0500230 }
231
232 @Override
233 public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
234 updateConnected();
Jason Monk744cf642015-05-19 12:04:41 -0400235 mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
Jason Monkbe3c5db2015-02-04 13:00:55 -0500236 }
237
238 @Override
239 public void onDeviceAttributesChanged() {
240 updateConnected();
Jason Monk744cf642015-05-19 12:04:41 -0400241 mHandler.sendEmptyMessage(H.MSG_PAIRED_DEVICES_CHANGED);
Jason Monkbe3c5db2015-02-04 13:00:55 -0500242 }
243
244 @Override
245 public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
Jason Monkbe3c5db2015-02-04 13:00:55 -0500246 mLastDevice = cachedDevice;
247 updateConnected();
Jason Monk744cf642015-05-19 12:04:41 -0400248 mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
249 }
250
251 private final class H extends Handler {
Adrian Roosa4b54862016-06-17 14:28:27 -0700252 private final ArrayList<BluetoothController.Callback> mCallbacks = new ArrayList<>();
253
Jason Monk744cf642015-05-19 12:04:41 -0400254 private static final int MSG_PAIRED_DEVICES_CHANGED = 1;
255 private static final int MSG_STATE_CHANGED = 2;
Adrian Roosa4b54862016-06-17 14:28:27 -0700256 private static final int MSG_ADD_CALLBACK = 3;
257 private static final int MSG_REMOVE_CALLBACK = 4;
Jason Monk744cf642015-05-19 12:04:41 -0400258
259 @Override
260 public void handleMessage(Message msg) {
261 switch (msg.what) {
262 case MSG_PAIRED_DEVICES_CHANGED:
263 firePairedDevicesChanged();
264 break;
265 case MSG_STATE_CHANGED:
266 fireStateChange();
267 break;
Adrian Roosa4b54862016-06-17 14:28:27 -0700268 case MSG_ADD_CALLBACK:
269 mCallbacks.add((BluetoothController.Callback) msg.obj);
270 break;
271 case MSG_REMOVE_CALLBACK:
272 mCallbacks.remove((BluetoothController.Callback) msg.obj);
273 break;
Jason Monk744cf642015-05-19 12:04:41 -0400274 }
275 }
276
277 private void firePairedDevicesChanged() {
278 for (BluetoothController.Callback cb : mCallbacks) {
279 cb.onBluetoothDevicesChanged();
280 }
281 }
282
283 private void fireStateChange() {
284 for (BluetoothController.Callback cb : mCallbacks) {
285 fireStateChange(cb);
286 }
287 }
288
289 private void fireStateChange(BluetoothController.Callback cb) {
Jason Monka7d92b62015-05-27 10:20:37 -0400290 cb.onBluetoothStateChange(mEnabled);
Jason Monk744cf642015-05-19 12:04:41 -0400291 }
John Spurlock486b78e2014-07-07 08:37:56 -0400292 }
John Spurlockaf8d6c42014-05-07 17:49:08 -0400293}