blob: 3c3b9db182bb2433ae200dcf8414e407b50d92f9 [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;
fredc0f420372012-04-12 00:02:00 -070028class BluetoothManagerService extends IBluetoothManager.Stub {
29 private static final String TAG = "BluetoothManagerService";
30 private static final boolean DBG = true;
31
zzyc2f5cc52012-05-01 18:05:08 -070032 private static final boolean ALWAYS_SYNC_NAME_ADDRESS=false; //true; //If true, always load name and address
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_AIRPLANE_MODE_OFF=10;
45 private static final int MESSAGE_AIRPLANE_MODE_ON=11;
46 private static final int MESSAGE_REGISTER_ADAPTER = 20;
47 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
48 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
49 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
50 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
51 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
52 private static final int MESSAGE_BLUETOOTH_ON = 50;
53 private static final int MESSAGE_BLUETOOTH_OFF = 51;
fredc0f420372012-04-12 00:02:00 -070054 private static final int MESSAGE_TIMEOUT_BIND =100;
55 private static final int MESSAGE_TIMEOUT_UNBIND =101;
56 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
57 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
58 private static final int MAX_SAVE_RETRIES=3;
59
60 private final Context mContext;
61 private String mAddress;
62 private String mName;
63 private ContentResolver mContentResolver;
fredcd6883532012-04-25 17:46:13 -070064 private RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
65 private 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
fredc0f420372012-04-12 00:02:00 -070083 private BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -070084 @Override
85 public void onReceive(Context context, Intent intent) {
86 String action = intent.getAction();
87 if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
88 int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
89 if (state == BluetoothAdapter.STATE_OFF) {
90 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_OFF);
91 mHandler.sendMessage(msg);
92 } else if (state == BluetoothAdapter.STATE_ON) {
93 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_ON);
94 mHandler.sendMessage(msg);
95 }
96 } else if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
97 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
98 Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
99 if (newName != null) {
100 storeNameAndAddress(newName, null);
101 }
fredc649fe492012-04-19 01:07:18 -0700102 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
103 if (isAirplaneModeOn()) {
104 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_ON);
105 msg.arg1=0;
106 mHandler.sendMessage(msg);
107 } else {
108 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_OFF);
109 msg.arg1=0;
110 mHandler.sendMessage(msg);
111 }
fredc0f420372012-04-12 00:02:00 -0700112 }
113 }
114 };
115
116 BluetoothManagerService(Context context) {
117 mContext = context;
118 mBluetooth = null;
119 mBinding = false;
120 mUnbinding = false;
121 mAddress = null;
122 mName = null;
123 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700124 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
125 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
fredc649fe492012-04-19 01:07:18 -0700126 IntentFilter mFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
fredc116d1d462012-04-20 14:47:08 -0700127 mFilter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
fredc649fe492012-04-19 01:07:18 -0700128 registerForAirplaneMode(mFilter);
fredc0f420372012-04-12 00:02:00 -0700129 mContext.registerReceiver(mReceiver, mFilter);
fredc649fe492012-04-19 01:07:18 -0700130 boolean airplaneModeOn = isAirplaneModeOn();
131 boolean bluetoothOn = isBluetoothPersistedStateOn();
fredc0f420372012-04-12 00:02:00 -0700132 loadStoredNameAndAddress();
fredc649fe492012-04-19 01:07:18 -0700133 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
Andre Eisenbacha732ffd2012-05-02 00:39:24 -0700134 if (bluetoothOn) {
fredc0f420372012-04-12 00:02:00 -0700135 //Enable
fredc649fe492012-04-19 01:07:18 -0700136 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
fredc0f420372012-04-12 00:02:00 -0700137 enable();
138 } else if (ALWAYS_SYNC_NAME_ADDRESS || !isNameAndAddressSet()) {
fredc649fe492012-04-19 01:07:18 -0700139 //Sync the Bluetooth name and address from the Bluetooth Adapter
140 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
fredc0f420372012-04-12 00:02:00 -0700141 getNameAndAddress();
142 }
143 }
144
fredc649fe492012-04-19 01:07:18 -0700145 /**
146 * Returns true if airplane mode is currently on
147 */
148 private final boolean isAirplaneModeOn() {
149 return Settings.System.getInt(mContext.getContentResolver(),
150 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
151 }
152
153 /**
154 * Returns true if the Bluetooth saved state is "on"
155 */
156 private final boolean isBluetoothPersistedStateOn() {
157 return Settings.Secure.getInt(mContentResolver,
158 Settings.Secure.BLUETOOTH_ON, 0) ==1;
159 }
160
161 /**
162 * Save the Bluetooth on/off state
163 *
164 */
165 private void persistBluetoothSetting(boolean setOn) {
166 Settings.Secure.putInt(mContext.getContentResolver(),
167 Settings.Secure.BLUETOOTH_ON,
168 setOn ? 1 : 0);
169 }
170
171 /**
172 * Returns true if the Bluetooth Adapter's name and address is
173 * locally cached
174 * @return
175 */
fredc0f420372012-04-12 00:02:00 -0700176 private boolean isNameAndAddressSet() {
177 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
178 }
179
fredc649fe492012-04-19 01:07:18 -0700180 /**
181 * Retrieve the Bluetooth Adapter's name and address and save it in
182 * in the local cache
183 */
fredc0f420372012-04-12 00:02:00 -0700184 private void loadStoredNameAndAddress() {
185 if (DBG) Log.d(TAG, "Loading stored name and address");
186 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
187 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
188 if (mName == null || mAddress == null) {
189 if (DBG) Log.d(TAG, "Name or address not cached...");
190 }
191 }
192
fredc649fe492012-04-19 01:07:18 -0700193 /**
194 * Save the Bluetooth name and address in the persistent store.
195 * Only non-null values will be saved.
196 * @param name
197 * @param address
198 */
fredc0f420372012-04-12 00:02:00 -0700199 private void storeNameAndAddress(String name, String address) {
200 if (name != null) {
201 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700202 mName = name;
fredc649fe492012-04-19 01:07:18 -0700203 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
204 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700205 }
206
207 if (address != null) {
208 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700209 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700210 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
211 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700212 }
213 }
214
215 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
216 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
217 "Need BLUETOOTH permission");
218 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
219 msg.obj = callback;
220 mHandler.sendMessage(msg);
221 synchronized(mConnection) {
222 return mBluetooth;
223 }
224 }
225
226 public void unregisterAdapter(IBluetoothManagerCallback callback) {
227 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
228 "Need BLUETOOTH permission");
229 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
230 msg.obj = callback;
231 mHandler.sendMessage(msg);
232 }
233
234 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
235 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
236 "Need BLUETOOTH permission");
237 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
238 msg.obj = callback;
239 mHandler.sendMessage(msg);
240 }
241
242 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
243 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
244 "Need BLUETOOTH permission");
245 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
246 msg.obj = callback;
247 mHandler.sendMessage(msg);
248 }
249
250 public boolean isEnabled() {
251 synchronized(mConnection) {
252 try {
253 return (mBluetooth != null && mBluetooth.isEnabled());
254 } catch (RemoteException e) {
255 Log.e(TAG, "isEnabled()", e);
256 }
257 }
258 return false;
259 }
260
fredcf2458862012-04-16 15:18:27 -0700261 private boolean isConnected() {
262 return mBluetooth != null;
263 }
fredc649fe492012-04-19 01:07:18 -0700264
fredc0f420372012-04-12 00:02:00 -0700265 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700266 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700267 Log.d(TAG,"getNameAndAddress(): mBluetooth = " +
268 (mBluetooth==null?"null":mBluetooth) +
269 " mBinding = " + mBinding +
270 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700271 }
fredc0f420372012-04-12 00:02:00 -0700272 synchronized(mConnection) {
273 if (mBinding) return ;
fredcf2458862012-04-16 15:18:27 -0700274 if (!isConnected()) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700275 }
276 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
277 mHandler.sendMessage(msg);
278 }
279
280 public boolean enable() {
281 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
282 "Need BLUETOOTH ADMIN permission");
fredcf2458862012-04-16 15:18:27 -0700283 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700284 Log.d(TAG,"enable(): mBluetooth =" +
285 (mBluetooth==null?"null":mBluetooth) +
286 " mBinding = " + mBinding +
287 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700288 }
289
fredc0f420372012-04-12 00:02:00 -0700290 synchronized(mConnection) {
fredc649fe492012-04-19 01:07:18 -0700291 //if (mBluetooth != null) return false;
292 if (mBinding) {
293 Log.w(TAG,"enable(): binding in progress. Returning..");
294 return true;
295 }
fredcf2458862012-04-16 15:18:27 -0700296 if (!isConnected()) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700297 }
fredc116d1d462012-04-20 14:47:08 -0700298
fredc0f420372012-04-12 00:02:00 -0700299 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
fredc649fe492012-04-19 01:07:18 -0700300 msg.arg1=1; //persist
fredc0f420372012-04-12 00:02:00 -0700301 mHandler.sendMessage(msg);
302 return true;
303 }
304
305 public boolean disable(boolean persist) {
306 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
307 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
fredcf2458862012-04-16 15:18:27 -0700308 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700309 Log.d(TAG,"disable(): mBluetooth = " +
310 (mBluetooth==null?"null":mBluetooth) +
311 " mBinding = " + mBinding +
312 " isConnected = " + isConnected());}
fredcf2458862012-04-16 15:18:27 -0700313
fredc0f420372012-04-12 00:02:00 -0700314 synchronized(mConnection) {
315 if (mBluetooth == null) return false;
fredc0f420372012-04-12 00:02:00 -0700316 }
317 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700318 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700319 mHandler.sendMessage(msg);
320 return true;
321 }
322
fredc649fe492012-04-19 01:07:18 -0700323 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700324 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700325 Log.d(TAG,"unbindAndFinish(): " +
326 (mBluetooth==null?"null":mBluetooth) +
327 " mBinding = " + mBinding +
328 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700329 }
330
fredc0f420372012-04-12 00:02:00 -0700331 synchronized (mConnection) {
332 if (mUnbinding) return;
333 mUnbinding = true;
fredcf2458862012-04-16 15:18:27 -0700334 if (isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700335 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700336 mBluetooth = null;
337 //Unbind
fredc0f420372012-04-12 00:02:00 -0700338 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700339 mUnbinding = false;
fredcf2458862012-04-16 15:18:27 -0700340 } else {
341 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700342 }
343 }
344 }
345
fredcd6883532012-04-25 17:46:13 -0700346 private void sendBluetoothServiceDownEvent() {
347 if (!mConnection.isGetNameAddressOnly()) {
348 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
349 int n = mCallbacks.beginBroadcast();
350 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
351 for (int i=0; i <n;i++) {
352 try {
353 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
354 } catch (RemoteException e) {
355 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
356 }
357 }
358 mCallbacks.finishBroadcast();
359 }
360 }
fredc0f420372012-04-12 00:02:00 -0700361 public String getAddress() {
362 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
363 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700364 synchronized(mConnection) {
365 if (mBluetooth != null) {
366 try {
367 return mBluetooth.getAddress();
368 } catch (RemoteException e) {
369 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
370 }
371 }
372 }
fredc0f420372012-04-12 00:02:00 -0700373 return mAddress;
374 }
fredc649fe492012-04-19 01:07:18 -0700375
fredc0f420372012-04-12 00:02:00 -0700376 public String getName() {
377 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
378 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700379 synchronized(mConnection) {
380 if (mBluetooth != null) {
381 try {
382 return mBluetooth.getName();
383 } catch (RemoteException e) {
384 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
385 }
386 }
387 }
fredc0f420372012-04-12 00:02:00 -0700388 return mName;
389 }
390
fredc0f420372012-04-12 00:02:00 -0700391 private class BluetoothServiceConnection implements ServiceConnection {
392
393 private boolean mGetNameAddressOnly;
394
395 public void setGetNameAddressOnly(boolean getOnly) {
396 mGetNameAddressOnly = getOnly;
397 }
398
399 public boolean isGetNameAddressOnly() {
400 return mGetNameAddressOnly;
401 }
402
403 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700404 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700405 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
406 msg.obj = service;
407 mHandler.sendMessage(msg);
408 }
409
410 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700411 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700412 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700413 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
414 mHandler.sendMessage(msg);
415 }
416 }
417
418 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
419
420 private final Handler mHandler = new Handler() {
421 @Override
422 public void handleMessage(Message msg) {
423 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700424 switch (msg.what) {
425 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700426 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700427 if (mBluetooth == null) {
428 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700429 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700430 if (DBG) Log.d(TAG, "Binding to service to get name and address");
431 mConnection.setGetNameAddressOnly(true);
432 //Start bind timeout and bind
433 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
434 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
435 Intent i = new Intent(IBluetooth.class.getName());
436 if (!mContext.bindService(i, mConnection,
437 Context.BIND_AUTO_CREATE)) {
438 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
439 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
440 }
441 }
442 } else {
443 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
444 mHandler.sendMessage(saveMsg);
445 }
446 }
fredc649fe492012-04-19 01:07:18 -0700447 break;
fredc0f420372012-04-12 00:02:00 -0700448 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700449 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700450 if (mBluetooth != null) {
451 String name = null;
452 String address = null;
453 try {
454 name = mBluetooth.getName();
455 address = mBluetooth.getAddress();
456 } catch (RemoteException re) {
457 Log.e(TAG,"",re);
458 }
459
460 if (name != null && address != null) {
461 storeNameAndAddress(name,address);
fredc649fe492012-04-19 01:07:18 -0700462 Intent i = new Intent(IBluetooth.class.getName());
463 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
464 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
465 mContext.startService(i);
fredcd6883532012-04-25 17:46:13 -0700466 sendBluetoothServiceDownEvent();
fredc649fe492012-04-19 01:07:18 -0700467 unbindAndFinish();
468 } else {
fredc0f420372012-04-12 00:02:00 -0700469 if (msg.arg1 < MAX_SAVE_RETRIES) {
470 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
471 retryMsg.arg1= 1+msg.arg1;
472 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
473 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
474 } else {
475 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
fredcd6883532012-04-25 17:46:13 -0700476 sendBluetoothServiceDownEvent();
fredc649fe492012-04-19 01:07:18 -0700477 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700478 }
479 }
480 }
481 }
fredc649fe492012-04-19 01:07:18 -0700482 break;
483 case MESSAGE_AIRPLANE_MODE_OFF: {
484 if (DBG) Log.d(TAG,"MESSAGE_AIRPLANE_MODE_OFF");
485 //Check if we should turn on bluetooth
486 if (!isBluetoothPersistedStateOn()) {
487 if (DBG)Log.d(TAG, "Bluetooth persisted state is off. Not turning on Bluetooth.");
488 return;
489 }
490 //Fall through to MESSAGE_ENABLE
491 }
fredc0f420372012-04-12 00:02:00 -0700492 case MESSAGE_ENABLE: {
fredcf2458862012-04-16 15:18:27 -0700493 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700494 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth +
495 " isConnected = " + isConnected());
496 }
497 boolean persist = (1==msg.arg1);
498 if (persist) {
499 persistBluetoothSetting(true);
500 }
fredc0f420372012-04-12 00:02:00 -0700501 if (mBluetooth == null) {
502 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700503 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700504 //Start bind timeout and bind
505 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
506 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
507 Intent i = new Intent(IBluetooth.class.getName());
508 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
509 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
510 mContext.startService(i);
511 mConnection.setGetNameAddressOnly(false);
fredc649fe492012-04-19 01:07:18 -0700512 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
fredc0f420372012-04-12 00:02:00 -0700513 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
fredc649fe492012-04-19 01:07:18 -0700514 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
fredc0f420372012-04-12 00:02:00 -0700515 }
516 }
517 } else {
518 //Check if name and address is loaded if not get it first.
519 if (ALWAYS_SYNC_NAME_ADDRESS || !isNameAndAddressSet()) {
520 try {
fredc649fe492012-04-19 01:07:18 -0700521 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
fredc0f420372012-04-12 00:02:00 -0700522 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
523 } catch (RemoteException e) {Log.e(TAG, "", e);};
524 }
fredc649fe492012-04-19 01:07:18 -0700525 Intent i = new Intent(IBluetooth.class.getName());
526 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
527 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
528 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700529 }
530 // TODO(BT) what if service failed to start:
531 // [fc] fixed: watch for bind timeout and handle accordingly
532 // TODO(BT) persist the setting depending on argument
533 // [fc]: let AdapterServiceHandle
534 }
fredc649fe492012-04-19 01:07:18 -0700535 break;
536 case MESSAGE_AIRPLANE_MODE_ON:;
537 if (DBG) {
538 Log.d(TAG, "MESSAGE_AIRPLANE_MODE_ON: mBluetooth = " + mBluetooth +
539 " isConnected = " + isConnected());
540 //Fall through to MESSAGE_DISABLE
541 }
fredc0f420372012-04-12 00:02:00 -0700542 case MESSAGE_DISABLE:
543 if (mBluetooth != null ) {
fredc649fe492012-04-19 01:07:18 -0700544 boolean persist = (1==msg.arg1);
545 if (persist) {
546 persistBluetoothSetting(false);
fredc0f420372012-04-12 00:02:00 -0700547 }
fredc649fe492012-04-19 01:07:18 -0700548 mConnection.setGetNameAddressOnly(false);
549 if (DBG) Log.d(TAG,"Sending off request.");
550 Intent i = new Intent(IBluetooth.class.getName());
551 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
552 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
553 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700554 }
fredc0f420372012-04-12 00:02:00 -0700555 // TODO(BT) what if service failed to stop:
556 // [fc] fixed: watch for disable event and unbind accordingly
557 // TODO(BT) persist the setting depending on argument
558 // [fc]: let AdapterServiceHandle
559
560 break;
561 case MESSAGE_REGISTER_ADAPTER:
562 {
563 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700564 boolean added = mCallbacks.register(callback);
565 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700566 }
567 break;
568 case MESSAGE_UNREGISTER_ADAPTER:
569 {
570 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700571 boolean removed = mCallbacks.unregister(callback);
572 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700573 }
574 break;
575 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
576 {
577 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700578 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700579 }
580 break;
581 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
582 {
583 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700584 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700585 }
586 break;
587 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
588 {
fredc649fe492012-04-19 01:07:18 -0700589 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
590
fredc0f420372012-04-12 00:02:00 -0700591 //Remove timeout
592 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
593
594 IBinder service = (IBinder) msg.obj;
595 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700596 mBinding = false;
597 mBluetooth = IBluetooth.Stub.asInterface(service);
598 }
599
600 if (mConnection.isGetNameAddressOnly()) {
601 //Request GET NAME AND ADDRESS
602 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
603 mHandler.sendMessage(getMsg);
604 return;
605 }
fredcd6883532012-04-25 17:46:13 -0700606 int n = mCallbacks.beginBroadcast();
607 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
608 for (int i=0; i <n;i++) {
609 try {
610 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
611 } catch (RemoteException e) {
612 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
613 }
fredc0f420372012-04-12 00:02:00 -0700614 }
fredcd6883532012-04-25 17:46:13 -0700615 mCallbacks.finishBroadcast();
fredc0f420372012-04-12 00:02:00 -0700616
fredc0f420372012-04-12 00:02:00 -0700617 }
fredc649fe492012-04-19 01:07:18 -0700618 break;
619 case MESSAGE_TIMEOUT_BIND: {
620 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700621 synchronized(mConnection) {
622 mBinding = false;
623 }
624 }
fredc649fe492012-04-19 01:07:18 -0700625 break;
fredc0f420372012-04-12 00:02:00 -0700626 case MESSAGE_BLUETOOTH_ON:
627 {
fredc649fe492012-04-19 01:07:18 -0700628 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_ON");
fredcd6883532012-04-25 17:46:13 -0700629 int n = mStateChangeCallbacks.beginBroadcast();
630 Log.d(TAG,"Broadcasting onBluetoothStateChange() to " + n + " receivers.");
631 for (int i=0; i <n;i++) {
632 try {
633 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(true);
634 } catch (RemoteException e) {
635 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
fredc0f420372012-04-12 00:02:00 -0700636 }
fredc0f420372012-04-12 00:02:00 -0700637 }
fredcd6883532012-04-25 17:46:13 -0700638 mStateChangeCallbacks.finishBroadcast();
fredc0f420372012-04-12 00:02:00 -0700639 }
640 break;
fredc0f420372012-04-12 00:02:00 -0700641 case MESSAGE_BLUETOOTH_OFF:
642 {
fredc649fe492012-04-19 01:07:18 -0700643 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_OFF");
fredcd6883532012-04-25 17:46:13 -0700644 int n = mStateChangeCallbacks.beginBroadcast();
645 Log.d(TAG,"Broadcasting onBluetoothStateChange() to " + n + " receivers.");
646 for (int i=0; i <n;i++) {
647 try {
648 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(false);
649 } catch (RemoteException e) {
650 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
fredc0f420372012-04-12 00:02:00 -0700651 }
fredc0f420372012-04-12 00:02:00 -0700652 }
fredcd6883532012-04-25 17:46:13 -0700653 mStateChangeCallbacks.finishBroadcast();
654 sendBluetoothServiceDownEvent();
fredc649fe492012-04-19 01:07:18 -0700655 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700656 }
fredc649fe492012-04-19 01:07:18 -0700657 break;
fredc0f420372012-04-12 00:02:00 -0700658 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
659 {
fredc649fe492012-04-19 01:07:18 -0700660 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredcd6883532012-04-25 17:46:13 -0700661 sendBluetoothServiceDownEvent();
fredc0f420372012-04-12 00:02:00 -0700662 }
fredc649fe492012-04-19 01:07:18 -0700663 break;
fredc0f420372012-04-12 00:02:00 -0700664 case MESSAGE_TIMEOUT_UNBIND:
665 {
fredc649fe492012-04-19 01:07:18 -0700666 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700667 synchronized(mConnection) {
668 mUnbinding = false;
669 }
670 }
fredc649fe492012-04-19 01:07:18 -0700671 break;
fredc0f420372012-04-12 00:02:00 -0700672 }
673 }
674 };
675}