blob: 56487fe9c2597e82d962c4f48fd24140d8ca9e60 [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;
22import android.os.RemoteException;
23import android.provider.Settings;
24import android.util.Log;
25import java.util.List;
26import java.util.ArrayList;
27
28class BluetoothManagerService extends IBluetoothManager.Stub {
29 private static final String TAG = "BluetoothManagerService";
30 private static final boolean DBG = true;
31
32 private static final boolean ALWAYS_SYNC_NAME_ADDRESS=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;
64 private List<IBluetoothManagerCallback> mCallbacks;
65 private List<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();
124 mCallbacks = new ArrayList<IBluetoothManagerCallback>();
125 mStateChangeCallbacks = new ArrayList<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);
134 if (!airplaneModeOn && 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.");
336 mContext.unbindService(mConnection);
337 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED));
fredcf2458862012-04-16 15:18:27 -0700338 } else {
339 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700340 }
341 }
342 }
343
344 public String getAddress() {
345 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
346 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700347 synchronized(mConnection) {
348 if (mBluetooth != null) {
349 try {
350 return mBluetooth.getAddress();
351 } catch (RemoteException e) {
352 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
353 }
354 }
355 }
fredc0f420372012-04-12 00:02:00 -0700356 return mAddress;
357 }
fredc649fe492012-04-19 01:07:18 -0700358
fredc0f420372012-04-12 00:02:00 -0700359 public String getName() {
360 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
361 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700362 synchronized(mConnection) {
363 if (mBluetooth != null) {
364 try {
365 return mBluetooth.getName();
366 } catch (RemoteException e) {
367 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
368 }
369 }
370 }
fredc0f420372012-04-12 00:02:00 -0700371 return mName;
372 }
373
fredc0f420372012-04-12 00:02:00 -0700374 private class BluetoothServiceConnection implements ServiceConnection {
375
376 private boolean mGetNameAddressOnly;
377
378 public void setGetNameAddressOnly(boolean getOnly) {
379 mGetNameAddressOnly = getOnly;
380 }
381
382 public boolean isGetNameAddressOnly() {
383 return mGetNameAddressOnly;
384 }
385
386 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700387 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700388 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
389 msg.obj = service;
390 mHandler.sendMessage(msg);
391 }
392
393 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700394 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700395 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700396 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
397 mHandler.sendMessage(msg);
398 }
399 }
400
401 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
402
403 private final Handler mHandler = new Handler() {
404 @Override
405 public void handleMessage(Message msg) {
406 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700407 switch (msg.what) {
408 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700409 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700410 if (mBluetooth == null) {
411 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700412 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700413 if (DBG) Log.d(TAG, "Binding to service to get name and address");
414 mConnection.setGetNameAddressOnly(true);
415 //Start bind timeout and bind
416 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
417 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
418 Intent i = new Intent(IBluetooth.class.getName());
419 if (!mContext.bindService(i, mConnection,
420 Context.BIND_AUTO_CREATE)) {
421 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
422 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
423 }
424 }
425 } else {
426 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
427 mHandler.sendMessage(saveMsg);
428 }
429 }
fredc649fe492012-04-19 01:07:18 -0700430 break;
fredc0f420372012-04-12 00:02:00 -0700431 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700432 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700433 if (mBluetooth != null) {
434 String name = null;
435 String address = null;
436 try {
437 name = mBluetooth.getName();
438 address = mBluetooth.getAddress();
439 } catch (RemoteException re) {
440 Log.e(TAG,"",re);
441 }
442
443 if (name != null && address != null) {
444 storeNameAndAddress(name,address);
fredc649fe492012-04-19 01:07:18 -0700445 Intent i = new Intent(IBluetooth.class.getName());
446 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
447 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
448 mContext.startService(i);
449 unbindAndFinish();
450 } else {
fredc0f420372012-04-12 00:02:00 -0700451 if (msg.arg1 < MAX_SAVE_RETRIES) {
452 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
453 retryMsg.arg1= 1+msg.arg1;
454 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
455 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
456 } else {
457 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
fredc649fe492012-04-19 01:07:18 -0700458 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700459 }
460 }
461 }
462 }
fredc649fe492012-04-19 01:07:18 -0700463 break;
464 case MESSAGE_AIRPLANE_MODE_OFF: {
465 if (DBG) Log.d(TAG,"MESSAGE_AIRPLANE_MODE_OFF");
466 //Check if we should turn on bluetooth
467 if (!isBluetoothPersistedStateOn()) {
468 if (DBG)Log.d(TAG, "Bluetooth persisted state is off. Not turning on Bluetooth.");
469 return;
470 }
471 //Fall through to MESSAGE_ENABLE
472 }
fredc0f420372012-04-12 00:02:00 -0700473 case MESSAGE_ENABLE: {
fredcf2458862012-04-16 15:18:27 -0700474 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700475 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth +
476 " isConnected = " + isConnected());
477 }
478 boolean persist = (1==msg.arg1);
479 if (persist) {
480 persistBluetoothSetting(true);
481 }
fredc0f420372012-04-12 00:02:00 -0700482 if (mBluetooth == null) {
483 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700484 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700485 //Start bind timeout and bind
486 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
487 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
488 Intent i = new Intent(IBluetooth.class.getName());
489 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
490 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
491 mContext.startService(i);
492 mConnection.setGetNameAddressOnly(false);
fredc649fe492012-04-19 01:07:18 -0700493 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
fredc0f420372012-04-12 00:02:00 -0700494 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
fredc649fe492012-04-19 01:07:18 -0700495 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
fredc0f420372012-04-12 00:02:00 -0700496 }
497 }
498 } else {
499 //Check if name and address is loaded if not get it first.
500 if (ALWAYS_SYNC_NAME_ADDRESS || !isNameAndAddressSet()) {
501 try {
fredc649fe492012-04-19 01:07:18 -0700502 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
fredc0f420372012-04-12 00:02:00 -0700503 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
504 } catch (RemoteException e) {Log.e(TAG, "", e);};
505 }
fredc649fe492012-04-19 01:07:18 -0700506 Intent i = new Intent(IBluetooth.class.getName());
507 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
508 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
509 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700510 }
511 // TODO(BT) what if service failed to start:
512 // [fc] fixed: watch for bind timeout and handle accordingly
513 // TODO(BT) persist the setting depending on argument
514 // [fc]: let AdapterServiceHandle
515 }
fredc649fe492012-04-19 01:07:18 -0700516 break;
517 case MESSAGE_AIRPLANE_MODE_ON:;
518 if (DBG) {
519 Log.d(TAG, "MESSAGE_AIRPLANE_MODE_ON: mBluetooth = " + mBluetooth +
520 " isConnected = " + isConnected());
521 //Fall through to MESSAGE_DISABLE
522 }
fredc0f420372012-04-12 00:02:00 -0700523 case MESSAGE_DISABLE:
524 if (mBluetooth != null ) {
fredc649fe492012-04-19 01:07:18 -0700525 boolean persist = (1==msg.arg1);
526 if (persist) {
527 persistBluetoothSetting(false);
fredc0f420372012-04-12 00:02:00 -0700528 }
fredc649fe492012-04-19 01:07:18 -0700529 mConnection.setGetNameAddressOnly(false);
530 if (DBG) Log.d(TAG,"Sending off request.");
531 Intent i = new Intent(IBluetooth.class.getName());
532 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
533 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
534 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700535 }
fredc0f420372012-04-12 00:02:00 -0700536 // TODO(BT) what if service failed to stop:
537 // [fc] fixed: watch for disable event and unbind accordingly
538 // TODO(BT) persist the setting depending on argument
539 // [fc]: let AdapterServiceHandle
540
541 break;
542 case MESSAGE_REGISTER_ADAPTER:
543 {
544 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
545 mCallbacks.add(callback);
546 }
547 break;
548 case MESSAGE_UNREGISTER_ADAPTER:
549 {
550 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
551 mCallbacks.remove(callback);
552 }
553 break;
554 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
555 {
556 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
557 mStateChangeCallbacks.add(callback);
558 }
559 break;
560 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
561 {
562 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
563 mStateChangeCallbacks.remove(callback);
564 }
565 break;
566 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
567 {
fredc649fe492012-04-19 01:07:18 -0700568 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
569
fredc0f420372012-04-12 00:02:00 -0700570 //Remove timeout
571 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
572
573 IBinder service = (IBinder) msg.obj;
574 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700575 mBinding = false;
576 mBluetooth = IBluetooth.Stub.asInterface(service);
577 }
578
579 if (mConnection.isGetNameAddressOnly()) {
580 //Request GET NAME AND ADDRESS
581 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
582 mHandler.sendMessage(getMsg);
583 return;
584 }
585
fredc0f420372012-04-12 00:02:00 -0700586 try {
587 for (IBluetoothManagerCallback callback : mCallbacks) {
588 callback.onBluetoothServiceUp(mBluetooth);
589 }
590 } catch (RemoteException e) {
591 Log.e(TAG, "", e);
592 }
593
fredc0f420372012-04-12 00:02:00 -0700594 }
fredc649fe492012-04-19 01:07:18 -0700595 break;
596 case MESSAGE_TIMEOUT_BIND: {
597 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700598 synchronized(mConnection) {
599 mBinding = false;
600 }
601 }
fredc649fe492012-04-19 01:07:18 -0700602 break;
fredc0f420372012-04-12 00:02:00 -0700603 case MESSAGE_BLUETOOTH_ON:
604 {
fredc649fe492012-04-19 01:07:18 -0700605 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_ON");
606 try {
fredc0f420372012-04-12 00:02:00 -0700607 for (IBluetoothStateChangeCallback callback : mStateChangeCallbacks) {
608 callback.onBluetoothStateChange(true);
609 }
610 } catch (RemoteException e) {
611 Log.e(TAG, "", e);
612 }
613 }
614 break;
fredc0f420372012-04-12 00:02:00 -0700615 case MESSAGE_BLUETOOTH_OFF:
616 {
fredc649fe492012-04-19 01:07:18 -0700617 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_OFF");
fredc0f420372012-04-12 00:02:00 -0700618 try {
619 for (IBluetoothStateChangeCallback callback : mStateChangeCallbacks) {
620 callback.onBluetoothStateChange(false);
621 }
622 } catch (RemoteException e) {
623 Log.e(TAG, "", e);
624 }
fredc649fe492012-04-19 01:07:18 -0700625 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700626 }
fredc649fe492012-04-19 01:07:18 -0700627 break;
fredc0f420372012-04-12 00:02:00 -0700628 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
629 {
fredc649fe492012-04-19 01:07:18 -0700630 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredc0f420372012-04-12 00:02:00 -0700631 boolean isUnexpectedDisconnect = false;
632 synchronized(mConnection) {
633 mBluetooth = null;
fredc0f420372012-04-12 00:02:00 -0700634 if (mUnbinding) {
635 mUnbinding = false;
636 } else {
637 isUnexpectedDisconnect = true;
638 }
639 }
fredc649fe492012-04-19 01:07:18 -0700640 if (!mConnection.isGetNameAddressOnly()) {
641 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: Calling onBluetoothSerivceDown callbacks");
fredc0f420372012-04-12 00:02:00 -0700642 try {
643 for (IBluetoothManagerCallback callback : mCallbacks) {
644 callback.onBluetoothServiceDown();
645 }
646 } catch (RemoteException e) {
647 Log.e(TAG, "", e);
648 }
649 }
650 }
fredc649fe492012-04-19 01:07:18 -0700651 break;
fredc0f420372012-04-12 00:02:00 -0700652 case MESSAGE_TIMEOUT_UNBIND:
653 {
fredc649fe492012-04-19 01:07:18 -0700654 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700655 synchronized(mConnection) {
656 mUnbinding = false;
657 }
658 }
fredc649fe492012-04-19 01:07:18 -0700659 break;
fredc0f420372012-04-12 00:02:00 -0700660 }
661 }
662 };
663}