blob: e2a8ca2b99ed5142d1df586ef53e7aa6151c2f92 [file] [log] [blame]
fredc0f420372012-04-12 00:02:00 -07001/*
Zhihai Xufa0fd392012-10-23 17:31:56 -07002 * Copyright (C) 2012 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.
fredc0f420372012-04-12 00:02:00 -070015 */
16
17package com.android.server;
18
Zhihai Xu40874a02012-10-08 17:57:03 -070019import android.app.ActivityManager;
fredc0f420372012-04-12 00:02:00 -070020import android.bluetooth.BluetoothAdapter;
21import android.bluetooth.IBluetooth;
Matthew Xieddf7e472013-03-01 18:41:02 -080022import android.bluetooth.IBluetoothGatt;
fredcbf072a72012-05-09 16:52:50 -070023import android.bluetooth.IBluetoothCallback;
fredc0f420372012-04-12 00:02:00 -070024import android.bluetooth.IBluetoothManager;
25import android.bluetooth.IBluetoothManagerCallback;
26import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070027import android.content.BroadcastReceiver;
28import android.content.ComponentName;
29import android.content.ContentResolver;
30import android.content.Context;
31import android.content.Intent;
32import android.content.IntentFilter;
33import android.content.ServiceConnection;
Matthew Xie32ab77b2013-05-08 19:26:57 -070034import android.content.pm.PackageManager;
Zhihai Xu40874a02012-10-08 17:57:03 -070035import android.os.Binder;
fredc0f420372012-04-12 00:02:00 -070036import android.os.Handler;
fredc0f420372012-04-12 00:02:00 -070037import android.os.IBinder;
Zhihai Xu40874a02012-10-08 17:57:03 -070038import android.os.Looper;
fredc0f420372012-04-12 00:02:00 -070039import android.os.Message;
Zhihai Xu40874a02012-10-08 17:57:03 -070040import android.os.Process;
fredcd6883532012-04-25 17:46:13 -070041import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070042import android.os.RemoteException;
Zhihai Xu40874a02012-10-08 17:57:03 -070043import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070044import android.os.UserHandle;
fredc0f420372012-04-12 00:02:00 -070045import android.provider.Settings;
46import android.util.Log;
fredc0f420372012-04-12 00:02:00 -070047class BluetoothManagerService extends IBluetoothManager.Stub {
48 private static final String TAG = "BluetoothManagerService";
49 private static final boolean DBG = true;
50
fredc0f420372012-04-12 00:02:00 -070051 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
52 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070053 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
54 private static final String EXTRA_ACTION="action";
Zhihai Xud31c3222012-10-31 16:08:57 -070055 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
fredc0f420372012-04-12 00:02:00 -070056 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
57 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070058 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
59 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053060 //Maximum msec to wait for service restart
61 private static final int SERVICE_RESTART_TIME_MS = 200;
Zhihai Xudd9d17d2013-01-08 17:05:58 -080062 //Maximum msec to wait for restart due to error
63 private static final int ERROR_RESTART_TIME_MS = 3000;
Zhihai Xu40874a02012-10-08 17:57:03 -070064 //Maximum msec to delay MESSAGE_USER_SWITCHED
65 private static final int USER_SWITCHED_TIME_MS = 200;
fredc0f420372012-04-12 00:02:00 -070066
67 private static final int MESSAGE_ENABLE = 1;
68 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070069 private static final int MESSAGE_REGISTER_ADAPTER = 20;
70 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
71 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
72 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
73 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
74 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053075 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070076 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070077 private static final int MESSAGE_TIMEOUT_BIND =100;
78 private static final int MESSAGE_TIMEOUT_UNBIND =101;
79 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
80 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
Zhihai Xu40874a02012-10-08 17:57:03 -070081 private static final int MESSAGE_USER_SWITCHED = 300;
fredc0f420372012-04-12 00:02:00 -070082 private static final int MAX_SAVE_RETRIES=3;
Zhihai Xudd9d17d2013-01-08 17:05:58 -080083 private static final int MAX_ERROR_RESTART_RETRIES=6;
84
Zhihai Xu401202b2012-12-03 11:36:21 -080085 // Bluetooth persisted setting is off
86 private static final int BLUETOOTH_OFF=0;
87 // Bluetooth persisted setting is on
88 // and Airplane mode won't affect Bluetooth state at start up
89 private static final int BLUETOOTH_ON_BLUETOOTH=1;
90 // Bluetooth persisted setting is on
91 // but Airplane mode will affect Bluetooth state at start up
92 // and Airplane mode will have higher priority.
93 private static final int BLUETOOTH_ON_AIRPLANE=2;
fredc0f420372012-04-12 00:02:00 -070094
Matthew Xieddf7e472013-03-01 18:41:02 -080095 private static final int SERVICE_IBLUETOOTH = 1;
96 private static final int SERVICE_IBLUETOOTHGATT = 2;
97
fredc0f420372012-04-12 00:02:00 -070098 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070099
100 // Locks are not provided for mName and mAddress.
101 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -0700102 private String mAddress;
103 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -0700104 private final ContentResolver mContentResolver;
105 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
106 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -0700107 private IBluetooth mBluetooth;
Matthew Xieddf7e472013-03-01 18:41:02 -0800108 private IBluetoothGatt mBluetoothGatt;
fredc649fe492012-04-19 01:07:18 -0700109 private boolean mBinding;
110 private boolean mUnbinding;
Zhihai Xu401202b2012-12-03 11:36:21 -0800111 // used inside handler thread
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700112 private boolean mQuietEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800113 // configuarion from external IBinder call which is used to
114 // synchronize with broadcast receiver.
115 private boolean mQuietEnableExternal;
116 // configuarion from external IBinder call which is used to
117 // synchronize with broadcast receiver.
118 private boolean mEnableExternal;
119 // used inside handler thread
Zhihai Xu40874a02012-10-08 17:57:03 -0700120 private boolean mEnable;
121 private int mState;
Zhihai Xu40874a02012-10-08 17:57:03 -0700122 private final BluetoothHandler mHandler;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800123 private int mErrorRecoveryRetryCounter;
fredc0f420372012-04-12 00:02:00 -0700124
fredc649fe492012-04-19 01:07:18 -0700125 private void registerForAirplaneMode(IntentFilter filter) {
126 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700127 final String airplaneModeRadios = Settings.Global.getString(resolver,
128 Settings.Global.AIRPLANE_MODE_RADIOS);
129 final String toggleableRadios = Settings.Global.getString(resolver,
130 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700131 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700132 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700133 if (mIsAirplaneSensitive) {
134 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
135 }
136 }
137
fredcbf072a72012-05-09 16:52:50 -0700138 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
139 @Override
140 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
141 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
142 mHandler.sendMessage(msg);
143 }
144 };
145
146 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700147 @Override
148 public void onReceive(Context context, Intent intent) {
149 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700150 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700151 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700152 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700153 if (newName != null) {
154 storeNameAndAddress(newName, null);
155 }
fredc649fe492012-04-19 01:07:18 -0700156 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
Zhihai Xu401202b2012-12-03 11:36:21 -0800157 synchronized(mReceiver) {
158 if (isBluetoothPersistedStateOn()) {
159 if (isAirplaneModeOn()) {
160 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
161 } else {
162 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
163 }
164 }
165 if (isAirplaneModeOn()) {
166 // disable without persisting the setting
167 sendDisableMsg();
168 } else if (mEnableExternal) {
169 // enable without persisting the setting
170 sendEnableMsg(mQuietEnableExternal);
171 }
fredc649fe492012-04-19 01:07:18 -0700172 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700173 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
174 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
175 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Zhihai Xu401202b2012-12-03 11:36:21 -0800176 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
177 synchronized(mReceiver) {
178 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
179 //Enable
180 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
181 sendEnableMsg(mQuietEnableExternal);
182 }
183 }
184
185 if (!isNameAndAddressSet()) {
186 //Sync the Bluetooth name and address from the Bluetooth Adapter
187 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
188 getNameAndAddress();
189 }
fredc0f420372012-04-12 00:02:00 -0700190 }
191 }
192 };
193
194 BluetoothManagerService(Context context) {
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700195 mHandler = new BluetoothHandler(IoThread.get().getLooper());
Zhihai Xu40874a02012-10-08 17:57:03 -0700196
fredc0f420372012-04-12 00:02:00 -0700197 mContext = context;
198 mBluetooth = null;
199 mBinding = false;
200 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700201 mEnable = false;
202 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu401202b2012-12-03 11:36:21 -0800203 mQuietEnableExternal = false;
204 mEnableExternal = false;
fredc0f420372012-04-12 00:02:00 -0700205 mAddress = null;
206 mName = null;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800207 mErrorRecoveryRetryCounter = 0;
fredc0f420372012-04-12 00:02:00 -0700208 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700209 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
210 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Zhihai Xu401202b2012-12-03 11:36:21 -0800211 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700212 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700213 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700214 registerForAirplaneMode(filter);
Dianne Hackbornd83a0962014-05-02 16:28:33 -0700215 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Matthew Xie6fde3092012-07-11 17:10:07 -0700216 mContext.registerReceiver(mReceiver, filter);
fredc0f420372012-04-12 00:02:00 -0700217 loadStoredNameAndAddress();
Zhihai Xu401202b2012-12-03 11:36:21 -0800218 if (isBluetoothPersistedStateOn()) {
219 mEnableExternal = true;
fredc0f420372012-04-12 00:02:00 -0700220 }
221 }
222
fredc649fe492012-04-19 01:07:18 -0700223 /**
224 * Returns true if airplane mode is currently on
225 */
226 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700227 return Settings.Global.getInt(mContext.getContentResolver(),
228 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700229 }
230
231 /**
232 * Returns true if the Bluetooth saved state is "on"
233 */
234 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700235 return Settings.Global.getInt(mContentResolver,
Zhihai Xu401202b2012-12-03 11:36:21 -0800236 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
237 }
238
239 /**
240 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
241 */
242 private final boolean isBluetoothPersistedStateOnBluetooth() {
243 return Settings.Global.getInt(mContentResolver,
244 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
fredc649fe492012-04-19 01:07:18 -0700245 }
246
247 /**
248 * Save the Bluetooth on/off state
249 *
250 */
Zhihai Xu401202b2012-12-03 11:36:21 -0800251 private void persistBluetoothSetting(int value) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700252 Settings.Global.putInt(mContext.getContentResolver(),
253 Settings.Global.BLUETOOTH_ON,
Zhihai Xu401202b2012-12-03 11:36:21 -0800254 value);
fredc649fe492012-04-19 01:07:18 -0700255 }
256
257 /**
258 * Returns true if the Bluetooth Adapter's name and address is
259 * locally cached
260 * @return
261 */
fredc0f420372012-04-12 00:02:00 -0700262 private boolean isNameAndAddressSet() {
263 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
264 }
265
fredc649fe492012-04-19 01:07:18 -0700266 /**
267 * Retrieve the Bluetooth Adapter's name and address and save it in
268 * in the local cache
269 */
fredc0f420372012-04-12 00:02:00 -0700270 private void loadStoredNameAndAddress() {
271 if (DBG) Log.d(TAG, "Loading stored name and address");
Zhihai Xud31c3222012-10-31 16:08:57 -0700272 if (mContext.getResources().getBoolean
273 (com.android.internal.R.bool.config_bluetooth_address_validation) &&
274 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
275 // if the valid flag is not set, don't load the address and name
276 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
277 return;
278 }
fredc0f420372012-04-12 00:02:00 -0700279 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
280 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
Zhihai Xud31c3222012-10-31 16:08:57 -0700281 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
fredc0f420372012-04-12 00:02:00 -0700282 }
283
fredc649fe492012-04-19 01:07:18 -0700284 /**
285 * Save the Bluetooth name and address in the persistent store.
286 * Only non-null values will be saved.
287 * @param name
288 * @param address
289 */
fredc0f420372012-04-12 00:02:00 -0700290 private void storeNameAndAddress(String name, String address) {
291 if (name != null) {
292 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700293 mName = name;
fredc649fe492012-04-19 01:07:18 -0700294 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
295 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700296 }
297
298 if (address != null) {
299 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700300 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700301 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
302 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700303 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700304
305 if ((name != null) && (address != null)) {
306 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
307 }
fredc0f420372012-04-12 00:02:00 -0700308 }
309
310 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
fredc0f420372012-04-12 00:02:00 -0700311 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
312 msg.obj = callback;
313 mHandler.sendMessage(msg);
314 synchronized(mConnection) {
315 return mBluetooth;
316 }
317 }
318
319 public void unregisterAdapter(IBluetoothManagerCallback callback) {
320 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
321 "Need BLUETOOTH permission");
322 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
323 msg.obj = callback;
324 mHandler.sendMessage(msg);
325 }
326
327 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
328 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
329 "Need BLUETOOTH permission");
330 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
331 msg.obj = callback;
332 mHandler.sendMessage(msg);
333 }
334
335 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
336 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
337 "Need BLUETOOTH permission");
338 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
339 msg.obj = callback;
340 mHandler.sendMessage(msg);
341 }
342
343 public boolean isEnabled() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800344 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
345 (!checkIfCallerIsForegroundUser())) {
346 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700347 return false;
348 }
349
fredc0f420372012-04-12 00:02:00 -0700350 synchronized(mConnection) {
351 try {
352 return (mBluetooth != null && mBluetooth.isEnabled());
353 } catch (RemoteException e) {
354 Log.e(TAG, "isEnabled()", e);
355 }
356 }
357 return false;
358 }
359
360 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700361 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700362 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
363 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700364 }
fredc0f420372012-04-12 00:02:00 -0700365 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
366 mHandler.sendMessage(msg);
367 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700368 public boolean enableNoAutoConnect()
369 {
370 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
371 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700372
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700373 if (DBG) {
374 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
375 " mBinding = " + mBinding);
376 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800377 int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
378
379 if (callingAppId != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700380 throw new SecurityException("no permission to enable Bluetooth quietly");
381 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800382
Zhihai Xu401202b2012-12-03 11:36:21 -0800383 synchronized(mReceiver) {
384 mQuietEnableExternal = true;
385 mEnableExternal = true;
386 sendEnableMsg(true);
387 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700388 return true;
389
390 }
fredc0f420372012-04-12 00:02:00 -0700391 public boolean enable() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800392 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
393 (!checkIfCallerIsForegroundUser())) {
394 Log.w(TAG,"enable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700395 return false;
fredcf2458862012-04-16 15:18:27 -0700396 }
397
Zhihai Xu401202b2012-12-03 11:36:21 -0800398 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
399 "Need BLUETOOTH ADMIN permission");
400 if (DBG) {
401 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
402 " mBinding = " + mBinding);
403 }
404
405 synchronized(mReceiver) {
406 mQuietEnableExternal = false;
407 mEnableExternal = true;
408 // waive WRITE_SECURE_SETTINGS permission check
409 long callingIdentity = Binder.clearCallingIdentity();
410 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
411 Binder.restoreCallingIdentity(callingIdentity);
412 sendEnableMsg(false);
413 }
414 return true;
fredc0f420372012-04-12 00:02:00 -0700415 }
416
417 public boolean disable(boolean persist) {
418 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
419 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700420
Zhihai Xu6eb76522012-11-29 15:41:04 -0800421 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
422 (!checkIfCallerIsForegroundUser())) {
423 Log.w(TAG,"disable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700424 return false;
425 }
426
fredcf2458862012-04-16 15:18:27 -0700427 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700428 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
429 " mBinding = " + mBinding);
430 }
fredcf2458862012-04-16 15:18:27 -0700431
Zhihai Xu401202b2012-12-03 11:36:21 -0800432 synchronized(mReceiver) {
433 if (persist) {
434 // waive WRITE_SECURE_SETTINGS permission check
435 long callingIdentity = Binder.clearCallingIdentity();
436 persistBluetoothSetting(BLUETOOTH_OFF);
437 Binder.restoreCallingIdentity(callingIdentity);
438 }
439 mEnableExternal = false;
440 sendDisableMsg();
441 }
fredc0f420372012-04-12 00:02:00 -0700442 return true;
443 }
444
fredc649fe492012-04-19 01:07:18 -0700445 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700446 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700447 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
448 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700449 }
450
fredc0f420372012-04-12 00:02:00 -0700451 synchronized (mConnection) {
452 if (mUnbinding) return;
453 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700454 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700455 if (!mConnection.isGetNameAddressOnly()) {
456 //Unregister callback object
457 try {
458 mBluetooth.unregisterCallback(mBluetoothCallback);
459 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700460 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700461 }
462 }
fredc0f420372012-04-12 00:02:00 -0700463 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700464 mBluetooth = null;
465 //Unbind
fredc0f420372012-04-12 00:02:00 -0700466 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700467 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700468 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700469 } else {
470 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700471 }
472 }
473 }
474
Matthew Xieddf7e472013-03-01 18:41:02 -0800475 public IBluetoothGatt getBluetoothGatt() {
476 // sync protection
477 return mBluetoothGatt;
478 }
479
fredcbf072a72012-05-09 16:52:50 -0700480 private void sendBluetoothStateCallback(boolean isUp) {
481 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700482 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700483 for (int i=0; i <n;i++) {
484 try {
485 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
486 } catch (RemoteException e) {
487 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
488 }
489 }
490 mStateChangeCallbacks.finishBroadcast();
491 }
492
493 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700494 * Inform BluetoothAdapter instances that Adapter service is up
495 */
496 private void sendBluetoothServiceUpCallback() {
497 if (!mConnection.isGetNameAddressOnly()) {
498 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
499 int n = mCallbacks.beginBroadcast();
500 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
501 for (int i=0; i <n;i++) {
502 try {
503 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
504 } catch (RemoteException e) {
505 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
506 }
507 }
508 mCallbacks.finishBroadcast();
509 }
510 }
511 /**
fredcbf072a72012-05-09 16:52:50 -0700512 * Inform BluetoothAdapter instances that Adapter service is down
513 */
514 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700515 if (!mConnection.isGetNameAddressOnly()) {
516 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
517 int n = mCallbacks.beginBroadcast();
518 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
519 for (int i=0; i <n;i++) {
520 try {
521 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
522 } catch (RemoteException e) {
523 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
524 }
525 }
526 mCallbacks.finishBroadcast();
527 }
528 }
fredc0f420372012-04-12 00:02:00 -0700529 public String getAddress() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800530 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
531 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700532
Zhihai Xu6eb76522012-11-29 15:41:04 -0800533 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
534 (!checkIfCallerIsForegroundUser())) {
535 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
536 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700537 }
538
fredc116d1d462012-04-20 14:47:08 -0700539 synchronized(mConnection) {
540 if (mBluetooth != null) {
541 try {
542 return mBluetooth.getAddress();
543 } catch (RemoteException e) {
544 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
545 }
546 }
547 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700548 // mAddress is accessed from outside.
549 // It is alright without a lock. Here, bluetooth is off, no other thread is
550 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700551 return mAddress;
552 }
fredc649fe492012-04-19 01:07:18 -0700553
fredc0f420372012-04-12 00:02:00 -0700554 public String getName() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800555 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
556 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700557
Zhihai Xu6eb76522012-11-29 15:41:04 -0800558 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
559 (!checkIfCallerIsForegroundUser())) {
560 Log.w(TAG,"getName(): not allowed for non-active and non system user");
561 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700562 }
563
fredc116d1d462012-04-20 14:47:08 -0700564 synchronized(mConnection) {
565 if (mBluetooth != null) {
566 try {
567 return mBluetooth.getName();
568 } catch (RemoteException e) {
569 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
570 }
571 }
572 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700573 // mName is accessed from outside.
574 // It alright without a lock. Here, bluetooth is off, no other thread is
575 // changing mName
fredc0f420372012-04-12 00:02:00 -0700576 return mName;
577 }
578
fredc0f420372012-04-12 00:02:00 -0700579 private class BluetoothServiceConnection implements ServiceConnection {
580
581 private boolean mGetNameAddressOnly;
582
583 public void setGetNameAddressOnly(boolean getOnly) {
584 mGetNameAddressOnly = getOnly;
585 }
586
587 public boolean isGetNameAddressOnly() {
588 return mGetNameAddressOnly;
589 }
590
591 public void onServiceConnected(ComponentName className, IBinder service) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800592 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700593 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800594 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
595 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
596 msg.arg1 = SERVICE_IBLUETOOTH;
597 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
598 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
599 msg.arg1 = SERVICE_IBLUETOOTHGATT;
600 } else {
601 Log.e(TAG, "Unknown service connected: " + className.getClassName());
602 return;
603 }
fredc0f420372012-04-12 00:02:00 -0700604 msg.obj = service;
605 mHandler.sendMessage(msg);
606 }
607
608 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700609 // Called if we unexpected disconnected.
Matthew Xieddf7e472013-03-01 18:41:02 -0800610 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
611 className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700612 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800613 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
614 msg.arg1 = SERVICE_IBLUETOOTH;
615 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
616 msg.arg1 = SERVICE_IBLUETOOTHGATT;
617 } else {
618 Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
619 return;
620 }
fredc0f420372012-04-12 00:02:00 -0700621 mHandler.sendMessage(msg);
622 }
623 }
624
625 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
626
Zhihai Xu40874a02012-10-08 17:57:03 -0700627 private class BluetoothHandler extends Handler {
628 public BluetoothHandler(Looper looper) {
629 super(looper);
630 }
631
fredc0f420372012-04-12 00:02:00 -0700632 @Override
633 public void handleMessage(Message msg) {
634 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700635 switch (msg.what) {
636 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700637 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700638 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700639 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -0700640 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -0700641 if (DBG) Log.d(TAG, "Binding to service to get name and address");
642 mConnection.setGetNameAddressOnly(true);
643 //Start bind timeout and bind
644 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
645 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
646 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackborn221ea892013-08-04 16:50:16 -0700647 if (!doBind(i, mConnection,
648 Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700649 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -0700650 } else {
651 mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700652 }
653 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700654 else {
655 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -0700656 saveMsg.arg1 = 0;
657 if (mBluetooth != null) {
658 mHandler.sendMessage(saveMsg);
659 } else {
660 // if enable is also called to bind the service
661 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
662 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
663 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700664 }
fredc0f420372012-04-12 00:02:00 -0700665 }
fredc649fe492012-04-19 01:07:18 -0700666 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700667 }
fredc0f420372012-04-12 00:02:00 -0700668 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -0700669 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -0700670 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700671 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700672 if (!mEnable && mBluetooth != null) {
673 try {
674 mBluetooth.enable();
675 } catch (RemoteException e) {
676 Log.e(TAG,"Unable to call enable()",e);
677 }
678 }
679 }
680 if (mBluetooth != null) waitForOnOff(true, false);
681 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700682 if (mBluetooth != null) {
683 String name = null;
684 String address = null;
685 try {
686 name = mBluetooth.getName();
687 address = mBluetooth.getAddress();
688 } catch (RemoteException re) {
689 Log.e(TAG,"",re);
690 }
fredc0f420372012-04-12 00:02:00 -0700691
Matthew Xiecdce0b92012-07-12 19:06:15 -0700692 if (name != null && address != null) {
693 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -0700694 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700695 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700696 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700697 } else {
698 if (msg.arg1 < MAX_SAVE_RETRIES) {
699 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
700 retryMsg.arg1= 1+msg.arg1;
701 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
702 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
703 } else {
704 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -0700705 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700706 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700707 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700708 }
fredc0f420372012-04-12 00:02:00 -0700709 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700710 if (!mEnable) {
711 try {
712 mBluetooth.disable();
713 } catch (RemoteException e) {
714 Log.e(TAG,"Unable to call disable()",e);
715 }
716 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700717 } else {
718 // rebind service by Request GET NAME AND ADDRESS
719 // if service is unbinded by disable or
720 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
721 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
722 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -0700723 }
724 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700725 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
726 if (unbind) {
727 unbindAndFinish();
728 }
fredc649fe492012-04-19 01:07:18 -0700729 break;
fredc649fe492012-04-19 01:07:18 -0700730 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700731 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700732 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700733 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700734 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700735 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
736 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800737 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -0700738 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700739
fredc0f420372012-04-12 00:02:00 -0700740 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -0700741 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
742 if (mEnable && mBluetooth != null) {
743 waitForOnOff(true, false);
744 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800745 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700746 waitForOnOff(false, false);
747 } else {
748 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800749 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700750 }
fredc0f420372012-04-12 00:02:00 -0700751 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700752
fredc0f420372012-04-12 00:02:00 -0700753 case MESSAGE_REGISTER_ADAPTER:
754 {
755 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700756 boolean added = mCallbacks.register(callback);
757 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700758 }
759 break;
760 case MESSAGE_UNREGISTER_ADAPTER:
761 {
762 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700763 boolean removed = mCallbacks.unregister(callback);
764 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700765 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700766 }
fredc0f420372012-04-12 00:02:00 -0700767 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
768 {
769 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -0700770 if (callback != null) {
771 mStateChangeCallbacks.register(callback);
772 }
fredc0f420372012-04-12 00:02:00 -0700773 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700774 }
fredc0f420372012-04-12 00:02:00 -0700775 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
776 {
777 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -0700778 if (callback != null) {
779 mStateChangeCallbacks.unregister(callback);
780 }
fredc0f420372012-04-12 00:02:00 -0700781 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700782 }
fredc0f420372012-04-12 00:02:00 -0700783 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
784 {
Matthew Xieddf7e472013-03-01 18:41:02 -0800785 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
fredc0f420372012-04-12 00:02:00 -0700786
787 IBinder service = (IBinder) msg.obj;
788 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800789 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
790 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
791 break;
792 } // else must be SERVICE_IBLUETOOTH
793
794 //Remove timeout
Zhihai Xuaf5971e2013-06-10 20:28:31 -0700795 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Matthew Xieddf7e472013-03-01 18:41:02 -0800796
fredc0f420372012-04-12 00:02:00 -0700797 mBinding = false;
798 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700799
Zhihai Xuaf5971e2013-06-10 20:28:31 -0700800 try {
801 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
802 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
803 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
804 Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
805 }
806 } catch (RemoteException e) {
807 Log.e(TAG,"Unable to call configHciSnoopLog", e);
808 }
809
Matthew Xiecdce0b92012-07-12 19:06:15 -0700810 if (mConnection.isGetNameAddressOnly()) {
811 //Request GET NAME AND ADDRESS
812 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
813 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -0700814 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700815 }
fredc0f420372012-04-12 00:02:00 -0700816
Zhihai Xu40874a02012-10-08 17:57:03 -0700817 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700818 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700819 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700820 mBluetooth.registerCallback(mBluetoothCallback);
821 } catch (RemoteException re) {
822 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700823 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700824 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -0700825 sendBluetoothServiceUpCallback();
826
Matthew Xiecdce0b92012-07-12 19:06:15 -0700827 //Do enable request
828 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700829 if (mQuietEnable == false) {
830 if(!mBluetooth.enable()) {
831 Log.e(TAG,"IBluetooth.enable() returned false");
832 }
833 }
834 else
835 {
836 if(!mBluetooth.enableNoAutoConnect()) {
837 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
838 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700839 }
840 } catch (RemoteException e) {
841 Log.e(TAG,"Unable to call enable()",e);
842 }
Freda8c6df02012-07-11 10:25:23 -0700843 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700844
845 if (!mEnable) {
846 waitForOnOff(true, false);
Zhihai Xu401202b2012-12-03 11:36:21 -0800847 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700848 waitForOnOff(false, false);
849 }
fredc649fe492012-04-19 01:07:18 -0700850 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700851 }
fredc649fe492012-04-19 01:07:18 -0700852 case MESSAGE_TIMEOUT_BIND: {
853 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700854 synchronized(mConnection) {
855 mBinding = false;
856 }
fredc649fe492012-04-19 01:07:18 -0700857 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700858 }
fredcbf072a72012-05-09 16:52:50 -0700859 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700860 {
fredcbf072a72012-05-09 16:52:50 -0700861 int prevState = msg.arg1;
862 int newState = msg.arg2;
863 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -0700864 mState = newState;
865 bluetoothStateChangeHandler(prevState, newState);
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800866 // handle error state transition case from TURNING_ON to OFF
867 // unbind and rebind bluetooth service and enable bluetooth
868 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
869 (newState == BluetoothAdapter.STATE_OFF) &&
870 (mBluetooth != null) && mEnable) {
871 recoverBluetoothServiceFromError();
872 }
873 if (newState == BluetoothAdapter.STATE_ON) {
874 // bluetooth is working, reset the counter
875 if (mErrorRecoveryRetryCounter != 0) {
876 Log.w(TAG, "bluetooth is recovered from error");
877 mErrorRecoveryRetryCounter = 0;
878 }
879 }
fredc649fe492012-04-19 01:07:18 -0700880 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700881 }
fredc0f420372012-04-12 00:02:00 -0700882 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
883 {
Matthew Xieddf7e472013-03-01 18:41:02 -0800884 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530885 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800886 if (msg.arg1 == SERVICE_IBLUETOOTH) {
887 // if service is unbinded already, do nothing and return
888 if (mBluetooth == null) break;
889 mBluetooth = null;
890 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
891 mBluetoothGatt = null;
892 break;
893 } else {
894 Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
895 break;
896 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530897 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700898
899 if (mEnable) {
900 mEnable = false;
901 // Send a Bluetooth Restart message
902 Message restartMsg = mHandler.obtainMessage(
903 MESSAGE_RESTART_BLUETOOTH_SERVICE);
904 mHandler.sendMessageDelayed(restartMsg,
905 SERVICE_RESTART_TIME_MS);
906 }
907
908 if (!mConnection.isGetNameAddressOnly()) {
909 sendBluetoothServiceDownCallback();
910
911 // Send BT state broadcast to update
912 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800913 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
914 (mState == BluetoothAdapter.STATE_ON)) {
915 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
916 BluetoothAdapter.STATE_TURNING_OFF);
917 mState = BluetoothAdapter.STATE_TURNING_OFF;
918 }
919 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
920 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
921 BluetoothAdapter.STATE_OFF);
922 }
923
924 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -0700925 mState = BluetoothAdapter.STATE_OFF;
926 }
fredc649fe492012-04-19 01:07:18 -0700927 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700928 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530929 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
930 {
931 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
932 +" Restart IBluetooth service");
933 /* Enable without persisting the setting as
934 it doesnt change when IBluetooth
935 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -0700936 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800937 handleEnable(mQuietEnable);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530938 break;
939 }
940
fredc0f420372012-04-12 00:02:00 -0700941 case MESSAGE_TIMEOUT_UNBIND:
942 {
fredc649fe492012-04-19 01:07:18 -0700943 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700944 synchronized(mConnection) {
945 mUnbinding = false;
946 }
fredc649fe492012-04-19 01:07:18 -0700947 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700948 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700949
950 case MESSAGE_USER_SWITCHED:
951 {
952 if (DBG) {
953 Log.d(TAG, "MESSAGE_USER_SWITCHED");
954 }
955 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
956 /* disable and enable BT when detect a user switch */
957 if (mEnable && mBluetooth != null) {
958 synchronized (mConnection) {
959 if (mBluetooth != null) {
960 //Unregister callback object
961 try {
962 mBluetooth.unregisterCallback(mBluetoothCallback);
963 } catch (RemoteException re) {
964 Log.e(TAG, "Unable to unregister",re);
965 }
966 }
967 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800968
969 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
970 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
971 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
972 mState = BluetoothAdapter.STATE_OFF;
973 }
974 if (mState == BluetoothAdapter.STATE_OFF) {
975 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
976 mState = BluetoothAdapter.STATE_TURNING_ON;
977 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700978
979 waitForOnOff(true, false);
980
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800981 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
982 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
983 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700984
985 // disable
Zhihai Xu401202b2012-12-03 11:36:21 -0800986 handleDisable();
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800987 // Pbap service need receive STATE_TURNING_OFF intent to close
988 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
989 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700990
991 waitForOnOff(false, true);
992
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800993 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -0700994 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700995 sendBluetoothServiceDownCallback();
996 synchronized (mConnection) {
997 if (mBluetooth != null) {
998 mBluetooth = null;
999 //Unbind
1000 mContext.unbindService(mConnection);
1001 }
1002 }
1003 SystemClock.sleep(100);
1004
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001005 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1006 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -07001007 // enable
Zhihai Xu401202b2012-12-03 11:36:21 -08001008 handleEnable(mQuietEnable);
John Spurlock8a985d22014-02-25 09:40:05 -05001009 } else if (mBinding || mBluetooth != null) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001010 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1011 userMsg.arg2 = 1 + msg.arg2;
1012 // if user is switched when service is being binding
1013 // delay sending MESSAGE_USER_SWITCHED
1014 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1015 if (DBG) {
1016 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1017 }
John Spurlock8a985d22014-02-25 09:40:05 -05001018 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001019 break;
1020 }
fredc0f420372012-04-12 00:02:00 -07001021 }
1022 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001023 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001024
Zhihai Xu401202b2012-12-03 11:36:21 -08001025 private void handleEnable(boolean quietMode) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001026 mQuietEnable = quietMode;
1027
Matthew Xiecdce0b92012-07-12 19:06:15 -07001028 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001029 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001030 //Start bind timeout and bind
1031 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1032 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1033 mConnection.setGetNameAddressOnly(false);
1034 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackborn221ea892013-08-04 16:50:16 -07001035 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001036 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -07001037 } else {
1038 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001039 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001040 } else if (mBluetooth != null) {
1041 if (mConnection.isGetNameAddressOnly()) {
1042 // if GetNameAddressOnly is set, we can clear this flag,
1043 // so the service won't be unbind
1044 // after name and address are saved
1045 mConnection.setGetNameAddressOnly(false);
1046 //Register callback object
1047 try {
1048 mBluetooth.registerCallback(mBluetoothCallback);
1049 } catch (RemoteException re) {
1050 Log.e(TAG, "Unable to register BluetoothCallback",re);
1051 }
1052 //Inform BluetoothAdapter instances that service is up
1053 sendBluetoothServiceUpCallback();
1054 }
1055
Matthew Xiecdce0b92012-07-12 19:06:15 -07001056 //Enable bluetooth
1057 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001058 if (!mQuietEnable) {
1059 if(!mBluetooth.enable()) {
1060 Log.e(TAG,"IBluetooth.enable() returned false");
1061 }
1062 }
1063 else {
1064 if(!mBluetooth.enableNoAutoConnect()) {
1065 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1066 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001067 }
1068 } catch (RemoteException e) {
1069 Log.e(TAG,"Unable to call enable()",e);
1070 }
1071 }
1072 }
1073 }
1074
Dianne Hackborn221ea892013-08-04 16:50:16 -07001075 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1076 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1077 intent.setComponent(comp);
1078 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1079 Log.e(TAG, "Fail to bind to: " + intent);
1080 return false;
1081 }
1082 return true;
1083 }
1084
Zhihai Xu401202b2012-12-03 11:36:21 -08001085 private void handleDisable() {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001086 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001087 // don't need to disable if GetNameAddressOnly is set,
1088 // service will be unbinded after Name and Address are saved
1089 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001090 if (DBG) Log.d(TAG,"Sending off request.");
1091
1092 try {
1093 if(!mBluetooth.disable()) {
1094 Log.e(TAG,"IBluetooth.disable() returned false");
1095 }
1096 } catch (RemoteException e) {
1097 Log.e(TAG,"Unable to call disable()",e);
1098 }
1099 }
1100 }
1101 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001102
1103 private boolean checkIfCallerIsForegroundUser() {
1104 int foregroundUser;
1105 int callingUser = UserHandle.getCallingUserId();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001106 int callingUid = Binder.getCallingUid();
Zhihai Xu40874a02012-10-08 17:57:03 -07001107 long callingIdentity = Binder.clearCallingIdentity();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001108 int callingAppId = UserHandle.getAppId(callingUid);
Zhihai Xu40874a02012-10-08 17:57:03 -07001109 boolean valid = false;
1110 try {
1111 foregroundUser = ActivityManager.getCurrentUser();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001112 valid = (callingUser == foregroundUser) ||
1113 callingAppId == Process.NFC_UID;
Zhihai Xu40874a02012-10-08 17:57:03 -07001114 if (DBG) {
1115 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1116 + " callingUser=" + callingUser
1117 + " foregroundUser=" + foregroundUser);
1118 }
1119 } finally {
1120 Binder.restoreCallingIdentity(callingIdentity);
1121 }
1122 return valid;
1123 }
1124
Zhihai Xu40874a02012-10-08 17:57:03 -07001125 private void bluetoothStateChangeHandler(int prevState, int newState) {
1126 if (prevState != newState) {
1127 //Notify all proxy objects first of adapter state change
1128 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
1129 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1130 sendBluetoothStateCallback(isUp);
1131
Matthew Xieddf7e472013-03-01 18:41:02 -08001132 if (isUp) {
1133 // connect to GattService
Matthew Xie32ab77b2013-05-08 19:26:57 -07001134 if (mContext.getPackageManager().hasSystemFeature(
1135 PackageManager.FEATURE_BLUETOOTH_LE)) {
1136 Intent i = new Intent(IBluetoothGatt.class.getName());
Dianne Hackborn221ea892013-08-04 16:50:16 -07001137 doBind(i, mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
Matthew Xieddf7e472013-03-01 18:41:02 -08001138 }
1139 } else {
1140 //If Bluetooth is off, send service down event to proxy objects, and unbind
1141 if (!isUp && canUnbindBluetoothService()) {
1142 sendBluetoothServiceDownCallback();
1143 unbindAndFinish();
1144 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001145 }
1146 }
1147
1148 //Send broadcast message to everyone else
1149 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1150 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1151 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1152 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1153 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
1154 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1155 BLUETOOTH_PERM);
1156 }
1157 }
1158
1159 /**
1160 * if on is true, wait for state become ON
1161 * if off is true, wait for state become OFF
1162 * if both on and off are false, wait for state not ON
1163 */
1164 private boolean waitForOnOff(boolean on, boolean off) {
1165 int i = 0;
1166 while (i < 10) {
1167 synchronized(mConnection) {
1168 try {
1169 if (mBluetooth == null) break;
1170 if (on) {
1171 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1172 } else if (off) {
1173 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001174 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001175 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001176 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001177 } catch (RemoteException e) {
1178 Log.e(TAG, "getState()", e);
1179 break;
1180 }
1181 }
1182 if (on || off) {
1183 SystemClock.sleep(300);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001184 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001185 SystemClock.sleep(50);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001186 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001187 i++;
1188 }
1189 Log.e(TAG,"waitForOnOff time out");
1190 return false;
1191 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001192
Zhihai Xu401202b2012-12-03 11:36:21 -08001193 private void sendDisableMsg() {
1194 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1195 }
1196
1197 private void sendEnableMsg(boolean quietMode) {
1198 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1199 quietMode ? 1 : 0, 0));
1200 }
1201
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001202 private boolean canUnbindBluetoothService() {
1203 synchronized(mConnection) {
1204 //Only unbind with mEnable flag not set
1205 //For race condition: disable and enable back-to-back
1206 //Avoid unbind right after enable due to callback from disable
1207 //Only unbind with Bluetooth at OFF state
1208 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1209 try {
1210 if (mEnable || (mBluetooth == null)) return false;
1211 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1212 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1213 } catch (RemoteException e) {
1214 Log.e(TAG, "getState()", e);
1215 }
1216 }
1217 return false;
1218 }
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001219
1220 private void recoverBluetoothServiceFromError() {
1221 Log.e(TAG,"recoverBluetoothServiceFromError");
1222 synchronized (mConnection) {
1223 if (mBluetooth != null) {
1224 //Unregister callback object
1225 try {
1226 mBluetooth.unregisterCallback(mBluetoothCallback);
1227 } catch (RemoteException re) {
1228 Log.e(TAG, "Unable to unregister",re);
1229 }
1230 }
1231 }
1232
1233 SystemClock.sleep(500);
1234
1235 // disable
1236 handleDisable();
1237
1238 waitForOnOff(false, true);
1239
1240 sendBluetoothServiceDownCallback();
1241 synchronized (mConnection) {
1242 if (mBluetooth != null) {
1243 mBluetooth = null;
1244 //Unbind
1245 mContext.unbindService(mConnection);
1246 }
1247 }
1248
1249 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1250 mState = BluetoothAdapter.STATE_OFF;
1251
1252 mEnable = false;
1253
1254 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1255 // Send a Bluetooth Restart message to reenable bluetooth
1256 Message restartMsg = mHandler.obtainMessage(
1257 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1258 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1259 } else {
1260 // todo: notify user to power down and power up phone to make bluetooth work.
1261 }
1262 }
fredc0f420372012-04-12 00:02:00 -07001263}