blob: 32fddeb806356b9530962439bc8aced44262028d [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
zzyc2f5cc52012-05-01 18:05:08 -070033 private static final boolean ALWAYS_SYNC_NAME_ADDRESS=false; //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;
fredcbf072a72012-05-09 16:52:50 -070053 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
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
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);
97 Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
98 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()) {
103 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_ON);
104 msg.arg1=0;
105 mHandler.sendMessage(msg);
106 } else {
107 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_OFF);
108 msg.arg1=0;
109 mHandler.sendMessage(msg);
110 }
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>();
fredc649fe492012-04-19 01:07:18 -0700125 IntentFilter mFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
fredc116d1d462012-04-20 14:47:08 -0700126 mFilter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
fredc649fe492012-04-19 01:07:18 -0700127 registerForAirplaneMode(mFilter);
fredc0f420372012-04-12 00:02:00 -0700128 mContext.registerReceiver(mReceiver, mFilter);
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();
137 } else if (ALWAYS_SYNC_NAME_ADDRESS || !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
fredcf2458862012-04-16 15:18:27 -0700260 private boolean isConnected() {
261 return mBluetooth != null;
262 }
fredc649fe492012-04-19 01:07:18 -0700263
fredc0f420372012-04-12 00:02:00 -0700264 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700265 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700266 Log.d(TAG,"getNameAndAddress(): mBluetooth = " +
267 (mBluetooth==null?"null":mBluetooth) +
268 " mBinding = " + mBinding +
269 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700270 }
fredc0f420372012-04-12 00:02:00 -0700271 synchronized(mConnection) {
272 if (mBinding) return ;
fredcf2458862012-04-16 15:18:27 -0700273 if (!isConnected()) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700274 }
275 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
276 mHandler.sendMessage(msg);
277 }
278
279 public boolean enable() {
280 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
281 "Need BLUETOOTH ADMIN permission");
fredcf2458862012-04-16 15:18:27 -0700282 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700283 Log.d(TAG,"enable(): mBluetooth =" +
284 (mBluetooth==null?"null":mBluetooth) +
285 " mBinding = " + mBinding +
286 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700287 }
288
fredc0f420372012-04-12 00:02:00 -0700289 synchronized(mConnection) {
fredc649fe492012-04-19 01:07:18 -0700290 //if (mBluetooth != null) return false;
291 if (mBinding) {
292 Log.w(TAG,"enable(): binding in progress. Returning..");
293 return true;
294 }
fredcf2458862012-04-16 15:18:27 -0700295 if (!isConnected()) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700296 }
fredc116d1d462012-04-20 14:47:08 -0700297
fredc0f420372012-04-12 00:02:00 -0700298 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
fredc649fe492012-04-19 01:07:18 -0700299 msg.arg1=1; //persist
fredc0f420372012-04-12 00:02:00 -0700300 mHandler.sendMessage(msg);
301 return true;
302 }
303
304 public boolean disable(boolean persist) {
305 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
306 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
fredcf2458862012-04-16 15:18:27 -0700307 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700308 Log.d(TAG,"disable(): mBluetooth = " +
309 (mBluetooth==null?"null":mBluetooth) +
310 " mBinding = " + mBinding +
311 " isConnected = " + isConnected());}
fredcf2458862012-04-16 15:18:27 -0700312
fredc0f420372012-04-12 00:02:00 -0700313 synchronized(mConnection) {
314 if (mBluetooth == null) return false;
fredc0f420372012-04-12 00:02:00 -0700315 }
316 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700317 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700318 mHandler.sendMessage(msg);
319 return true;
320 }
321
fredc649fe492012-04-19 01:07:18 -0700322 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700323 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700324 Log.d(TAG,"unbindAndFinish(): " +
325 (mBluetooth==null?"null":mBluetooth) +
326 " mBinding = " + mBinding +
327 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700328 }
329
fredc0f420372012-04-12 00:02:00 -0700330 synchronized (mConnection) {
331 if (mUnbinding) return;
332 mUnbinding = true;
fredcf2458862012-04-16 15:18:27 -0700333 if (isConnected()) {
fredcbf072a72012-05-09 16:52:50 -0700334 if (!mConnection.isGetNameAddressOnly()) {
335 //Unregister callback object
336 try {
337 mBluetooth.unregisterCallback(mBluetoothCallback);
338 } catch (RemoteException re) {
339 Log.e(TAG, "Unable to register BluetoothCallback",re);
340 }
341 }
fredc0f420372012-04-12 00:02:00 -0700342 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700343 mBluetooth = null;
344 //Unbind
fredc0f420372012-04-12 00:02:00 -0700345 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700346 mUnbinding = false;
fredcf2458862012-04-16 15:18:27 -0700347 } else {
348 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700349 }
350 }
351 }
352
fredcbf072a72012-05-09 16:52:50 -0700353 private void sendBluetoothStateCallback(boolean isUp) {
354 int n = mStateChangeCallbacks.beginBroadcast();
355 Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
356 for (int i=0; i <n;i++) {
357 try {
358 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
359 } catch (RemoteException e) {
360 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
361 }
362 }
363 mStateChangeCallbacks.finishBroadcast();
364 }
365
366 /**
367 * Inform BluetoothAdapter instances that Adapter service is down
368 */
369 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700370 if (!mConnection.isGetNameAddressOnly()) {
371 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
372 int n = mCallbacks.beginBroadcast();
373 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
374 for (int i=0; i <n;i++) {
375 try {
376 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
377 } catch (RemoteException e) {
378 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
379 }
380 }
381 mCallbacks.finishBroadcast();
382 }
383 }
fredc0f420372012-04-12 00:02:00 -0700384 public String getAddress() {
385 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
386 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700387 synchronized(mConnection) {
388 if (mBluetooth != null) {
389 try {
390 return mBluetooth.getAddress();
391 } catch (RemoteException e) {
392 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
393 }
394 }
395 }
fredc0f420372012-04-12 00:02:00 -0700396 return mAddress;
397 }
fredc649fe492012-04-19 01:07:18 -0700398
fredc0f420372012-04-12 00:02:00 -0700399 public String getName() {
400 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
401 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700402 synchronized(mConnection) {
403 if (mBluetooth != null) {
404 try {
405 return mBluetooth.getName();
406 } catch (RemoteException e) {
407 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
408 }
409 }
410 }
fredc0f420372012-04-12 00:02:00 -0700411 return mName;
412 }
413
fredc0f420372012-04-12 00:02:00 -0700414 private class BluetoothServiceConnection implements ServiceConnection {
415
416 private boolean mGetNameAddressOnly;
417
418 public void setGetNameAddressOnly(boolean getOnly) {
419 mGetNameAddressOnly = getOnly;
420 }
421
422 public boolean isGetNameAddressOnly() {
423 return mGetNameAddressOnly;
424 }
425
426 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700427 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700428 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
429 msg.obj = service;
430 mHandler.sendMessage(msg);
431 }
432
433 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700434 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700435 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700436 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
437 mHandler.sendMessage(msg);
438 }
439 }
440
441 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
442
443 private final Handler mHandler = new Handler() {
444 @Override
445 public void handleMessage(Message msg) {
446 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700447 switch (msg.what) {
448 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700449 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700450 if (mBluetooth == null) {
451 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700452 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700453 if (DBG) Log.d(TAG, "Binding to service to get name and address");
454 mConnection.setGetNameAddressOnly(true);
455 //Start bind timeout and bind
456 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
457 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
458 Intent i = new Intent(IBluetooth.class.getName());
459 if (!mContext.bindService(i, mConnection,
460 Context.BIND_AUTO_CREATE)) {
461 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
462 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
463 }
464 }
465 } else {
466 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
467 mHandler.sendMessage(saveMsg);
468 }
469 }
fredc649fe492012-04-19 01:07:18 -0700470 break;
fredc0f420372012-04-12 00:02:00 -0700471 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700472 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700473 if (mBluetooth != null) {
474 String name = null;
475 String address = null;
476 try {
477 name = mBluetooth.getName();
478 address = mBluetooth.getAddress();
479 } catch (RemoteException re) {
480 Log.e(TAG,"",re);
481 }
482
483 if (name != null && address != null) {
484 storeNameAndAddress(name,address);
fredc649fe492012-04-19 01:07:18 -0700485 Intent i = new Intent(IBluetooth.class.getName());
486 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
487 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
488 mContext.startService(i);
fredcbf072a72012-05-09 16:52:50 -0700489 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700490 unbindAndFinish();
491 } else {
fredc0f420372012-04-12 00:02:00 -0700492 if (msg.arg1 < MAX_SAVE_RETRIES) {
493 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
494 retryMsg.arg1= 1+msg.arg1;
495 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
496 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
497 } else {
498 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
fredcbf072a72012-05-09 16:52:50 -0700499 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700500 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700501 }
502 }
503 }
504 }
fredc649fe492012-04-19 01:07:18 -0700505 break;
506 case MESSAGE_AIRPLANE_MODE_OFF: {
507 if (DBG) Log.d(TAG,"MESSAGE_AIRPLANE_MODE_OFF");
508 //Check if we should turn on bluetooth
509 if (!isBluetoothPersistedStateOn()) {
510 if (DBG)Log.d(TAG, "Bluetooth persisted state is off. Not turning on Bluetooth.");
511 return;
512 }
513 //Fall through to MESSAGE_ENABLE
514 }
fredc0f420372012-04-12 00:02:00 -0700515 case MESSAGE_ENABLE: {
fredcf2458862012-04-16 15:18:27 -0700516 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700517 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth +
518 " isConnected = " + isConnected());
519 }
520 boolean persist = (1==msg.arg1);
521 if (persist) {
522 persistBluetoothSetting(true);
523 }
fredc0f420372012-04-12 00:02:00 -0700524 if (mBluetooth == null) {
525 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700526 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700527 //Start bind timeout and bind
528 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
529 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
fredcbf072a72012-05-09 16:52:50 -0700530 /*
fredc0f420372012-04-12 00:02:00 -0700531 Intent i = new Intent(IBluetooth.class.getName());
532 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
533 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
534 mContext.startService(i);
fredcbf072a72012-05-09 16:52:50 -0700535 */
fredc0f420372012-04-12 00:02:00 -0700536 mConnection.setGetNameAddressOnly(false);
fredcbf072a72012-05-09 16:52:50 -0700537 Intent i = new Intent(IBluetooth.class.getName());
fredc649fe492012-04-19 01:07:18 -0700538 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
fredc0f420372012-04-12 00:02:00 -0700539 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
fredc649fe492012-04-19 01:07:18 -0700540 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
fredc0f420372012-04-12 00:02:00 -0700541 }
542 }
543 } else {
544 //Check if name and address is loaded if not get it first.
545 if (ALWAYS_SYNC_NAME_ADDRESS || !isNameAndAddressSet()) {
546 try {
fredc649fe492012-04-19 01:07:18 -0700547 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
fredc0f420372012-04-12 00:02:00 -0700548 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
549 } catch (RemoteException e) {Log.e(TAG, "", e);};
550 }
fredc649fe492012-04-19 01:07:18 -0700551 Intent i = new Intent(IBluetooth.class.getName());
552 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
553 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
554 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700555 }
556 // TODO(BT) what if service failed to start:
557 // [fc] fixed: watch for bind timeout and handle accordingly
558 // TODO(BT) persist the setting depending on argument
559 // [fc]: let AdapterServiceHandle
560 }
fredc649fe492012-04-19 01:07:18 -0700561 break;
562 case MESSAGE_AIRPLANE_MODE_ON:;
563 if (DBG) {
564 Log.d(TAG, "MESSAGE_AIRPLANE_MODE_ON: mBluetooth = " + mBluetooth +
565 " isConnected = " + isConnected());
566 //Fall through to MESSAGE_DISABLE
567 }
fredc0f420372012-04-12 00:02:00 -0700568 case MESSAGE_DISABLE:
569 if (mBluetooth != null ) {
fredc649fe492012-04-19 01:07:18 -0700570 boolean persist = (1==msg.arg1);
571 if (persist) {
572 persistBluetoothSetting(false);
fredc0f420372012-04-12 00:02:00 -0700573 }
fredc649fe492012-04-19 01:07:18 -0700574 mConnection.setGetNameAddressOnly(false);
575 if (DBG) Log.d(TAG,"Sending off request.");
576 Intent i = new Intent(IBluetooth.class.getName());
577 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
578 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
579 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700580 }
fredc0f420372012-04-12 00:02:00 -0700581 // TODO(BT) what if service failed to stop:
582 // [fc] fixed: watch for disable event and unbind accordingly
583 // TODO(BT) persist the setting depending on argument
584 // [fc]: let AdapterServiceHandle
585
586 break;
587 case MESSAGE_REGISTER_ADAPTER:
588 {
589 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700590 boolean added = mCallbacks.register(callback);
591 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700592 }
593 break;
594 case MESSAGE_UNREGISTER_ADAPTER:
595 {
596 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700597 boolean removed = mCallbacks.unregister(callback);
598 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700599 }
600 break;
601 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
602 {
603 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700604 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700605 }
606 break;
607 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
608 {
609 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700610 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700611 }
612 break;
613 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
614 {
fredc649fe492012-04-19 01:07:18 -0700615 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
616
fredc0f420372012-04-12 00:02:00 -0700617 //Remove timeout
618 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
619
620 IBinder service = (IBinder) msg.obj;
621 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700622 mBinding = false;
623 mBluetooth = IBluetooth.Stub.asInterface(service);
624 }
625
626 if (mConnection.isGetNameAddressOnly()) {
627 //Request GET NAME AND ADDRESS
628 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
629 mHandler.sendMessage(getMsg);
630 return;
631 }
fredc0f420372012-04-12 00:02:00 -0700632
fredcbf072a72012-05-09 16:52:50 -0700633 //Register callback object
634 try {
635 mBluetooth.registerCallback(mBluetoothCallback);
636 } catch (RemoteException re) {
637 Log.e(TAG, "Unable to register BluetoothCallback",re);
638 }
639
640 //Inform BluetoothAdapter instances that service is up
641 int n = mCallbacks.beginBroadcast();
642 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
643 for (int i=0; i <n;i++) {
644 try {
645 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
646 } catch (RemoteException e) {
647 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
648 }
649 }
650 mCallbacks.finishBroadcast();
651
652 //Do enable request
653 Intent i = new Intent(IBluetooth.class.getName());
654 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
655 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
656 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700657 }
fredc649fe492012-04-19 01:07:18 -0700658 break;
659 case MESSAGE_TIMEOUT_BIND: {
660 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700661 synchronized(mConnection) {
662 mBinding = false;
663 }
664 }
fredc649fe492012-04-19 01:07:18 -0700665 break;
fredcbf072a72012-05-09 16:52:50 -0700666 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700667 {
fredcbf072a72012-05-09 16:52:50 -0700668 int prevState = msg.arg1;
669 int newState = msg.arg2;
670 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
671 if (prevState != newState) {
672 //Notify all proxy objects first of adapter state change
673 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
674 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
675 sendBluetoothStateCallback(isUp);
676
677 //If Bluetooth is off, send service down event to proxy objects, and unbind
678 if (!isUp) {
679 sendBluetoothServiceDownCallback();
680 unbindAndFinish();
681 }
fredc0f420372012-04-12 00:02:00 -0700682 }
fredcbf072a72012-05-09 16:52:50 -0700683
684 //Send broadcast message to everyone else
685 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
686 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
687 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
688 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
689 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
690 mContext.sendBroadcast(intent,BLUETOOTH_PERM);
fredc0f420372012-04-12 00:02:00 -0700691 }
fredc0f420372012-04-12 00:02:00 -0700692 }
fredc649fe492012-04-19 01:07:18 -0700693 break;
fredc0f420372012-04-12 00:02:00 -0700694 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
695 {
fredc649fe492012-04-19 01:07:18 -0700696 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredcbf072a72012-05-09 16:52:50 -0700697 sendBluetoothServiceDownCallback();
fredc0f420372012-04-12 00:02:00 -0700698 }
fredc649fe492012-04-19 01:07:18 -0700699 break;
fredc0f420372012-04-12 00:02:00 -0700700 case MESSAGE_TIMEOUT_UNBIND:
701 {
fredc649fe492012-04-19 01:07:18 -0700702 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700703 synchronized(mConnection) {
704 mUnbinding = false;
705 }
706 }
fredc649fe492012-04-19 01:07:18 -0700707 break;
fredc0f420372012-04-12 00:02:00 -0700708 }
709 }
710 };
711}