blob: 4c98ac3d795288118e5be921e2f98cef79ea4501 [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;
fredc0f420372012-04-12 00:02:00 -070026import android.provider.Settings;
27import android.util.Log;
28import java.util.List;
29import java.util.ArrayList;
fredc0f420372012-04-12 00:02:00 -070030class BluetoothManagerService extends IBluetoothManager.Stub {
31 private static final String TAG = "BluetoothManagerService";
32 private static final boolean DBG = true;
33
fredc0f420372012-04-12 00:02:00 -070034 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
35 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070036 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
37 private static final String EXTRA_ACTION="action";
fredc0f420372012-04-12 00:02:00 -070038 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
39 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070040 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
41 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
42
43 private static final int MESSAGE_ENABLE = 1;
44 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070045 private static final int MESSAGE_REGISTER_ADAPTER = 20;
46 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
47 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
48 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
49 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
50 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
fredcbf072a72012-05-09 16:52:50 -070051 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070052 private static final int MESSAGE_TIMEOUT_BIND =100;
53 private static final int MESSAGE_TIMEOUT_UNBIND =101;
54 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
55 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
56 private static final int MAX_SAVE_RETRIES=3;
57
58 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070059
60 // Locks are not provided for mName and mAddress.
61 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070062 private String mAddress;
63 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -070064 private final ContentResolver mContentResolver;
65 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
66 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070067 private IBluetooth mBluetooth;
68 private boolean mBinding;
69 private boolean mUnbinding;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -070070 private boolean mQuietEnable = false;
fredc0f420372012-04-12 00:02:00 -070071
fredc649fe492012-04-19 01:07:18 -070072 private void registerForAirplaneMode(IntentFilter filter) {
73 final ContentResolver resolver = mContext.getContentResolver();
74 final String airplaneModeRadios = Settings.System.getString(resolver,
75 Settings.System.AIRPLANE_MODE_RADIOS);
76 final String toggleableRadios = Settings.System.getString(resolver,
77 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
78 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
79 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
80 if (mIsAirplaneSensitive) {
81 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
82 }
83 }
84
fredcbf072a72012-05-09 16:52:50 -070085 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
86 @Override
87 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
88 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
89 mHandler.sendMessage(msg);
90 }
91 };
92
93 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -070094 @Override
95 public void onReceive(Context context, Intent intent) {
96 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -070097 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -070098 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -070099 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700100 if (newName != null) {
101 storeNameAndAddress(newName, null);
102 }
fredc649fe492012-04-19 01:07:18 -0700103 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
104 if (isAirplaneModeOn()) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700105 // disable without persisting the setting
106 handleDisable(false);
fredc649fe492012-04-19 01:07:18 -0700107 } else {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700108 if (isBluetoothPersistedStateOn()) {
109 // enable without persisting the setting
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700110 handleEnable(false, false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700111 }
fredc649fe492012-04-19 01:07:18 -0700112 }
fredc0f420372012-04-12 00:02:00 -0700113 }
114 }
115 };
116
117 BluetoothManagerService(Context context) {
118 mContext = context;
119 mBluetooth = null;
120 mBinding = false;
121 mUnbinding = false;
122 mAddress = null;
123 mName = null;
124 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700125 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
126 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Matthew Xie6fde3092012-07-11 17:10:07 -0700127 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
128 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
129 registerForAirplaneMode(filter);
130 mContext.registerReceiver(mReceiver, filter);
fredc649fe492012-04-19 01:07:18 -0700131 boolean airplaneModeOn = isAirplaneModeOn();
132 boolean bluetoothOn = isBluetoothPersistedStateOn();
fredc0f420372012-04-12 00:02:00 -0700133 loadStoredNameAndAddress();
fredc649fe492012-04-19 01:07:18 -0700134 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
Andre Eisenbacha732ffd2012-05-02 00:39:24 -0700135 if (bluetoothOn) {
fredc0f420372012-04-12 00:02:00 -0700136 //Enable
fredc649fe492012-04-19 01:07:18 -0700137 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
fredc0f420372012-04-12 00:02:00 -0700138 enable();
Freda8c6df02012-07-11 10:25:23 -0700139 } else if (!isNameAndAddressSet()) {
fredc649fe492012-04-19 01:07:18 -0700140 //Sync the Bluetooth name and address from the Bluetooth Adapter
141 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
fredc0f420372012-04-12 00:02:00 -0700142 getNameAndAddress();
143 }
144 }
145
fredc649fe492012-04-19 01:07:18 -0700146 /**
147 * Returns true if airplane mode is currently on
148 */
149 private final boolean isAirplaneModeOn() {
150 return Settings.System.getInt(mContext.getContentResolver(),
151 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
152 }
153
154 /**
155 * Returns true if the Bluetooth saved state is "on"
156 */
157 private final boolean isBluetoothPersistedStateOn() {
158 return Settings.Secure.getInt(mContentResolver,
159 Settings.Secure.BLUETOOTH_ON, 0) ==1;
160 }
161
162 /**
163 * Save the Bluetooth on/off state
164 *
165 */
166 private void persistBluetoothSetting(boolean setOn) {
167 Settings.Secure.putInt(mContext.getContentResolver(),
168 Settings.Secure.BLUETOOTH_ON,
169 setOn ? 1 : 0);
170 }
171
172 /**
173 * Returns true if the Bluetooth Adapter's name and address is
174 * locally cached
175 * @return
176 */
fredc0f420372012-04-12 00:02:00 -0700177 private boolean isNameAndAddressSet() {
178 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
179 }
180
fredc649fe492012-04-19 01:07:18 -0700181 /**
182 * Retrieve the Bluetooth Adapter's name and address and save it in
183 * in the local cache
184 */
fredc0f420372012-04-12 00:02:00 -0700185 private void loadStoredNameAndAddress() {
186 if (DBG) Log.d(TAG, "Loading stored name and address");
187 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
188 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
189 if (mName == null || mAddress == null) {
190 if (DBG) Log.d(TAG, "Name or address not cached...");
191 }
192 }
193
fredc649fe492012-04-19 01:07:18 -0700194 /**
195 * Save the Bluetooth name and address in the persistent store.
196 * Only non-null values will be saved.
197 * @param name
198 * @param address
199 */
fredc0f420372012-04-12 00:02:00 -0700200 private void storeNameAndAddress(String name, String address) {
201 if (name != null) {
202 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700203 mName = name;
fredc649fe492012-04-19 01:07:18 -0700204 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
205 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700206 }
207
208 if (address != null) {
209 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700210 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700211 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
212 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700213 }
214 }
215
216 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
217 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
218 "Need BLUETOOTH permission");
219 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
220 msg.obj = callback;
221 mHandler.sendMessage(msg);
222 synchronized(mConnection) {
223 return mBluetooth;
224 }
225 }
226
227 public void unregisterAdapter(IBluetoothManagerCallback callback) {
228 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
229 "Need BLUETOOTH permission");
230 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
231 msg.obj = callback;
232 mHandler.sendMessage(msg);
233 }
234
235 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
236 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
237 "Need BLUETOOTH permission");
238 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
239 msg.obj = callback;
240 mHandler.sendMessage(msg);
241 }
242
243 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
244 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
245 "Need BLUETOOTH permission");
246 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
247 msg.obj = callback;
248 mHandler.sendMessage(msg);
249 }
250
251 public boolean isEnabled() {
252 synchronized(mConnection) {
253 try {
254 return (mBluetooth != null && mBluetooth.isEnabled());
255 } catch (RemoteException e) {
256 Log.e(TAG, "isEnabled()", e);
257 }
258 }
259 return false;
260 }
261
262 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700263 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700264 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
265 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700266 }
fredc0f420372012-04-12 00:02:00 -0700267 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700268 if (mBinding) return;
269 if (mConnection == null) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700270 }
271 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
272 mHandler.sendMessage(msg);
273 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700274 public boolean enableNoAutoConnect()
275 {
276 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
277 "Need BLUETOOTH ADMIN permission");
278 if (DBG) {
279 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
280 " mBinding = " + mBinding);
281 }
282 if (Binder.getCallingUid() != android.os.Process.NFC_UID) {
283 throw new SecurityException("no permission to enable Bluetooth quietly");
284 }
285 synchronized(mConnection) {
286 if (mBinding) {
287 Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning..");
288 return true;
289 }
290 if (mConnection == null) mBinding = true;
291 }
fredc0f420372012-04-12 00:02:00 -0700292
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700293 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
294 msg.arg1=0; //No persist
295 msg.arg2=1; //Quiet mode
296 mHandler.sendMessage(msg);
297 return true;
298
299 }
fredc0f420372012-04-12 00:02:00 -0700300 public boolean enable() {
301 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
302 "Need BLUETOOTH ADMIN permission");
fredcf2458862012-04-16 15:18:27 -0700303 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700304 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
305 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700306 }
307
fredc0f420372012-04-12 00:02:00 -0700308 synchronized(mConnection) {
fredc649fe492012-04-19 01:07:18 -0700309 if (mBinding) {
310 Log.w(TAG,"enable(): binding in progress. Returning..");
311 return true;
312 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700313 if (mConnection == null) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700314 }
fredc116d1d462012-04-20 14:47:08 -0700315
fredc0f420372012-04-12 00:02:00 -0700316 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
fredc649fe492012-04-19 01:07:18 -0700317 msg.arg1=1; //persist
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700318 msg.arg2=0; //No Quiet Mode
fredc0f420372012-04-12 00:02:00 -0700319 mHandler.sendMessage(msg);
320 return true;
321 }
322
323 public boolean disable(boolean persist) {
324 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
325 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
fredcf2458862012-04-16 15:18:27 -0700326 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700327 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
328 " mBinding = " + mBinding);
329 }
fredcf2458862012-04-16 15:18:27 -0700330
fredc0f420372012-04-12 00:02:00 -0700331 synchronized(mConnection) {
332 if (mBluetooth == null) return false;
fredc0f420372012-04-12 00:02:00 -0700333 }
334 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700335 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700336 mHandler.sendMessage(msg);
337 return true;
338 }
339
fredc649fe492012-04-19 01:07:18 -0700340 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700341 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700342 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
343 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700344 }
345
fredc0f420372012-04-12 00:02:00 -0700346 synchronized (mConnection) {
347 if (mUnbinding) return;
348 mUnbinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700349 if (mConnection != null) {
fredcbf072a72012-05-09 16:52:50 -0700350 if (!mConnection.isGetNameAddressOnly()) {
351 //Unregister callback object
352 try {
353 mBluetooth.unregisterCallback(mBluetoothCallback);
354 } catch (RemoteException re) {
355 Log.e(TAG, "Unable to register BluetoothCallback",re);
356 }
357 }
fredc0f420372012-04-12 00:02:00 -0700358 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700359 mBluetooth = null;
360 //Unbind
fredc0f420372012-04-12 00:02:00 -0700361 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700362 mUnbinding = false;
fredcf2458862012-04-16 15:18:27 -0700363 } else {
364 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700365 }
366 }
367 }
368
fredcbf072a72012-05-09 16:52:50 -0700369 private void sendBluetoothStateCallback(boolean isUp) {
370 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700371 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700372 for (int i=0; i <n;i++) {
373 try {
374 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
375 } catch (RemoteException e) {
376 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
377 }
378 }
379 mStateChangeCallbacks.finishBroadcast();
380 }
381
382 /**
383 * Inform BluetoothAdapter instances that Adapter service is down
384 */
385 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700386 if (!mConnection.isGetNameAddressOnly()) {
387 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
388 int n = mCallbacks.beginBroadcast();
389 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
390 for (int i=0; i <n;i++) {
391 try {
392 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
393 } catch (RemoteException e) {
394 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
395 }
396 }
397 mCallbacks.finishBroadcast();
398 }
399 }
fredc0f420372012-04-12 00:02:00 -0700400 public String getAddress() {
401 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
402 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700403 synchronized(mConnection) {
404 if (mBluetooth != null) {
405 try {
406 return mBluetooth.getAddress();
407 } catch (RemoteException e) {
408 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
409 }
410 }
411 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700412 // mAddress is accessed from outside.
413 // It is alright without a lock. Here, bluetooth is off, no other thread is
414 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700415 return mAddress;
416 }
fredc649fe492012-04-19 01:07:18 -0700417
fredc0f420372012-04-12 00:02:00 -0700418 public String getName() {
419 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
420 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700421 synchronized(mConnection) {
422 if (mBluetooth != null) {
423 try {
424 return mBluetooth.getName();
425 } catch (RemoteException e) {
426 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
427 }
428 }
429 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700430 // mName is accessed from outside.
431 // It alright without a lock. Here, bluetooth is off, no other thread is
432 // changing mName
fredc0f420372012-04-12 00:02:00 -0700433 return mName;
434 }
435
fredc0f420372012-04-12 00:02:00 -0700436 private class BluetoothServiceConnection implements ServiceConnection {
437
438 private boolean mGetNameAddressOnly;
439
440 public void setGetNameAddressOnly(boolean getOnly) {
441 mGetNameAddressOnly = getOnly;
442 }
443
444 public boolean isGetNameAddressOnly() {
445 return mGetNameAddressOnly;
446 }
447
448 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700449 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700450 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
451 msg.obj = service;
452 mHandler.sendMessage(msg);
453 }
454
455 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700456 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700457 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700458 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
459 mHandler.sendMessage(msg);
460 }
461 }
462
463 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
464
465 private final Handler mHandler = new Handler() {
466 @Override
467 public void handleMessage(Message msg) {
468 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700469 switch (msg.what) {
470 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700471 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700472 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700473 //Start bind request
Matthew Xiecdce0b92012-07-12 19:06:15 -0700474 if (mBluetooth == null) {
fredc0f420372012-04-12 00:02:00 -0700475 if (DBG) Log.d(TAG, "Binding to service to get name and address");
476 mConnection.setGetNameAddressOnly(true);
477 //Start bind timeout and bind
478 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
479 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
480 Intent i = new Intent(IBluetooth.class.getName());
481 if (!mContext.bindService(i, mConnection,
482 Context.BIND_AUTO_CREATE)) {
483 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
484 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
485 }
486 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700487 else {
488 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
489 mHandler.sendMessage(saveMsg);
490 }
fredc0f420372012-04-12 00:02:00 -0700491 }
fredc649fe492012-04-19 01:07:18 -0700492 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700493 }
fredc0f420372012-04-12 00:02:00 -0700494 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700495 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700496 synchronized(mConnection) {
497 if (mBluetooth != null) {
498 String name = null;
499 String address = null;
500 try {
501 name = mBluetooth.getName();
502 address = mBluetooth.getAddress();
503 } catch (RemoteException re) {
504 Log.e(TAG,"",re);
505 }
fredc0f420372012-04-12 00:02:00 -0700506
Matthew Xiecdce0b92012-07-12 19:06:15 -0700507 if (name != null && address != null) {
508 storeNameAndAddress(name,address);
fredcbf072a72012-05-09 16:52:50 -0700509 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700510 unbindAndFinish();
Matthew Xiecdce0b92012-07-12 19:06:15 -0700511 } else {
512 if (msg.arg1 < MAX_SAVE_RETRIES) {
513 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
514 retryMsg.arg1= 1+msg.arg1;
515 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
516 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
517 } else {
518 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
519 sendBluetoothServiceDownCallback();
520 unbindAndFinish();
521 }
fredc0f420372012-04-12 00:02:00 -0700522 }
523 }
524 }
fredc649fe492012-04-19 01:07:18 -0700525 break;
fredc649fe492012-04-19 01:07:18 -0700526 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700527 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700528 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700529 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700530 }
Freda8c6df02012-07-11 10:25:23 -0700531
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700532 handleEnable(msg.arg1 == 1, msg.arg2 ==1);
fredc649fe492012-04-19 01:07:18 -0700533 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700534
fredc0f420372012-04-12 00:02:00 -0700535 case MESSAGE_DISABLE:
Matthew Xiecdce0b92012-07-12 19:06:15 -0700536 handleDisable(msg.arg1 == 1);
fredc0f420372012-04-12 00:02:00 -0700537 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700538
fredc0f420372012-04-12 00:02:00 -0700539 case MESSAGE_REGISTER_ADAPTER:
540 {
541 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700542 boolean added = mCallbacks.register(callback);
543 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700544 }
545 break;
546 case MESSAGE_UNREGISTER_ADAPTER:
547 {
548 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700549 boolean removed = mCallbacks.unregister(callback);
550 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700551 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700552 }
fredc0f420372012-04-12 00:02:00 -0700553 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
554 {
555 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700556 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700557 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700558 }
fredc0f420372012-04-12 00:02:00 -0700559 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
560 {
561 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700562 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700563 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700564 }
fredc0f420372012-04-12 00:02:00 -0700565 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
566 {
fredc649fe492012-04-19 01:07:18 -0700567 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
568
fredc0f420372012-04-12 00:02:00 -0700569 //Remove timeout
570 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
571
572 IBinder service = (IBinder) msg.obj;
573 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700574 mBinding = false;
575 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700576
Matthew Xiecdce0b92012-07-12 19:06:15 -0700577 if (mConnection.isGetNameAddressOnly()) {
578 //Request GET NAME AND ADDRESS
579 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
580 mHandler.sendMessage(getMsg);
581 return;
582 }
fredc0f420372012-04-12 00:02:00 -0700583
Matthew Xiecdce0b92012-07-12 19:06:15 -0700584 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700585 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700586 mBluetooth.registerCallback(mBluetoothCallback);
587 } catch (RemoteException re) {
588 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700589 }
fredcbf072a72012-05-09 16:52:50 -0700590
Matthew Xiecdce0b92012-07-12 19:06:15 -0700591 //Inform BluetoothAdapter instances that service is up
592 int n = mCallbacks.beginBroadcast();
593 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
594 for (int i=0; i <n;i++) {
595 try {
596 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
597 } catch (RemoteException e) {
598 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
599 }
Freda8c6df02012-07-11 10:25:23 -0700600 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700601 mCallbacks.finishBroadcast();
602
603 //Do enable request
604 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700605 if (mQuietEnable == false) {
606 if(!mBluetooth.enable()) {
607 Log.e(TAG,"IBluetooth.enable() returned false");
608 }
609 }
610 else
611 {
612 if(!mBluetooth.enableNoAutoConnect()) {
613 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
614 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700615 }
616 } catch (RemoteException e) {
617 Log.e(TAG,"Unable to call enable()",e);
618 }
Freda8c6df02012-07-11 10:25:23 -0700619 }
fredc649fe492012-04-19 01:07:18 -0700620 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700621 }
fredc649fe492012-04-19 01:07:18 -0700622 case MESSAGE_TIMEOUT_BIND: {
623 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700624 synchronized(mConnection) {
625 mBinding = false;
626 }
fredc649fe492012-04-19 01:07:18 -0700627 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700628 }
fredcbf072a72012-05-09 16:52:50 -0700629 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700630 {
fredcbf072a72012-05-09 16:52:50 -0700631 int prevState = msg.arg1;
632 int newState = msg.arg2;
633 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
634 if (prevState != newState) {
635 //Notify all proxy objects first of adapter state change
636 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
637 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
638 sendBluetoothStateCallback(isUp);
639
640 //If Bluetooth is off, send service down event to proxy objects, and unbind
641 if (!isUp) {
642 sendBluetoothServiceDownCallback();
643 unbindAndFinish();
644 }
fredc0f420372012-04-12 00:02:00 -0700645 }
fredcbf072a72012-05-09 16:52:50 -0700646
647 //Send broadcast message to everyone else
648 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
649 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
650 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
651 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
652 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
653 mContext.sendBroadcast(intent,BLUETOOTH_PERM);
fredc0f420372012-04-12 00:02:00 -0700654 }
fredc649fe492012-04-19 01:07:18 -0700655 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700656 }
fredc0f420372012-04-12 00:02:00 -0700657 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
658 {
fredc649fe492012-04-19 01:07:18 -0700659 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredcbf072a72012-05-09 16:52:50 -0700660 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700661 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700662 }
fredc0f420372012-04-12 00:02:00 -0700663 case MESSAGE_TIMEOUT_UNBIND:
664 {
fredc649fe492012-04-19 01:07:18 -0700665 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700666 synchronized(mConnection) {
667 mUnbinding = false;
668 }
fredc649fe492012-04-19 01:07:18 -0700669 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700670 }
fredc0f420372012-04-12 00:02:00 -0700671 }
672 }
673 };
Matthew Xiecdce0b92012-07-12 19:06:15 -0700674
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700675 private void handleEnable(boolean persist, boolean quietMode) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700676 if (persist) {
677 persistBluetoothSetting(true);
678 }
679
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700680 mQuietEnable = quietMode;
681
Matthew Xiecdce0b92012-07-12 19:06:15 -0700682 synchronized(mConnection) {
683 if (mBluetooth == null) {
684 //Start bind timeout and bind
685 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
686 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
687 mConnection.setGetNameAddressOnly(false);
688 Intent i = new Intent(IBluetooth.class.getName());
689 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
690 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
691 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
692 }
693 } else {
694 //Check if name and address is loaded if not get it first.
695 if (!isNameAndAddressSet()) {
696 try {
697 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
698 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
699 } catch (RemoteException e) {Log.e(TAG, "", e);};
700 }
701
702 //Enable bluetooth
703 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700704 if (!mQuietEnable) {
705 if(!mBluetooth.enable()) {
706 Log.e(TAG,"IBluetooth.enable() returned false");
707 }
708 }
709 else {
710 if(!mBluetooth.enableNoAutoConnect()) {
711 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
712 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700713 }
714 } catch (RemoteException e) {
715 Log.e(TAG,"Unable to call enable()",e);
716 }
717 }
718 }
719 }
720
721 private void handleDisable(boolean persist) {
722 synchronized(mConnection) {
723 if (mBluetooth != null ) {
724 if (persist) {
725 persistBluetoothSetting(false);
726 }
727 mConnection.setGetNameAddressOnly(false);
728 if (DBG) Log.d(TAG,"Sending off request.");
729
730 try {
731 if(!mBluetooth.disable()) {
732 Log.e(TAG,"IBluetooth.disable() returned false");
733 }
734 } catch (RemoteException e) {
735 Log.e(TAG,"Unable to call disable()",e);
736 }
737 }
738 }
739 }
fredc0f420372012-04-12 00:02:00 -0700740}