blob: 4b430707a7710f60c25c506e41e7bcebc5432367 [file] [log] [blame]
fredc0f420372012-04-12 00:02:00 -07001/*
2 * Copyright (C) 2012 Google Inc.
3 */
4
5package com.android.server;
6
7import android.bluetooth.BluetoothAdapter;
8import android.bluetooth.IBluetooth;
fredcbf072a72012-05-09 16:52:50 -07009import android.bluetooth.IBluetoothCallback;
fredc0f420372012-04-12 00:02:00 -070010import android.bluetooth.IBluetoothManager;
11import android.bluetooth.IBluetoothManagerCallback;
12import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070013import android.content.BroadcastReceiver;
14import android.content.ComponentName;
15import android.content.ContentResolver;
16import android.content.Context;
17import android.content.Intent;
18import android.content.IntentFilter;
19import android.content.ServiceConnection;
20import android.os.Handler;
fredc0f420372012-04-12 00:02:00 -070021import android.os.IBinder;
22import android.os.Message;
fredcd6883532012-04-25 17:46:13 -070023import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070024import android.os.RemoteException;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -070025import android.os.Binder;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070026import android.os.UserHandle;
fredc0f420372012-04-12 00:02:00 -070027import android.provider.Settings;
28import android.util.Log;
29import java.util.List;
30import java.util.ArrayList;
fredc0f420372012-04-12 00:02:00 -070031class BluetoothManagerService extends IBluetoothManager.Stub {
32 private static final String TAG = "BluetoothManagerService";
33 private static final boolean DBG = true;
34
fredc0f420372012-04-12 00:02:00 -070035 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
36 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070037 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
38 private static final String EXTRA_ACTION="action";
fredc0f420372012-04-12 00:02:00 -070039 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
40 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070041 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
42 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
43
44 private static final int MESSAGE_ENABLE = 1;
45 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070046 private static final int MESSAGE_REGISTER_ADAPTER = 20;
47 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
48 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
49 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
50 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
51 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
fredcbf072a72012-05-09 16:52:50 -070052 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070053 private static final int MESSAGE_TIMEOUT_BIND =100;
54 private static final int MESSAGE_TIMEOUT_UNBIND =101;
55 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
56 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
57 private static final int MAX_SAVE_RETRIES=3;
58
59 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070060
61 // Locks are not provided for mName and mAddress.
62 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070063 private String mAddress;
64 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -070065 private final ContentResolver mContentResolver;
66 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
67 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070068 private IBluetooth mBluetooth;
69 private boolean mBinding;
70 private boolean mUnbinding;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -070071 private boolean mQuietEnable = false;
fredc0f420372012-04-12 00:02:00 -070072
fredc649fe492012-04-19 01:07:18 -070073 private void registerForAirplaneMode(IntentFilter filter) {
74 final ContentResolver resolver = mContext.getContentResolver();
75 final String airplaneModeRadios = Settings.System.getString(resolver,
76 Settings.System.AIRPLANE_MODE_RADIOS);
77 final String toggleableRadios = Settings.System.getString(resolver,
78 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
79 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
80 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
81 if (mIsAirplaneSensitive) {
82 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
83 }
84 }
85
fredcbf072a72012-05-09 16:52:50 -070086 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
87 @Override
88 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
89 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
90 mHandler.sendMessage(msg);
91 }
92 };
93
94 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -070095 @Override
96 public void onReceive(Context context, Intent intent) {
97 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -070098 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -070099 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700100 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700101 if (newName != null) {
102 storeNameAndAddress(newName, null);
103 }
fredc649fe492012-04-19 01:07:18 -0700104 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
105 if (isAirplaneModeOn()) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700106 // disable without persisting the setting
107 handleDisable(false);
fredc649fe492012-04-19 01:07:18 -0700108 } else {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700109 if (isBluetoothPersistedStateOn()) {
110 // enable without persisting the setting
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700111 handleEnable(false, false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700112 }
fredc649fe492012-04-19 01:07:18 -0700113 }
fredc0f420372012-04-12 00:02:00 -0700114 }
115 }
116 };
117
118 BluetoothManagerService(Context context) {
119 mContext = context;
120 mBluetooth = null;
121 mBinding = false;
122 mUnbinding = false;
123 mAddress = null;
124 mName = null;
125 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700126 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
127 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Matthew Xie6fde3092012-07-11 17:10:07 -0700128 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
129 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
130 registerForAirplaneMode(filter);
131 mContext.registerReceiver(mReceiver, filter);
fredc649fe492012-04-19 01:07:18 -0700132 boolean airplaneModeOn = isAirplaneModeOn();
133 boolean bluetoothOn = isBluetoothPersistedStateOn();
fredc0f420372012-04-12 00:02:00 -0700134 loadStoredNameAndAddress();
fredc649fe492012-04-19 01:07:18 -0700135 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
Andre Eisenbacha732ffd2012-05-02 00:39:24 -0700136 if (bluetoothOn) {
fredc0f420372012-04-12 00:02:00 -0700137 //Enable
fredc649fe492012-04-19 01:07:18 -0700138 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
fredc0f420372012-04-12 00:02:00 -0700139 enable();
Freda8c6df02012-07-11 10:25:23 -0700140 } else if (!isNameAndAddressSet()) {
fredc649fe492012-04-19 01:07:18 -0700141 //Sync the Bluetooth name and address from the Bluetooth Adapter
142 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
fredc0f420372012-04-12 00:02:00 -0700143 getNameAndAddress();
144 }
145 }
146
fredc649fe492012-04-19 01:07:18 -0700147 /**
148 * Returns true if airplane mode is currently on
149 */
150 private final boolean isAirplaneModeOn() {
151 return Settings.System.getInt(mContext.getContentResolver(),
152 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
153 }
154
155 /**
156 * Returns true if the Bluetooth saved state is "on"
157 */
158 private final boolean isBluetoothPersistedStateOn() {
159 return Settings.Secure.getInt(mContentResolver,
160 Settings.Secure.BLUETOOTH_ON, 0) ==1;
161 }
162
163 /**
164 * Save the Bluetooth on/off state
165 *
166 */
167 private void persistBluetoothSetting(boolean setOn) {
168 Settings.Secure.putInt(mContext.getContentResolver(),
169 Settings.Secure.BLUETOOTH_ON,
170 setOn ? 1 : 0);
171 }
172
173 /**
174 * Returns true if the Bluetooth Adapter's name and address is
175 * locally cached
176 * @return
177 */
fredc0f420372012-04-12 00:02:00 -0700178 private boolean isNameAndAddressSet() {
179 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
180 }
181
fredc649fe492012-04-19 01:07:18 -0700182 /**
183 * Retrieve the Bluetooth Adapter's name and address and save it in
184 * in the local cache
185 */
fredc0f420372012-04-12 00:02:00 -0700186 private void loadStoredNameAndAddress() {
187 if (DBG) Log.d(TAG, "Loading stored name and address");
188 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
189 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
190 if (mName == null || mAddress == null) {
191 if (DBG) Log.d(TAG, "Name or address not cached...");
192 }
193 }
194
fredc649fe492012-04-19 01:07:18 -0700195 /**
196 * Save the Bluetooth name and address in the persistent store.
197 * Only non-null values will be saved.
198 * @param name
199 * @param address
200 */
fredc0f420372012-04-12 00:02:00 -0700201 private void storeNameAndAddress(String name, String address) {
202 if (name != null) {
203 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700204 mName = name;
fredc649fe492012-04-19 01:07:18 -0700205 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
206 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700207 }
208
209 if (address != null) {
210 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700211 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700212 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
213 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700214 }
215 }
216
217 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
218 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
219 "Need BLUETOOTH permission");
220 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
221 msg.obj = callback;
222 mHandler.sendMessage(msg);
223 synchronized(mConnection) {
224 return mBluetooth;
225 }
226 }
227
228 public void unregisterAdapter(IBluetoothManagerCallback callback) {
229 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
230 "Need BLUETOOTH permission");
231 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
232 msg.obj = callback;
233 mHandler.sendMessage(msg);
234 }
235
236 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
237 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
238 "Need BLUETOOTH permission");
239 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
240 msg.obj = callback;
241 mHandler.sendMessage(msg);
242 }
243
244 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
245 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
246 "Need BLUETOOTH permission");
247 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
248 msg.obj = callback;
249 mHandler.sendMessage(msg);
250 }
251
252 public boolean isEnabled() {
253 synchronized(mConnection) {
254 try {
255 return (mBluetooth != null && mBluetooth.isEnabled());
256 } catch (RemoteException e) {
257 Log.e(TAG, "isEnabled()", e);
258 }
259 }
260 return false;
261 }
262
263 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700264 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700265 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
266 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700267 }
fredc0f420372012-04-12 00:02:00 -0700268 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700269 if (mBinding) return;
270 if (mConnection == null) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700271 }
272 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
273 mHandler.sendMessage(msg);
274 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700275 public boolean enableNoAutoConnect()
276 {
277 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
278 "Need BLUETOOTH ADMIN permission");
279 if (DBG) {
280 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
281 " mBinding = " + mBinding);
282 }
283 if (Binder.getCallingUid() != android.os.Process.NFC_UID) {
284 throw new SecurityException("no permission to enable Bluetooth quietly");
285 }
286 synchronized(mConnection) {
287 if (mBinding) {
288 Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning..");
289 return true;
290 }
291 if (mConnection == null) mBinding = true;
292 }
fredc0f420372012-04-12 00:02:00 -0700293
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700294 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
295 msg.arg1=0; //No persist
296 msg.arg2=1; //Quiet mode
297 mHandler.sendMessage(msg);
298 return true;
299
300 }
fredc0f420372012-04-12 00:02:00 -0700301 public boolean enable() {
302 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
303 "Need BLUETOOTH ADMIN permission");
fredcf2458862012-04-16 15:18:27 -0700304 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700305 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
306 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700307 }
308
fredc0f420372012-04-12 00:02:00 -0700309 synchronized(mConnection) {
fredc649fe492012-04-19 01:07:18 -0700310 if (mBinding) {
311 Log.w(TAG,"enable(): binding in progress. Returning..");
312 return true;
313 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700314 if (mConnection == null) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700315 }
fredc116d1d462012-04-20 14:47:08 -0700316
fredc0f420372012-04-12 00:02:00 -0700317 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
fredc649fe492012-04-19 01:07:18 -0700318 msg.arg1=1; //persist
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700319 msg.arg2=0; //No Quiet Mode
fredc0f420372012-04-12 00:02:00 -0700320 mHandler.sendMessage(msg);
321 return true;
322 }
323
324 public boolean disable(boolean persist) {
325 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
326 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
fredcf2458862012-04-16 15:18:27 -0700327 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700328 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
329 " mBinding = " + mBinding);
330 }
fredcf2458862012-04-16 15:18:27 -0700331
fredc0f420372012-04-12 00:02:00 -0700332 synchronized(mConnection) {
333 if (mBluetooth == null) return false;
fredc0f420372012-04-12 00:02:00 -0700334 }
335 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700336 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700337 mHandler.sendMessage(msg);
338 return true;
339 }
340
fredc649fe492012-04-19 01:07:18 -0700341 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700342 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700343 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
344 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700345 }
346
fredc0f420372012-04-12 00:02:00 -0700347 synchronized (mConnection) {
348 if (mUnbinding) return;
349 mUnbinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700350 if (mConnection != null) {
fredcbf072a72012-05-09 16:52:50 -0700351 if (!mConnection.isGetNameAddressOnly()) {
352 //Unregister callback object
353 try {
354 mBluetooth.unregisterCallback(mBluetoothCallback);
355 } catch (RemoteException re) {
356 Log.e(TAG, "Unable to register BluetoothCallback",re);
357 }
358 }
fredc0f420372012-04-12 00:02:00 -0700359 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700360 mBluetooth = null;
361 //Unbind
fredc0f420372012-04-12 00:02:00 -0700362 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700363 mUnbinding = false;
fredcf2458862012-04-16 15:18:27 -0700364 } else {
365 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700366 }
367 }
368 }
369
fredcbf072a72012-05-09 16:52:50 -0700370 private void sendBluetoothStateCallback(boolean isUp) {
371 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700372 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700373 for (int i=0; i <n;i++) {
374 try {
375 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
376 } catch (RemoteException e) {
377 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
378 }
379 }
380 mStateChangeCallbacks.finishBroadcast();
381 }
382
383 /**
384 * Inform BluetoothAdapter instances that Adapter service is down
385 */
386 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700387 if (!mConnection.isGetNameAddressOnly()) {
388 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
389 int n = mCallbacks.beginBroadcast();
390 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
391 for (int i=0; i <n;i++) {
392 try {
393 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
394 } catch (RemoteException e) {
395 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
396 }
397 }
398 mCallbacks.finishBroadcast();
399 }
400 }
fredc0f420372012-04-12 00:02:00 -0700401 public String getAddress() {
402 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
403 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700404 synchronized(mConnection) {
405 if (mBluetooth != null) {
406 try {
407 return mBluetooth.getAddress();
408 } catch (RemoteException e) {
409 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
410 }
411 }
412 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700413 // mAddress is accessed from outside.
414 // It is alright without a lock. Here, bluetooth is off, no other thread is
415 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700416 return mAddress;
417 }
fredc649fe492012-04-19 01:07:18 -0700418
fredc0f420372012-04-12 00:02:00 -0700419 public String getName() {
420 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
421 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700422 synchronized(mConnection) {
423 if (mBluetooth != null) {
424 try {
425 return mBluetooth.getName();
426 } catch (RemoteException e) {
427 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
428 }
429 }
430 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700431 // mName is accessed from outside.
432 // It alright without a lock. Here, bluetooth is off, no other thread is
433 // changing mName
fredc0f420372012-04-12 00:02:00 -0700434 return mName;
435 }
436
fredc0f420372012-04-12 00:02:00 -0700437 private class BluetoothServiceConnection implements ServiceConnection {
438
439 private boolean mGetNameAddressOnly;
440
441 public void setGetNameAddressOnly(boolean getOnly) {
442 mGetNameAddressOnly = getOnly;
443 }
444
445 public boolean isGetNameAddressOnly() {
446 return mGetNameAddressOnly;
447 }
448
449 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700450 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700451 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
452 msg.obj = service;
453 mHandler.sendMessage(msg);
454 }
455
456 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700457 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700458 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700459 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
460 mHandler.sendMessage(msg);
461 }
462 }
463
464 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
465
466 private final Handler mHandler = new Handler() {
467 @Override
468 public void handleMessage(Message msg) {
469 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700470 switch (msg.what) {
471 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700472 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700473 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700474 //Start bind request
Matthew Xiecdce0b92012-07-12 19:06:15 -0700475 if (mBluetooth == null) {
fredc0f420372012-04-12 00:02:00 -0700476 if (DBG) Log.d(TAG, "Binding to service to get name and address");
477 mConnection.setGetNameAddressOnly(true);
478 //Start bind timeout and bind
479 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
480 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
481 Intent i = new Intent(IBluetooth.class.getName());
482 if (!mContext.bindService(i, mConnection,
483 Context.BIND_AUTO_CREATE)) {
484 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
485 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
486 }
487 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700488 else {
489 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
490 mHandler.sendMessage(saveMsg);
491 }
fredc0f420372012-04-12 00:02:00 -0700492 }
fredc649fe492012-04-19 01:07:18 -0700493 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700494 }
fredc0f420372012-04-12 00:02:00 -0700495 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700496 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700497 synchronized(mConnection) {
498 if (mBluetooth != null) {
499 String name = null;
500 String address = null;
501 try {
502 name = mBluetooth.getName();
503 address = mBluetooth.getAddress();
504 } catch (RemoteException re) {
505 Log.e(TAG,"",re);
506 }
fredc0f420372012-04-12 00:02:00 -0700507
Matthew Xiecdce0b92012-07-12 19:06:15 -0700508 if (name != null && address != null) {
509 storeNameAndAddress(name,address);
fredcbf072a72012-05-09 16:52:50 -0700510 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700511 unbindAndFinish();
Matthew Xiecdce0b92012-07-12 19:06:15 -0700512 } else {
513 if (msg.arg1 < MAX_SAVE_RETRIES) {
514 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
515 retryMsg.arg1= 1+msg.arg1;
516 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
517 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
518 } else {
519 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
520 sendBluetoothServiceDownCallback();
521 unbindAndFinish();
522 }
fredc0f420372012-04-12 00:02:00 -0700523 }
524 }
525 }
fredc649fe492012-04-19 01:07:18 -0700526 break;
fredc649fe492012-04-19 01:07:18 -0700527 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700528 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700529 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700530 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700531 }
Freda8c6df02012-07-11 10:25:23 -0700532
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700533 handleEnable(msg.arg1 == 1, msg.arg2 ==1);
fredc649fe492012-04-19 01:07:18 -0700534 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700535
fredc0f420372012-04-12 00:02:00 -0700536 case MESSAGE_DISABLE:
Matthew Xiecdce0b92012-07-12 19:06:15 -0700537 handleDisable(msg.arg1 == 1);
fredc0f420372012-04-12 00:02:00 -0700538 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700539
fredc0f420372012-04-12 00:02:00 -0700540 case MESSAGE_REGISTER_ADAPTER:
541 {
542 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700543 boolean added = mCallbacks.register(callback);
544 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700545 }
546 break;
547 case MESSAGE_UNREGISTER_ADAPTER:
548 {
549 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700550 boolean removed = mCallbacks.unregister(callback);
551 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700552 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700553 }
fredc0f420372012-04-12 00:02:00 -0700554 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
555 {
556 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700557 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700558 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700559 }
fredc0f420372012-04-12 00:02:00 -0700560 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
561 {
562 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700563 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700564 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700565 }
fredc0f420372012-04-12 00:02:00 -0700566 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
567 {
fredc649fe492012-04-19 01:07:18 -0700568 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
569
fredc0f420372012-04-12 00:02:00 -0700570 //Remove timeout
571 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
572
573 IBinder service = (IBinder) msg.obj;
574 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700575 mBinding = false;
576 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700577
Matthew Xiecdce0b92012-07-12 19:06:15 -0700578 if (mConnection.isGetNameAddressOnly()) {
579 //Request GET NAME AND ADDRESS
580 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
581 mHandler.sendMessage(getMsg);
582 return;
583 }
fredc0f420372012-04-12 00:02:00 -0700584
Matthew Xiecdce0b92012-07-12 19:06:15 -0700585 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700586 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700587 mBluetooth.registerCallback(mBluetoothCallback);
588 } catch (RemoteException re) {
589 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700590 }
fredcbf072a72012-05-09 16:52:50 -0700591
Matthew Xiecdce0b92012-07-12 19:06:15 -0700592 //Inform BluetoothAdapter instances that service is up
593 int n = mCallbacks.beginBroadcast();
594 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
595 for (int i=0; i <n;i++) {
596 try {
597 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
598 } catch (RemoteException e) {
599 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
600 }
Freda8c6df02012-07-11 10:25:23 -0700601 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700602 mCallbacks.finishBroadcast();
603
604 //Do enable request
605 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700606 if (mQuietEnable == false) {
607 if(!mBluetooth.enable()) {
608 Log.e(TAG,"IBluetooth.enable() returned false");
609 }
610 }
611 else
612 {
613 if(!mBluetooth.enableNoAutoConnect()) {
614 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
615 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700616 }
617 } catch (RemoteException e) {
618 Log.e(TAG,"Unable to call enable()",e);
619 }
Freda8c6df02012-07-11 10:25:23 -0700620 }
fredc649fe492012-04-19 01:07:18 -0700621 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700622 }
fredc649fe492012-04-19 01:07:18 -0700623 case MESSAGE_TIMEOUT_BIND: {
624 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700625 synchronized(mConnection) {
626 mBinding = false;
627 }
fredc649fe492012-04-19 01:07:18 -0700628 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700629 }
fredcbf072a72012-05-09 16:52:50 -0700630 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700631 {
fredcbf072a72012-05-09 16:52:50 -0700632 int prevState = msg.arg1;
633 int newState = msg.arg2;
634 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
635 if (prevState != newState) {
636 //Notify all proxy objects first of adapter state change
637 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
638 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
639 sendBluetoothStateCallback(isUp);
640
641 //If Bluetooth is off, send service down event to proxy objects, and unbind
642 if (!isUp) {
643 sendBluetoothServiceDownCallback();
644 unbindAndFinish();
645 }
fredc0f420372012-04-12 00:02:00 -0700646 }
fredcbf072a72012-05-09 16:52:50 -0700647
648 //Send broadcast message to everyone else
649 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
650 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
651 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
652 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
653 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700654 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
655 BLUETOOTH_PERM);
fredc0f420372012-04-12 00:02:00 -0700656 }
fredc649fe492012-04-19 01:07:18 -0700657 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700658 }
fredc0f420372012-04-12 00:02:00 -0700659 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
660 {
fredc649fe492012-04-19 01:07:18 -0700661 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredcbf072a72012-05-09 16:52:50 -0700662 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700663 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700664 }
fredc0f420372012-04-12 00:02:00 -0700665 case MESSAGE_TIMEOUT_UNBIND:
666 {
fredc649fe492012-04-19 01:07:18 -0700667 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700668 synchronized(mConnection) {
669 mUnbinding = false;
670 }
fredc649fe492012-04-19 01:07:18 -0700671 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700672 }
fredc0f420372012-04-12 00:02:00 -0700673 }
674 }
675 };
Matthew Xiecdce0b92012-07-12 19:06:15 -0700676
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700677 private void handleEnable(boolean persist, boolean quietMode) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700678 if (persist) {
679 persistBluetoothSetting(true);
680 }
681
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700682 mQuietEnable = quietMode;
683
Matthew Xiecdce0b92012-07-12 19:06:15 -0700684 synchronized(mConnection) {
685 if (mBluetooth == null) {
686 //Start bind timeout and bind
687 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
688 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
689 mConnection.setGetNameAddressOnly(false);
690 Intent i = new Intent(IBluetooth.class.getName());
691 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
692 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
693 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
694 }
695 } else {
696 //Check if name and address is loaded if not get it first.
697 if (!isNameAndAddressSet()) {
698 try {
699 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
700 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
701 } catch (RemoteException e) {Log.e(TAG, "", e);};
702 }
703
704 //Enable bluetooth
705 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700706 if (!mQuietEnable) {
707 if(!mBluetooth.enable()) {
708 Log.e(TAG,"IBluetooth.enable() returned false");
709 }
710 }
711 else {
712 if(!mBluetooth.enableNoAutoConnect()) {
713 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
714 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700715 }
716 } catch (RemoteException e) {
717 Log.e(TAG,"Unable to call enable()",e);
718 }
719 }
720 }
721 }
722
723 private void handleDisable(boolean persist) {
724 synchronized(mConnection) {
725 if (mBluetooth != null ) {
726 if (persist) {
727 persistBluetoothSetting(false);
728 }
729 mConnection.setGetNameAddressOnly(false);
730 if (DBG) Log.d(TAG,"Sending off request.");
731
732 try {
733 if(!mBluetooth.disable()) {
734 Log.e(TAG,"IBluetooth.disable() returned false");
735 }
736 } catch (RemoteException e) {
737 Log.e(TAG,"Unable to call disable()",e);
738 }
739 }
740 }
741 }
fredc0f420372012-04-12 00:02:00 -0700742}