blob: 9610ffc6c2506e6a837544c72b1b26d25d9ae92d [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;
9import android.bluetooth.IBluetoothManager;
10import android.bluetooth.IBluetoothManagerCallback;
11import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070012import android.content.BroadcastReceiver;
13import android.content.ComponentName;
14import android.content.ContentResolver;
15import android.content.Context;
16import android.content.Intent;
17import android.content.IntentFilter;
18import android.content.ServiceConnection;
19import android.os.Handler;
fredc0f420372012-04-12 00:02:00 -070020import android.os.IBinder;
21import android.os.Message;
fredcd6883532012-04-25 17:46:13 -070022import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070023import android.os.RemoteException;
24import android.provider.Settings;
25import android.util.Log;
26import java.util.List;
27import java.util.ArrayList;
28
29class BluetoothManagerService extends IBluetoothManager.Stub {
30 private static final String TAG = "BluetoothManagerService";
31 private static final boolean DBG = true;
32
33 private static final boolean ALWAYS_SYNC_NAME_ADDRESS=true; //If true, always load name and address
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_AIRPLANE_MODE_OFF=10;
46 private static final int MESSAGE_AIRPLANE_MODE_ON=11;
47 private static final int MESSAGE_REGISTER_ADAPTER = 20;
48 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
49 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
50 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
51 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
52 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
53 private static final int MESSAGE_BLUETOOTH_ON = 50;
54 private static final int MESSAGE_BLUETOOTH_OFF = 51;
fredc0f420372012-04-12 00:02:00 -070055 private static final int MESSAGE_TIMEOUT_BIND =100;
56 private static final int MESSAGE_TIMEOUT_UNBIND =101;
57 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
58 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
59 private static final int MAX_SAVE_RETRIES=3;
60
61 private final Context mContext;
62 private String mAddress;
63 private String mName;
64 private ContentResolver mContentResolver;
fredcd6883532012-04-25 17:46:13 -070065 private RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
66 private RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070067 private IBluetooth mBluetooth;
68 private boolean mBinding;
69 private boolean mUnbinding;
fredc0f420372012-04-12 00:02:00 -070070
fredc649fe492012-04-19 01:07:18 -070071 private void registerForAirplaneMode(IntentFilter filter) {
72 final ContentResolver resolver = mContext.getContentResolver();
73 final String airplaneModeRadios = Settings.System.getString(resolver,
74 Settings.System.AIRPLANE_MODE_RADIOS);
75 final String toggleableRadios = Settings.System.getString(resolver,
76 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
77 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
78 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
79 if (mIsAirplaneSensitive) {
80 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
81 }
82 }
83
fredc0f420372012-04-12 00:02:00 -070084 private BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -070085 @Override
86 public void onReceive(Context context, Intent intent) {
87 String action = intent.getAction();
88 if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
89 int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
90 if (state == BluetoothAdapter.STATE_OFF) {
91 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_OFF);
92 mHandler.sendMessage(msg);
93 } else if (state == BluetoothAdapter.STATE_ON) {
94 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_ON);
95 mHandler.sendMessage(msg);
96 }
97 } else if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
98 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
99 Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
100 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()) {
105 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_ON);
106 msg.arg1=0;
107 mHandler.sendMessage(msg);
108 } else {
109 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_OFF);
110 msg.arg1=0;
111 mHandler.sendMessage(msg);
112 }
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>();
fredc649fe492012-04-19 01:07:18 -0700127 IntentFilter mFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
fredc116d1d462012-04-20 14:47:08 -0700128 mFilter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
fredc649fe492012-04-19 01:07:18 -0700129 registerForAirplaneMode(mFilter);
fredc0f420372012-04-12 00:02:00 -0700130 mContext.registerReceiver(mReceiver, mFilter);
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);
135 if (!airplaneModeOn && 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();
139 } else if (ALWAYS_SYNC_NAME_ADDRESS || !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
fredcf2458862012-04-16 15:18:27 -0700262 private boolean isConnected() {
263 return mBluetooth != null;
264 }
fredc649fe492012-04-19 01:07:18 -0700265
fredc0f420372012-04-12 00:02:00 -0700266 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700267 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700268 Log.d(TAG,"getNameAndAddress(): mBluetooth = " +
269 (mBluetooth==null?"null":mBluetooth) +
270 " mBinding = " + mBinding +
271 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700272 }
fredc0f420372012-04-12 00:02:00 -0700273 synchronized(mConnection) {
274 if (mBinding) return ;
fredcf2458862012-04-16 15:18:27 -0700275 if (!isConnected()) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700276 }
277 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
278 mHandler.sendMessage(msg);
279 }
280
281 public boolean enable() {
282 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
283 "Need BLUETOOTH ADMIN permission");
fredcf2458862012-04-16 15:18:27 -0700284 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700285 Log.d(TAG,"enable(): mBluetooth =" +
286 (mBluetooth==null?"null":mBluetooth) +
287 " mBinding = " + mBinding +
288 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700289 }
290
fredc0f420372012-04-12 00:02:00 -0700291 synchronized(mConnection) {
fredc649fe492012-04-19 01:07:18 -0700292 //if (mBluetooth != null) return false;
293 if (mBinding) {
294 Log.w(TAG,"enable(): binding in progress. Returning..");
295 return true;
296 }
fredcf2458862012-04-16 15:18:27 -0700297 if (!isConnected()) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700298 }
fredc116d1d462012-04-20 14:47:08 -0700299
fredc0f420372012-04-12 00:02:00 -0700300 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
fredc649fe492012-04-19 01:07:18 -0700301 msg.arg1=1; //persist
fredc0f420372012-04-12 00:02:00 -0700302 mHandler.sendMessage(msg);
303 return true;
304 }
305
306 public boolean disable(boolean persist) {
307 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
308 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
fredcf2458862012-04-16 15:18:27 -0700309 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700310 Log.d(TAG,"disable(): mBluetooth = " +
311 (mBluetooth==null?"null":mBluetooth) +
312 " mBinding = " + mBinding +
313 " isConnected = " + isConnected());}
fredcf2458862012-04-16 15:18:27 -0700314
fredc0f420372012-04-12 00:02:00 -0700315 synchronized(mConnection) {
316 if (mBluetooth == null) return false;
fredc0f420372012-04-12 00:02:00 -0700317 }
318 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700319 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700320 mHandler.sendMessage(msg);
321 return true;
322 }
323
fredc649fe492012-04-19 01:07:18 -0700324 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700325 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700326 Log.d(TAG,"unbindAndFinish(): " +
327 (mBluetooth==null?"null":mBluetooth) +
328 " mBinding = " + mBinding +
329 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700330 }
331
fredc0f420372012-04-12 00:02:00 -0700332 synchronized (mConnection) {
333 if (mUnbinding) return;
334 mUnbinding = true;
fredcf2458862012-04-16 15:18:27 -0700335 if (isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700336 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700337 mBluetooth = null;
338 //Unbind
fredc0f420372012-04-12 00:02:00 -0700339 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700340 mUnbinding = false;
fredcf2458862012-04-16 15:18:27 -0700341 } else {
342 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700343 }
344 }
345 }
346
fredcd6883532012-04-25 17:46:13 -0700347 private void sendBluetoothServiceDownEvent() {
348 if (!mConnection.isGetNameAddressOnly()) {
349 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
350 int n = mCallbacks.beginBroadcast();
351 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
352 for (int i=0; i <n;i++) {
353 try {
354 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
355 } catch (RemoteException e) {
356 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
357 }
358 }
359 mCallbacks.finishBroadcast();
360 }
361 }
fredc0f420372012-04-12 00:02:00 -0700362 public String getAddress() {
363 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
364 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700365 synchronized(mConnection) {
366 if (mBluetooth != null) {
367 try {
368 return mBluetooth.getAddress();
369 } catch (RemoteException e) {
370 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
371 }
372 }
373 }
fredc0f420372012-04-12 00:02:00 -0700374 return mAddress;
375 }
fredc649fe492012-04-19 01:07:18 -0700376
fredc0f420372012-04-12 00:02:00 -0700377 public String getName() {
378 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
379 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700380 synchronized(mConnection) {
381 if (mBluetooth != null) {
382 try {
383 return mBluetooth.getName();
384 } catch (RemoteException e) {
385 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
386 }
387 }
388 }
fredc0f420372012-04-12 00:02:00 -0700389 return mName;
390 }
391
fredc0f420372012-04-12 00:02:00 -0700392 private class BluetoothServiceConnection implements ServiceConnection {
393
394 private boolean mGetNameAddressOnly;
395
396 public void setGetNameAddressOnly(boolean getOnly) {
397 mGetNameAddressOnly = getOnly;
398 }
399
400 public boolean isGetNameAddressOnly() {
401 return mGetNameAddressOnly;
402 }
403
404 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700405 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700406 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
407 msg.obj = service;
408 mHandler.sendMessage(msg);
409 }
410
411 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700412 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700413 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700414 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
415 mHandler.sendMessage(msg);
416 }
417 }
418
419 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
420
421 private final Handler mHandler = new Handler() {
422 @Override
423 public void handleMessage(Message msg) {
424 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700425 switch (msg.what) {
426 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700427 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700428 if (mBluetooth == null) {
429 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700430 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700431 if (DBG) Log.d(TAG, "Binding to service to get name and address");
432 mConnection.setGetNameAddressOnly(true);
433 //Start bind timeout and bind
434 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
435 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
436 Intent i = new Intent(IBluetooth.class.getName());
437 if (!mContext.bindService(i, mConnection,
438 Context.BIND_AUTO_CREATE)) {
439 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
440 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
441 }
442 }
443 } else {
444 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
445 mHandler.sendMessage(saveMsg);
446 }
447 }
fredc649fe492012-04-19 01:07:18 -0700448 break;
fredc0f420372012-04-12 00:02:00 -0700449 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700450 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700451 if (mBluetooth != null) {
452 String name = null;
453 String address = null;
454 try {
455 name = mBluetooth.getName();
456 address = mBluetooth.getAddress();
457 } catch (RemoteException re) {
458 Log.e(TAG,"",re);
459 }
460
461 if (name != null && address != null) {
462 storeNameAndAddress(name,address);
fredc649fe492012-04-19 01:07:18 -0700463 Intent i = new Intent(IBluetooth.class.getName());
464 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
465 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
466 mContext.startService(i);
fredcd6883532012-04-25 17:46:13 -0700467 sendBluetoothServiceDownEvent();
fredc649fe492012-04-19 01:07:18 -0700468 unbindAndFinish();
469 } else {
fredc0f420372012-04-12 00:02:00 -0700470 if (msg.arg1 < MAX_SAVE_RETRIES) {
471 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
472 retryMsg.arg1= 1+msg.arg1;
473 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
474 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
475 } else {
476 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
fredcd6883532012-04-25 17:46:13 -0700477 sendBluetoothServiceDownEvent();
fredc649fe492012-04-19 01:07:18 -0700478 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700479 }
480 }
481 }
482 }
fredc649fe492012-04-19 01:07:18 -0700483 break;
484 case MESSAGE_AIRPLANE_MODE_OFF: {
485 if (DBG) Log.d(TAG,"MESSAGE_AIRPLANE_MODE_OFF");
486 //Check if we should turn on bluetooth
487 if (!isBluetoothPersistedStateOn()) {
488 if (DBG)Log.d(TAG, "Bluetooth persisted state is off. Not turning on Bluetooth.");
489 return;
490 }
491 //Fall through to MESSAGE_ENABLE
492 }
fredc0f420372012-04-12 00:02:00 -0700493 case MESSAGE_ENABLE: {
fredcf2458862012-04-16 15:18:27 -0700494 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700495 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth +
496 " isConnected = " + isConnected());
497 }
498 boolean persist = (1==msg.arg1);
499 if (persist) {
500 persistBluetoothSetting(true);
501 }
fredc0f420372012-04-12 00:02:00 -0700502 if (mBluetooth == null) {
503 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700504 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700505 //Start bind timeout and bind
506 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
507 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
508 Intent i = new Intent(IBluetooth.class.getName());
509 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
510 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
511 mContext.startService(i);
512 mConnection.setGetNameAddressOnly(false);
fredc649fe492012-04-19 01:07:18 -0700513 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
fredc0f420372012-04-12 00:02:00 -0700514 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
fredc649fe492012-04-19 01:07:18 -0700515 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
fredc0f420372012-04-12 00:02:00 -0700516 }
517 }
518 } else {
519 //Check if name and address is loaded if not get it first.
520 if (ALWAYS_SYNC_NAME_ADDRESS || !isNameAndAddressSet()) {
521 try {
fredc649fe492012-04-19 01:07:18 -0700522 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
fredc0f420372012-04-12 00:02:00 -0700523 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
524 } catch (RemoteException e) {Log.e(TAG, "", e);};
525 }
fredc649fe492012-04-19 01:07:18 -0700526 Intent i = new Intent(IBluetooth.class.getName());
527 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
528 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
529 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700530 }
531 // TODO(BT) what if service failed to start:
532 // [fc] fixed: watch for bind timeout and handle accordingly
533 // TODO(BT) persist the setting depending on argument
534 // [fc]: let AdapterServiceHandle
535 }
fredc649fe492012-04-19 01:07:18 -0700536 break;
537 case MESSAGE_AIRPLANE_MODE_ON:;
538 if (DBG) {
539 Log.d(TAG, "MESSAGE_AIRPLANE_MODE_ON: mBluetooth = " + mBluetooth +
540 " isConnected = " + isConnected());
541 //Fall through to MESSAGE_DISABLE
542 }
fredc0f420372012-04-12 00:02:00 -0700543 case MESSAGE_DISABLE:
544 if (mBluetooth != null ) {
fredc649fe492012-04-19 01:07:18 -0700545 boolean persist = (1==msg.arg1);
546 if (persist) {
547 persistBluetoothSetting(false);
fredc0f420372012-04-12 00:02:00 -0700548 }
fredc649fe492012-04-19 01:07:18 -0700549 mConnection.setGetNameAddressOnly(false);
550 if (DBG) Log.d(TAG,"Sending off request.");
551 Intent i = new Intent(IBluetooth.class.getName());
552 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
553 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
554 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700555 }
fredc0f420372012-04-12 00:02:00 -0700556 // TODO(BT) what if service failed to stop:
557 // [fc] fixed: watch for disable event and unbind accordingly
558 // TODO(BT) persist the setting depending on argument
559 // [fc]: let AdapterServiceHandle
560
561 break;
562 case MESSAGE_REGISTER_ADAPTER:
563 {
564 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700565 boolean added = mCallbacks.register(callback);
566 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700567 }
568 break;
569 case MESSAGE_UNREGISTER_ADAPTER:
570 {
571 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700572 boolean removed = mCallbacks.unregister(callback);
573 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700574 }
575 break;
576 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
577 {
578 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700579 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700580 }
581 break;
582 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
583 {
584 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700585 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700586 }
587 break;
588 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
589 {
fredc649fe492012-04-19 01:07:18 -0700590 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
591
fredc0f420372012-04-12 00:02:00 -0700592 //Remove timeout
593 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
594
595 IBinder service = (IBinder) msg.obj;
596 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700597 mBinding = false;
598 mBluetooth = IBluetooth.Stub.asInterface(service);
599 }
600
601 if (mConnection.isGetNameAddressOnly()) {
602 //Request GET NAME AND ADDRESS
603 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
604 mHandler.sendMessage(getMsg);
605 return;
606 }
fredcd6883532012-04-25 17:46:13 -0700607 int n = mCallbacks.beginBroadcast();
608 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
609 for (int i=0; i <n;i++) {
610 try {
611 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
612 } catch (RemoteException e) {
613 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
614 }
fredc0f420372012-04-12 00:02:00 -0700615 }
fredcd6883532012-04-25 17:46:13 -0700616 mCallbacks.finishBroadcast();
fredc0f420372012-04-12 00:02:00 -0700617
fredc0f420372012-04-12 00:02:00 -0700618 }
fredc649fe492012-04-19 01:07:18 -0700619 break;
620 case MESSAGE_TIMEOUT_BIND: {
621 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700622 synchronized(mConnection) {
623 mBinding = false;
624 }
625 }
fredc649fe492012-04-19 01:07:18 -0700626 break;
fredc0f420372012-04-12 00:02:00 -0700627 case MESSAGE_BLUETOOTH_ON:
628 {
fredc649fe492012-04-19 01:07:18 -0700629 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_ON");
fredcd6883532012-04-25 17:46:13 -0700630 int n = mStateChangeCallbacks.beginBroadcast();
631 Log.d(TAG,"Broadcasting onBluetoothStateChange() to " + n + " receivers.");
632 for (int i=0; i <n;i++) {
633 try {
634 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(true);
635 } catch (RemoteException e) {
636 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
fredc0f420372012-04-12 00:02:00 -0700637 }
fredc0f420372012-04-12 00:02:00 -0700638 }
fredcd6883532012-04-25 17:46:13 -0700639 mStateChangeCallbacks.finishBroadcast();
fredc0f420372012-04-12 00:02:00 -0700640 }
641 break;
fredc0f420372012-04-12 00:02:00 -0700642 case MESSAGE_BLUETOOTH_OFF:
643 {
fredc649fe492012-04-19 01:07:18 -0700644 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_OFF");
fredcd6883532012-04-25 17:46:13 -0700645 int n = mStateChangeCallbacks.beginBroadcast();
646 Log.d(TAG,"Broadcasting onBluetoothStateChange() to " + n + " receivers.");
647 for (int i=0; i <n;i++) {
648 try {
649 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(false);
650 } catch (RemoteException e) {
651 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
fredc0f420372012-04-12 00:02:00 -0700652 }
fredc0f420372012-04-12 00:02:00 -0700653 }
fredcd6883532012-04-25 17:46:13 -0700654 mStateChangeCallbacks.finishBroadcast();
655 sendBluetoothServiceDownEvent();
fredc649fe492012-04-19 01:07:18 -0700656 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700657 }
fredc649fe492012-04-19 01:07:18 -0700658 break;
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");
fredcd6883532012-04-25 17:46:13 -0700662 sendBluetoothServiceDownEvent();
fredc0f420372012-04-12 00:02:00 -0700663 }
fredc649fe492012-04-19 01:07:18 -0700664 break;
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 }
671 }
fredc649fe492012-04-19 01:07:18 -0700672 break;
fredc0f420372012-04-12 00:02:00 -0700673 }
674 }
675 };
676}