blob: cc9b9fa3ff2e1659948bbb74d7fdd93b14c71529 [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;
25import android.provider.Settings;
26import android.util.Log;
27import java.util.List;
28import java.util.ArrayList;
fredc0f420372012-04-12 00:02:00 -070029class BluetoothManagerService extends IBluetoothManager.Stub {
30 private static final String TAG = "BluetoothManagerService";
31 private static final boolean DBG = true;
32
fredc0f420372012-04-12 00:02:00 -070033 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
34 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070035 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
36 private static final String EXTRA_ACTION="action";
fredc0f420372012-04-12 00:02:00 -070037 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
38 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070039 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
40 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
41
42 private static final int MESSAGE_ENABLE = 1;
43 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070044 private static final int MESSAGE_REGISTER_ADAPTER = 20;
45 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
46 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
47 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
48 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
49 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
fredcbf072a72012-05-09 16:52:50 -070050 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070051 private static final int MESSAGE_TIMEOUT_BIND =100;
52 private static final int MESSAGE_TIMEOUT_UNBIND =101;
53 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
54 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
55 private static final int MAX_SAVE_RETRIES=3;
56
57 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070058
59 // Locks are not provided for mName and mAddress.
60 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070061 private String mAddress;
62 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -070063 private final ContentResolver mContentResolver;
64 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
65 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070066 private IBluetooth mBluetooth;
67 private boolean mBinding;
68 private boolean mUnbinding;
fredc0f420372012-04-12 00:02:00 -070069
fredc649fe492012-04-19 01:07:18 -070070 private void registerForAirplaneMode(IntentFilter filter) {
71 final ContentResolver resolver = mContext.getContentResolver();
72 final String airplaneModeRadios = Settings.System.getString(resolver,
73 Settings.System.AIRPLANE_MODE_RADIOS);
74 final String toggleableRadios = Settings.System.getString(resolver,
75 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
76 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
77 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
78 if (mIsAirplaneSensitive) {
79 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
80 }
81 }
82
fredcbf072a72012-05-09 16:52:50 -070083 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
84 @Override
85 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
86 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
87 mHandler.sendMessage(msg);
88 }
89 };
90
91 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -070092 @Override
93 public void onReceive(Context context, Intent intent) {
94 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -070095 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -070096 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -070097 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -070098 if (newName != null) {
99 storeNameAndAddress(newName, null);
100 }
fredc649fe492012-04-19 01:07:18 -0700101 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
102 if (isAirplaneModeOn()) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700103 // disable without persisting the setting
104 handleDisable(false);
fredc649fe492012-04-19 01:07:18 -0700105 } else {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700106 if (isBluetoothPersistedStateOn()) {
107 // enable without persisting the setting
108 handleEnable(false);
109 }
fredc649fe492012-04-19 01:07:18 -0700110 }
fredc0f420372012-04-12 00:02:00 -0700111 }
112 }
113 };
114
115 BluetoothManagerService(Context context) {
116 mContext = context;
117 mBluetooth = null;
118 mBinding = false;
119 mUnbinding = false;
120 mAddress = null;
121 mName = null;
122 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700123 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
124 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Matthew Xie6fde3092012-07-11 17:10:07 -0700125 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
126 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
127 registerForAirplaneMode(filter);
128 mContext.registerReceiver(mReceiver, filter);
fredc649fe492012-04-19 01:07:18 -0700129 boolean airplaneModeOn = isAirplaneModeOn();
130 boolean bluetoothOn = isBluetoothPersistedStateOn();
fredc0f420372012-04-12 00:02:00 -0700131 loadStoredNameAndAddress();
fredc649fe492012-04-19 01:07:18 -0700132 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
Andre Eisenbacha732ffd2012-05-02 00:39:24 -0700133 if (bluetoothOn) {
fredc0f420372012-04-12 00:02:00 -0700134 //Enable
fredc649fe492012-04-19 01:07:18 -0700135 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
fredc0f420372012-04-12 00:02:00 -0700136 enable();
Freda8c6df02012-07-11 10:25:23 -0700137 } else if (!isNameAndAddressSet()) {
fredc649fe492012-04-19 01:07:18 -0700138 //Sync the Bluetooth name and address from the Bluetooth Adapter
139 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
fredc0f420372012-04-12 00:02:00 -0700140 getNameAndAddress();
141 }
142 }
143
fredc649fe492012-04-19 01:07:18 -0700144 /**
145 * Returns true if airplane mode is currently on
146 */
147 private final boolean isAirplaneModeOn() {
148 return Settings.System.getInt(mContext.getContentResolver(),
149 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
150 }
151
152 /**
153 * Returns true if the Bluetooth saved state is "on"
154 */
155 private final boolean isBluetoothPersistedStateOn() {
156 return Settings.Secure.getInt(mContentResolver,
157 Settings.Secure.BLUETOOTH_ON, 0) ==1;
158 }
159
160 /**
161 * Save the Bluetooth on/off state
162 *
163 */
164 private void persistBluetoothSetting(boolean setOn) {
165 Settings.Secure.putInt(mContext.getContentResolver(),
166 Settings.Secure.BLUETOOTH_ON,
167 setOn ? 1 : 0);
168 }
169
170 /**
171 * Returns true if the Bluetooth Adapter's name and address is
172 * locally cached
173 * @return
174 */
fredc0f420372012-04-12 00:02:00 -0700175 private boolean isNameAndAddressSet() {
176 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
177 }
178
fredc649fe492012-04-19 01:07:18 -0700179 /**
180 * Retrieve the Bluetooth Adapter's name and address and save it in
181 * in the local cache
182 */
fredc0f420372012-04-12 00:02:00 -0700183 private void loadStoredNameAndAddress() {
184 if (DBG) Log.d(TAG, "Loading stored name and address");
185 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
186 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
187 if (mName == null || mAddress == null) {
188 if (DBG) Log.d(TAG, "Name or address not cached...");
189 }
190 }
191
fredc649fe492012-04-19 01:07:18 -0700192 /**
193 * Save the Bluetooth name and address in the persistent store.
194 * Only non-null values will be saved.
195 * @param name
196 * @param address
197 */
fredc0f420372012-04-12 00:02:00 -0700198 private void storeNameAndAddress(String name, String address) {
199 if (name != null) {
200 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700201 mName = name;
fredc649fe492012-04-19 01:07:18 -0700202 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
203 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700204 }
205
206 if (address != null) {
207 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700208 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700209 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
210 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700211 }
212 }
213
214 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
215 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
216 "Need BLUETOOTH permission");
217 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
218 msg.obj = callback;
219 mHandler.sendMessage(msg);
220 synchronized(mConnection) {
221 return mBluetooth;
222 }
223 }
224
225 public void unregisterAdapter(IBluetoothManagerCallback callback) {
226 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
227 "Need BLUETOOTH permission");
228 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
229 msg.obj = callback;
230 mHandler.sendMessage(msg);
231 }
232
233 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
234 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
235 "Need BLUETOOTH permission");
236 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
237 msg.obj = callback;
238 mHandler.sendMessage(msg);
239 }
240
241 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
242 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
243 "Need BLUETOOTH permission");
244 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
245 msg.obj = callback;
246 mHandler.sendMessage(msg);
247 }
248
249 public boolean isEnabled() {
250 synchronized(mConnection) {
251 try {
252 return (mBluetooth != null && mBluetooth.isEnabled());
253 } catch (RemoteException e) {
254 Log.e(TAG, "isEnabled()", e);
255 }
256 }
257 return false;
258 }
259
260 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700261 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700262 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
263 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700264 }
fredc0f420372012-04-12 00:02:00 -0700265 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700266 if (mBinding) return;
267 if (mConnection == null) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700268 }
269 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
270 mHandler.sendMessage(msg);
271 }
272
273 public boolean enable() {
274 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
275 "Need BLUETOOTH ADMIN permission");
fredcf2458862012-04-16 15:18:27 -0700276 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700277 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
278 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700279 }
280
fredc0f420372012-04-12 00:02:00 -0700281 synchronized(mConnection) {
fredc649fe492012-04-19 01:07:18 -0700282 if (mBinding) {
283 Log.w(TAG,"enable(): binding in progress. Returning..");
284 return true;
285 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700286 if (mConnection == null) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700287 }
fredc116d1d462012-04-20 14:47:08 -0700288
fredc0f420372012-04-12 00:02:00 -0700289 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
fredc649fe492012-04-19 01:07:18 -0700290 msg.arg1=1; //persist
fredc0f420372012-04-12 00:02:00 -0700291 mHandler.sendMessage(msg);
292 return true;
293 }
294
295 public boolean disable(boolean persist) {
296 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
297 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
fredcf2458862012-04-16 15:18:27 -0700298 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700299 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
300 " mBinding = " + mBinding);
301 }
fredcf2458862012-04-16 15:18:27 -0700302
fredc0f420372012-04-12 00:02:00 -0700303 synchronized(mConnection) {
304 if (mBluetooth == null) return false;
fredc0f420372012-04-12 00:02:00 -0700305 }
306 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700307 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700308 mHandler.sendMessage(msg);
309 return true;
310 }
311
fredc649fe492012-04-19 01:07:18 -0700312 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700313 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700314 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
315 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700316 }
317
fredc0f420372012-04-12 00:02:00 -0700318 synchronized (mConnection) {
319 if (mUnbinding) return;
320 mUnbinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700321 if (mConnection != null) {
fredcbf072a72012-05-09 16:52:50 -0700322 if (!mConnection.isGetNameAddressOnly()) {
323 //Unregister callback object
324 try {
325 mBluetooth.unregisterCallback(mBluetoothCallback);
326 } catch (RemoteException re) {
327 Log.e(TAG, "Unable to register BluetoothCallback",re);
328 }
329 }
fredc0f420372012-04-12 00:02:00 -0700330 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700331 mBluetooth = null;
332 //Unbind
fredc0f420372012-04-12 00:02:00 -0700333 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700334 mUnbinding = false;
fredcf2458862012-04-16 15:18:27 -0700335 } else {
336 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700337 }
338 }
339 }
340
fredcbf072a72012-05-09 16:52:50 -0700341 private void sendBluetoothStateCallback(boolean isUp) {
342 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700343 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700344 for (int i=0; i <n;i++) {
345 try {
346 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
347 } catch (RemoteException e) {
348 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
349 }
350 }
351 mStateChangeCallbacks.finishBroadcast();
352 }
353
354 /**
355 * Inform BluetoothAdapter instances that Adapter service is down
356 */
357 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700358 if (!mConnection.isGetNameAddressOnly()) {
359 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
360 int n = mCallbacks.beginBroadcast();
361 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
362 for (int i=0; i <n;i++) {
363 try {
364 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
365 } catch (RemoteException e) {
366 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
367 }
368 }
369 mCallbacks.finishBroadcast();
370 }
371 }
fredc0f420372012-04-12 00:02:00 -0700372 public String getAddress() {
373 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
374 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700375 synchronized(mConnection) {
376 if (mBluetooth != null) {
377 try {
378 return mBluetooth.getAddress();
379 } catch (RemoteException e) {
380 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
381 }
382 }
383 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700384 // mAddress is accessed from outside.
385 // It is alright without a lock. Here, bluetooth is off, no other thread is
386 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700387 return mAddress;
388 }
fredc649fe492012-04-19 01:07:18 -0700389
fredc0f420372012-04-12 00:02:00 -0700390 public String getName() {
391 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
392 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700393 synchronized(mConnection) {
394 if (mBluetooth != null) {
395 try {
396 return mBluetooth.getName();
397 } catch (RemoteException e) {
398 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
399 }
400 }
401 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700402 // mName is accessed from outside.
403 // It alright without a lock. Here, bluetooth is off, no other thread is
404 // changing mName
fredc0f420372012-04-12 00:02:00 -0700405 return mName;
406 }
407
fredc0f420372012-04-12 00:02:00 -0700408 private class BluetoothServiceConnection implements ServiceConnection {
409
410 private boolean mGetNameAddressOnly;
411
412 public void setGetNameAddressOnly(boolean getOnly) {
413 mGetNameAddressOnly = getOnly;
414 }
415
416 public boolean isGetNameAddressOnly() {
417 return mGetNameAddressOnly;
418 }
419
420 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700421 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700422 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
423 msg.obj = service;
424 mHandler.sendMessage(msg);
425 }
426
427 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700428 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700429 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700430 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
431 mHandler.sendMessage(msg);
432 }
433 }
434
435 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
436
437 private final Handler mHandler = new Handler() {
438 @Override
439 public void handleMessage(Message msg) {
440 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700441 switch (msg.what) {
442 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700443 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700444 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700445 //Start bind request
Matthew Xiecdce0b92012-07-12 19:06:15 -0700446 if (mBluetooth == null) {
fredc0f420372012-04-12 00:02:00 -0700447 if (DBG) Log.d(TAG, "Binding to service to get name and address");
448 mConnection.setGetNameAddressOnly(true);
449 //Start bind timeout and bind
450 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
451 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
452 Intent i = new Intent(IBluetooth.class.getName());
453 if (!mContext.bindService(i, mConnection,
454 Context.BIND_AUTO_CREATE)) {
455 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
456 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
457 }
458 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700459 else {
460 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
461 mHandler.sendMessage(saveMsg);
462 }
fredc0f420372012-04-12 00:02:00 -0700463 }
fredc649fe492012-04-19 01:07:18 -0700464 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700465 }
fredc0f420372012-04-12 00:02:00 -0700466 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700467 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700468 synchronized(mConnection) {
469 if (mBluetooth != null) {
470 String name = null;
471 String address = null;
472 try {
473 name = mBluetooth.getName();
474 address = mBluetooth.getAddress();
475 } catch (RemoteException re) {
476 Log.e(TAG,"",re);
477 }
fredc0f420372012-04-12 00:02:00 -0700478
Matthew Xiecdce0b92012-07-12 19:06:15 -0700479 if (name != null && address != null) {
480 storeNameAndAddress(name,address);
fredcbf072a72012-05-09 16:52:50 -0700481 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700482 unbindAndFinish();
Matthew Xiecdce0b92012-07-12 19:06:15 -0700483 } else {
484 if (msg.arg1 < MAX_SAVE_RETRIES) {
485 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
486 retryMsg.arg1= 1+msg.arg1;
487 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
488 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
489 } else {
490 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
491 sendBluetoothServiceDownCallback();
492 unbindAndFinish();
493 }
fredc0f420372012-04-12 00:02:00 -0700494 }
495 }
496 }
fredc649fe492012-04-19 01:07:18 -0700497 break;
fredc649fe492012-04-19 01:07:18 -0700498 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700499 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700500 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700501 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700502 }
Freda8c6df02012-07-11 10:25:23 -0700503
Matthew Xiecdce0b92012-07-12 19:06:15 -0700504 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -0700505 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700506
fredc0f420372012-04-12 00:02:00 -0700507 case MESSAGE_DISABLE:
Matthew Xiecdce0b92012-07-12 19:06:15 -0700508 handleDisable(msg.arg1 == 1);
fredc0f420372012-04-12 00:02:00 -0700509 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700510
fredc0f420372012-04-12 00:02:00 -0700511 case MESSAGE_REGISTER_ADAPTER:
512 {
513 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700514 boolean added = mCallbacks.register(callback);
515 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700516 }
517 break;
518 case MESSAGE_UNREGISTER_ADAPTER:
519 {
520 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700521 boolean removed = mCallbacks.unregister(callback);
522 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700523 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700524 }
fredc0f420372012-04-12 00:02:00 -0700525 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
526 {
527 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700528 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700529 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700530 }
fredc0f420372012-04-12 00:02:00 -0700531 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
532 {
533 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700534 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700535 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700536 }
fredc0f420372012-04-12 00:02:00 -0700537 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
538 {
fredc649fe492012-04-19 01:07:18 -0700539 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
540
fredc0f420372012-04-12 00:02:00 -0700541 //Remove timeout
542 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
543
544 IBinder service = (IBinder) msg.obj;
545 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700546 mBinding = false;
547 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700548
Matthew Xiecdce0b92012-07-12 19:06:15 -0700549 if (mConnection.isGetNameAddressOnly()) {
550 //Request GET NAME AND ADDRESS
551 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
552 mHandler.sendMessage(getMsg);
553 return;
554 }
fredc0f420372012-04-12 00:02:00 -0700555
Matthew Xiecdce0b92012-07-12 19:06:15 -0700556 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700557 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700558 mBluetooth.registerCallback(mBluetoothCallback);
559 } catch (RemoteException re) {
560 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700561 }
fredcbf072a72012-05-09 16:52:50 -0700562
Matthew Xiecdce0b92012-07-12 19:06:15 -0700563 //Inform BluetoothAdapter instances that service is up
564 int n = mCallbacks.beginBroadcast();
565 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
566 for (int i=0; i <n;i++) {
567 try {
568 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
569 } catch (RemoteException e) {
570 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
571 }
Freda8c6df02012-07-11 10:25:23 -0700572 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700573 mCallbacks.finishBroadcast();
574
575 //Do enable request
576 try {
577 if(!mBluetooth.enable()) {
578 Log.e(TAG,"IBluetooth.enable() returned false");
579 }
580 } catch (RemoteException e) {
581 Log.e(TAG,"Unable to call enable()",e);
582 }
Freda8c6df02012-07-11 10:25:23 -0700583 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700584
fredc649fe492012-04-19 01:07:18 -0700585 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700586 }
fredc649fe492012-04-19 01:07:18 -0700587 case MESSAGE_TIMEOUT_BIND: {
588 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700589 synchronized(mConnection) {
590 mBinding = false;
591 }
fredc649fe492012-04-19 01:07:18 -0700592 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700593 }
fredcbf072a72012-05-09 16:52:50 -0700594 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700595 {
fredcbf072a72012-05-09 16:52:50 -0700596 int prevState = msg.arg1;
597 int newState = msg.arg2;
598 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
599 if (prevState != newState) {
600 //Notify all proxy objects first of adapter state change
601 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
602 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
603 sendBluetoothStateCallback(isUp);
604
605 //If Bluetooth is off, send service down event to proxy objects, and unbind
606 if (!isUp) {
607 sendBluetoothServiceDownCallback();
608 unbindAndFinish();
609 }
fredc0f420372012-04-12 00:02:00 -0700610 }
fredcbf072a72012-05-09 16:52:50 -0700611
612 //Send broadcast message to everyone else
613 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
614 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
615 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
616 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
617 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
618 mContext.sendBroadcast(intent,BLUETOOTH_PERM);
fredc0f420372012-04-12 00:02:00 -0700619 }
fredc649fe492012-04-19 01:07:18 -0700620 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700621 }
fredc0f420372012-04-12 00:02:00 -0700622 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
623 {
fredc649fe492012-04-19 01:07:18 -0700624 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredcbf072a72012-05-09 16:52:50 -0700625 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700626 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700627 }
fredc0f420372012-04-12 00:02:00 -0700628 case MESSAGE_TIMEOUT_UNBIND:
629 {
fredc649fe492012-04-19 01:07:18 -0700630 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700631 synchronized(mConnection) {
632 mUnbinding = false;
633 }
fredc649fe492012-04-19 01:07:18 -0700634 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700635 }
fredc0f420372012-04-12 00:02:00 -0700636 }
637 }
638 };
Matthew Xiecdce0b92012-07-12 19:06:15 -0700639
640 private void handleEnable(boolean persist) {
641 if (persist) {
642 persistBluetoothSetting(true);
643 }
644
645 synchronized(mConnection) {
646 if (mBluetooth == null) {
647 //Start bind timeout and bind
648 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
649 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
650 mConnection.setGetNameAddressOnly(false);
651 Intent i = new Intent(IBluetooth.class.getName());
652 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
653 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
654 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
655 }
656 } else {
657 //Check if name and address is loaded if not get it first.
658 if (!isNameAndAddressSet()) {
659 try {
660 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
661 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
662 } catch (RemoteException e) {Log.e(TAG, "", e);};
663 }
664
665 //Enable bluetooth
666 try {
667 if(!mBluetooth.enable()) {
668 Log.e(TAG,"IBluetooth.enable() returned false");
669 }
670 } catch (RemoteException e) {
671 Log.e(TAG,"Unable to call enable()",e);
672 }
673 }
674 }
675 }
676
677 private void handleDisable(boolean persist) {
678 synchronized(mConnection) {
679 if (mBluetooth != null ) {
680 if (persist) {
681 persistBluetoothSetting(false);
682 }
683 mConnection.setGetNameAddressOnly(false);
684 if (DBG) Log.d(TAG,"Sending off request.");
685
686 try {
687 if(!mBluetooth.disable()) {
688 Log.e(TAG,"IBluetooth.disable() returned false");
689 }
690 } catch (RemoteException e) {
691 Log.e(TAG,"Unable to call disable()",e);
692 }
693 }
694 }
695 }
fredc0f420372012-04-12 00:02:00 -0700696}