blob: f60bc7d77f51135b72a6faa03c9fa5f920a3867c [file] [log] [blame]
fredc0f420372012-04-12 00:02:00 -07001/*
2 * Copyright (C) 2012 Google Inc.
3 */
4
5package com.android.server;
6
7import android.bluetooth.BluetoothAdapter;
8import android.bluetooth.IBluetooth;
fredcbf072a72012-05-09 16:52:50 -07009import android.bluetooth.IBluetoothCallback;
fredc0f420372012-04-12 00:02:00 -070010import android.bluetooth.IBluetoothManager;
11import android.bluetooth.IBluetoothManagerCallback;
12import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070013import android.content.BroadcastReceiver;
14import android.content.ComponentName;
15import android.content.ContentResolver;
16import android.content.Context;
17import android.content.Intent;
18import android.content.IntentFilter;
19import android.content.ServiceConnection;
20import android.os.Handler;
fredc0f420372012-04-12 00:02:00 -070021import android.os.IBinder;
22import android.os.Message;
fredcd6883532012-04-25 17:46:13 -070023import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070024import android.os.RemoteException;
25import android.provider.Settings;
26import android.util.Log;
27import java.util.List;
28import java.util.ArrayList;
fredc0f420372012-04-12 00:02:00 -070029class BluetoothManagerService extends IBluetoothManager.Stub {
30 private static final String TAG = "BluetoothManagerService";
31 private static final boolean DBG = true;
32
fredc0f420372012-04-12 00:02:00 -070033 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
34 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070035 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
36 private static final String EXTRA_ACTION="action";
fredc0f420372012-04-12 00:02:00 -070037 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
38 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070039 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
40 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
41
42 private static final int MESSAGE_ENABLE = 1;
43 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070044 private static final int MESSAGE_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;
fredcbf072a72012-05-09 16:52:50 -070052 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070053 private static final int MESSAGE_TIMEOUT_BIND =100;
54 private static final int MESSAGE_TIMEOUT_UNBIND =101;
55 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
56 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
57 private static final int MAX_SAVE_RETRIES=3;
58
59 private final Context mContext;
60 private String mAddress;
61 private String mName;
62 private ContentResolver mContentResolver;
fredcd6883532012-04-25 17:46:13 -070063 private RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
64 private RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070065 private IBluetooth mBluetooth;
66 private boolean mBinding;
67 private boolean mUnbinding;
fredc0f420372012-04-12 00:02:00 -070068
fredc649fe492012-04-19 01:07:18 -070069 private void registerForAirplaneMode(IntentFilter filter) {
70 final ContentResolver resolver = mContext.getContentResolver();
71 final String airplaneModeRadios = Settings.System.getString(resolver,
72 Settings.System.AIRPLANE_MODE_RADIOS);
73 final String toggleableRadios = Settings.System.getString(resolver,
74 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
75 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
76 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
77 if (mIsAirplaneSensitive) {
78 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
79 }
80 }
81
fredcbf072a72012-05-09 16:52:50 -070082 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
83 @Override
84 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
85 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
86 mHandler.sendMessage(msg);
87 }
88 };
89
90 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -070091 @Override
92 public void onReceive(Context context, Intent intent) {
93 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -070094 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -070095 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -070096 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -070097 if (newName != null) {
98 storeNameAndAddress(newName, null);
99 }
fredc649fe492012-04-19 01:07:18 -0700100 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
101 if (isAirplaneModeOn()) {
102 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_ON);
103 msg.arg1=0;
104 mHandler.sendMessage(msg);
105 } else {
106 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_OFF);
107 msg.arg1=0;
108 mHandler.sendMessage(msg);
109 }
fredc0f420372012-04-12 00:02:00 -0700110 }
111 }
112 };
113
114 BluetoothManagerService(Context context) {
115 mContext = context;
116 mBluetooth = null;
117 mBinding = false;
118 mUnbinding = false;
119 mAddress = null;
120 mName = null;
121 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700122 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
123 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
fredc649fe492012-04-19 01:07:18 -0700124 IntentFilter mFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
fredc116d1d462012-04-20 14:47:08 -0700125 mFilter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
fredc649fe492012-04-19 01:07:18 -0700126 registerForAirplaneMode(mFilter);
fredc0f420372012-04-12 00:02:00 -0700127 mContext.registerReceiver(mReceiver, mFilter);
fredc649fe492012-04-19 01:07:18 -0700128 boolean airplaneModeOn = isAirplaneModeOn();
129 boolean bluetoothOn = isBluetoothPersistedStateOn();
fredc0f420372012-04-12 00:02:00 -0700130 loadStoredNameAndAddress();
fredc649fe492012-04-19 01:07:18 -0700131 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
Andre Eisenbacha732ffd2012-05-02 00:39:24 -0700132 if (bluetoothOn) {
fredc0f420372012-04-12 00:02:00 -0700133 //Enable
fredc649fe492012-04-19 01:07:18 -0700134 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
fredc0f420372012-04-12 00:02:00 -0700135 enable();
Freda8c6df02012-07-11 10:25:23 -0700136 } else if (!isNameAndAddressSet()) {
fredc649fe492012-04-19 01:07:18 -0700137 //Sync the Bluetooth name and address from the Bluetooth Adapter
138 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
fredc0f420372012-04-12 00:02:00 -0700139 getNameAndAddress();
140 }
141 }
142
fredc649fe492012-04-19 01:07:18 -0700143 /**
144 * Returns true if airplane mode is currently on
145 */
146 private final boolean isAirplaneModeOn() {
147 return Settings.System.getInt(mContext.getContentResolver(),
148 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
149 }
150
151 /**
152 * Returns true if the Bluetooth saved state is "on"
153 */
154 private final boolean isBluetoothPersistedStateOn() {
155 return Settings.Secure.getInt(mContentResolver,
156 Settings.Secure.BLUETOOTH_ON, 0) ==1;
157 }
158
159 /**
160 * Save the Bluetooth on/off state
161 *
162 */
163 private void persistBluetoothSetting(boolean setOn) {
164 Settings.Secure.putInt(mContext.getContentResolver(),
165 Settings.Secure.BLUETOOTH_ON,
166 setOn ? 1 : 0);
167 }
168
169 /**
170 * Returns true if the Bluetooth Adapter's name and address is
171 * locally cached
172 * @return
173 */
fredc0f420372012-04-12 00:02:00 -0700174 private boolean isNameAndAddressSet() {
175 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
176 }
177
fredc649fe492012-04-19 01:07:18 -0700178 /**
179 * Retrieve the Bluetooth Adapter's name and address and save it in
180 * in the local cache
181 */
fredc0f420372012-04-12 00:02:00 -0700182 private void loadStoredNameAndAddress() {
183 if (DBG) Log.d(TAG, "Loading stored name and address");
184 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
185 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
186 if (mName == null || mAddress == null) {
187 if (DBG) Log.d(TAG, "Name or address not cached...");
188 }
189 }
190
fredc649fe492012-04-19 01:07:18 -0700191 /**
192 * Save the Bluetooth name and address in the persistent store.
193 * Only non-null values will be saved.
194 * @param name
195 * @param address
196 */
fredc0f420372012-04-12 00:02:00 -0700197 private void storeNameAndAddress(String name, String address) {
198 if (name != null) {
199 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700200 mName = name;
fredc649fe492012-04-19 01:07:18 -0700201 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
202 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700203 }
204
205 if (address != null) {
206 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700207 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700208 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
209 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700210 }
211 }
212
213 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
214 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
215 "Need BLUETOOTH permission");
216 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
217 msg.obj = callback;
218 mHandler.sendMessage(msg);
219 synchronized(mConnection) {
220 return mBluetooth;
221 }
222 }
223
224 public void unregisterAdapter(IBluetoothManagerCallback callback) {
225 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
226 "Need BLUETOOTH permission");
227 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
228 msg.obj = callback;
229 mHandler.sendMessage(msg);
230 }
231
232 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
233 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
234 "Need BLUETOOTH permission");
235 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
236 msg.obj = callback;
237 mHandler.sendMessage(msg);
238 }
239
240 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
241 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
242 "Need BLUETOOTH permission");
243 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
244 msg.obj = callback;
245 mHandler.sendMessage(msg);
246 }
247
248 public boolean isEnabled() {
249 synchronized(mConnection) {
250 try {
251 return (mBluetooth != null && mBluetooth.isEnabled());
252 } catch (RemoteException e) {
253 Log.e(TAG, "isEnabled()", e);
254 }
255 }
256 return false;
257 }
258
fredcf2458862012-04-16 15:18:27 -0700259 private boolean isConnected() {
260 return mBluetooth != null;
261 }
fredc649fe492012-04-19 01:07:18 -0700262
fredc0f420372012-04-12 00:02:00 -0700263 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700264 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700265 Log.d(TAG,"getNameAndAddress(): mBluetooth = " +
266 (mBluetooth==null?"null":mBluetooth) +
267 " mBinding = " + mBinding +
268 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700269 }
fredc0f420372012-04-12 00:02:00 -0700270 synchronized(mConnection) {
271 if (mBinding) return ;
fredcf2458862012-04-16 15:18:27 -0700272 if (!isConnected()) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700273 }
274 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
275 mHandler.sendMessage(msg);
276 }
277
278 public boolean enable() {
279 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
280 "Need BLUETOOTH ADMIN permission");
fredcf2458862012-04-16 15:18:27 -0700281 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700282 Log.d(TAG,"enable(): mBluetooth =" +
283 (mBluetooth==null?"null":mBluetooth) +
284 " mBinding = " + mBinding +
285 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700286 }
287
fredc0f420372012-04-12 00:02:00 -0700288 synchronized(mConnection) {
fredc649fe492012-04-19 01:07:18 -0700289 //if (mBluetooth != null) return false;
290 if (mBinding) {
291 Log.w(TAG,"enable(): binding in progress. Returning..");
292 return true;
293 }
fredcf2458862012-04-16 15:18:27 -0700294 if (!isConnected()) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700295 }
fredc116d1d462012-04-20 14:47:08 -0700296
fredc0f420372012-04-12 00:02:00 -0700297 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
fredc649fe492012-04-19 01:07:18 -0700298 msg.arg1=1; //persist
fredc0f420372012-04-12 00:02:00 -0700299 mHandler.sendMessage(msg);
300 return true;
301 }
302
303 public boolean disable(boolean persist) {
304 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
305 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
fredcf2458862012-04-16 15:18:27 -0700306 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700307 Log.d(TAG,"disable(): mBluetooth = " +
308 (mBluetooth==null?"null":mBluetooth) +
309 " mBinding = " + mBinding +
310 " isConnected = " + isConnected());}
fredcf2458862012-04-16 15:18:27 -0700311
fredc0f420372012-04-12 00:02:00 -0700312 synchronized(mConnection) {
313 if (mBluetooth == null) return false;
fredc0f420372012-04-12 00:02:00 -0700314 }
315 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700316 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700317 mHandler.sendMessage(msg);
318 return true;
319 }
320
fredc649fe492012-04-19 01:07:18 -0700321 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700322 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700323 Log.d(TAG,"unbindAndFinish(): " +
324 (mBluetooth==null?"null":mBluetooth) +
325 " mBinding = " + mBinding +
326 " isConnected = " + isConnected());
fredcf2458862012-04-16 15:18:27 -0700327 }
328
fredc0f420372012-04-12 00:02:00 -0700329 synchronized (mConnection) {
330 if (mUnbinding) return;
331 mUnbinding = true;
fredcf2458862012-04-16 15:18:27 -0700332 if (isConnected()) {
fredcbf072a72012-05-09 16:52:50 -0700333 if (!mConnection.isGetNameAddressOnly()) {
334 //Unregister callback object
335 try {
336 mBluetooth.unregisterCallback(mBluetoothCallback);
337 } catch (RemoteException re) {
338 Log.e(TAG, "Unable to register BluetoothCallback",re);
339 }
340 }
fredc0f420372012-04-12 00:02:00 -0700341 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700342 mBluetooth = null;
343 //Unbind
fredc0f420372012-04-12 00:02:00 -0700344 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700345 mUnbinding = false;
fredcf2458862012-04-16 15:18:27 -0700346 } else {
347 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700348 }
349 }
350 }
351
fredcbf072a72012-05-09 16:52:50 -0700352 private void sendBluetoothStateCallback(boolean isUp) {
353 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700354 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700355 for (int i=0; i <n;i++) {
356 try {
357 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
358 } catch (RemoteException e) {
359 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
360 }
361 }
362 mStateChangeCallbacks.finishBroadcast();
363 }
364
365 /**
366 * Inform BluetoothAdapter instances that Adapter service is down
367 */
368 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700369 if (!mConnection.isGetNameAddressOnly()) {
370 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
371 int n = mCallbacks.beginBroadcast();
372 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
373 for (int i=0; i <n;i++) {
374 try {
375 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
376 } catch (RemoteException e) {
377 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
378 }
379 }
380 mCallbacks.finishBroadcast();
381 }
382 }
fredc0f420372012-04-12 00:02:00 -0700383 public String getAddress() {
384 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
385 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700386 synchronized(mConnection) {
387 if (mBluetooth != null) {
388 try {
389 return mBluetooth.getAddress();
390 } catch (RemoteException e) {
391 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
392 }
393 }
394 }
fredc0f420372012-04-12 00:02:00 -0700395 return mAddress;
396 }
fredc649fe492012-04-19 01:07:18 -0700397
fredc0f420372012-04-12 00:02:00 -0700398 public String getName() {
399 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
400 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700401 synchronized(mConnection) {
402 if (mBluetooth != null) {
403 try {
404 return mBluetooth.getName();
405 } catch (RemoteException e) {
406 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
407 }
408 }
409 }
fredc0f420372012-04-12 00:02:00 -0700410 return mName;
411 }
412
fredc0f420372012-04-12 00:02:00 -0700413 private class BluetoothServiceConnection implements ServiceConnection {
414
415 private boolean mGetNameAddressOnly;
416
417 public void setGetNameAddressOnly(boolean getOnly) {
418 mGetNameAddressOnly = getOnly;
419 }
420
421 public boolean isGetNameAddressOnly() {
422 return mGetNameAddressOnly;
423 }
424
425 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700426 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700427 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
428 msg.obj = service;
429 mHandler.sendMessage(msg);
430 }
431
432 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700433 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700434 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700435 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
436 mHandler.sendMessage(msg);
437 }
438 }
439
440 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
441
442 private final Handler mHandler = new Handler() {
443 @Override
444 public void handleMessage(Message msg) {
445 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700446 switch (msg.what) {
447 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700448 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700449 if (mBluetooth == null) {
450 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700451 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700452 if (DBG) Log.d(TAG, "Binding to service to get name and address");
453 mConnection.setGetNameAddressOnly(true);
454 //Start bind timeout and bind
455 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
456 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
457 Intent i = new Intent(IBluetooth.class.getName());
458 if (!mContext.bindService(i, mConnection,
459 Context.BIND_AUTO_CREATE)) {
460 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
461 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
462 }
463 }
464 } else {
465 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
466 mHandler.sendMessage(saveMsg);
467 }
468 }
fredc649fe492012-04-19 01:07:18 -0700469 break;
fredc0f420372012-04-12 00:02:00 -0700470 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700471 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700472 if (mBluetooth != null) {
473 String name = null;
474 String address = null;
475 try {
476 name = mBluetooth.getName();
477 address = mBluetooth.getAddress();
478 } catch (RemoteException re) {
479 Log.e(TAG,"",re);
480 }
481
482 if (name != null && address != null) {
483 storeNameAndAddress(name,address);
fredcbf072a72012-05-09 16:52:50 -0700484 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700485 unbindAndFinish();
486 } else {
fredc0f420372012-04-12 00:02:00 -0700487 if (msg.arg1 < MAX_SAVE_RETRIES) {
488 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
489 retryMsg.arg1= 1+msg.arg1;
490 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
491 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
492 } else {
493 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
fredcbf072a72012-05-09 16:52:50 -0700494 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700495 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700496 }
497 }
498 }
499 }
fredc649fe492012-04-19 01:07:18 -0700500 break;
501 case MESSAGE_AIRPLANE_MODE_OFF: {
502 if (DBG) Log.d(TAG,"MESSAGE_AIRPLANE_MODE_OFF");
503 //Check if we should turn on bluetooth
504 if (!isBluetoothPersistedStateOn()) {
505 if (DBG)Log.d(TAG, "Bluetooth persisted state is off. Not turning on Bluetooth.");
506 return;
507 }
508 //Fall through to MESSAGE_ENABLE
509 }
fredc0f420372012-04-12 00:02:00 -0700510 case MESSAGE_ENABLE: {
fredcf2458862012-04-16 15:18:27 -0700511 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700512 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth +
513 " isConnected = " + isConnected());
514 }
Freda8c6df02012-07-11 10:25:23 -0700515
516 boolean persist = (1==msg.arg1);
fredc649fe492012-04-19 01:07:18 -0700517 if (persist) {
518 persistBluetoothSetting(true);
519 }
Freda8c6df02012-07-11 10:25:23 -0700520
fredc0f420372012-04-12 00:02:00 -0700521 if (mBluetooth == null) {
Freda8c6df02012-07-11 10:25:23 -0700522 //Start bind timeout and bind
523 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
524 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
525 mConnection.setGetNameAddressOnly(false);
526 Intent i = new Intent(IBluetooth.class.getName());
527 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
528 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
529 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
fredc0f420372012-04-12 00:02:00 -0700530 }
531 } else {
532 //Check if name and address is loaded if not get it first.
Freda8c6df02012-07-11 10:25:23 -0700533 if (!isNameAndAddressSet()) {
fredc0f420372012-04-12 00:02:00 -0700534 try {
fredc649fe492012-04-19 01:07:18 -0700535 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
fredc0f420372012-04-12 00:02:00 -0700536 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
537 } catch (RemoteException e) {Log.e(TAG, "", e);};
538 }
Freda8c6df02012-07-11 10:25:23 -0700539
540 //Enable bluetooth
541 try {
542 if(!mBluetooth.enable()) {
543 Log.e(TAG,"IBluetooth.enable() returned false");
544 }
545 } catch (RemoteException e) {
546 Log.e(TAG,"Unable to call enable()",e);
547 }
548
fredc0f420372012-04-12 00:02:00 -0700549 }
550 // TODO(BT) what if service failed to start:
551 // [fc] fixed: watch for bind timeout and handle accordingly
552 // TODO(BT) persist the setting depending on argument
553 // [fc]: let AdapterServiceHandle
554 }
fredc649fe492012-04-19 01:07:18 -0700555 break;
556 case MESSAGE_AIRPLANE_MODE_ON:;
557 if (DBG) {
558 Log.d(TAG, "MESSAGE_AIRPLANE_MODE_ON: mBluetooth = " + mBluetooth +
559 " isConnected = " + isConnected());
560 //Fall through to MESSAGE_DISABLE
561 }
fredc0f420372012-04-12 00:02:00 -0700562 case MESSAGE_DISABLE:
563 if (mBluetooth != null ) {
fredc649fe492012-04-19 01:07:18 -0700564 boolean persist = (1==msg.arg1);
565 if (persist) {
566 persistBluetoothSetting(false);
fredc0f420372012-04-12 00:02:00 -0700567 }
fredc649fe492012-04-19 01:07:18 -0700568 mConnection.setGetNameAddressOnly(false);
569 if (DBG) Log.d(TAG,"Sending off request.");
fredc0f420372012-04-12 00:02:00 -0700570
Freda8c6df02012-07-11 10:25:23 -0700571 try {
572 if(!mBluetooth.disable()) {
573 Log.e(TAG,"IBluetooth.disable() returned false");
574 }
575 } catch (RemoteException e) {
576 Log.e(TAG,"Unable to call disable()",e);
577 }
578 }
fredc0f420372012-04-12 00:02:00 -0700579 break;
580 case MESSAGE_REGISTER_ADAPTER:
581 {
582 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700583 boolean added = mCallbacks.register(callback);
584 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700585 }
586 break;
587 case MESSAGE_UNREGISTER_ADAPTER:
588 {
589 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700590 boolean removed = mCallbacks.unregister(callback);
591 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700592 }
593 break;
594 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
595 {
596 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700597 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700598 }
599 break;
600 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
601 {
602 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700603 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700604 }
605 break;
606 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
607 {
fredc649fe492012-04-19 01:07:18 -0700608 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
609
fredc0f420372012-04-12 00:02:00 -0700610 //Remove timeout
611 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
612
613 IBinder service = (IBinder) msg.obj;
614 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700615 mBinding = false;
616 mBluetooth = IBluetooth.Stub.asInterface(service);
617 }
618
619 if (mConnection.isGetNameAddressOnly()) {
620 //Request GET NAME AND ADDRESS
621 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
622 mHandler.sendMessage(getMsg);
623 return;
624 }
fredc0f420372012-04-12 00:02:00 -0700625
fredcbf072a72012-05-09 16:52:50 -0700626 //Register callback object
627 try {
628 mBluetooth.registerCallback(mBluetoothCallback);
629 } catch (RemoteException re) {
630 Log.e(TAG, "Unable to register BluetoothCallback",re);
631 }
632
633 //Inform BluetoothAdapter instances that service is up
634 int n = mCallbacks.beginBroadcast();
635 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
636 for (int i=0; i <n;i++) {
637 try {
638 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
639 } catch (RemoteException e) {
640 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
641 }
642 }
643 mCallbacks.finishBroadcast();
644
645 //Do enable request
Freda8c6df02012-07-11 10:25:23 -0700646 try {
647 if(!mBluetooth.enable()) {
648 Log.e(TAG,"IBluetooth.enable() returned false");
649 }
650 } catch (RemoteException e) {
651 Log.e(TAG,"Unable to call enable()",e);
652 }
fredc0f420372012-04-12 00:02:00 -0700653 }
fredc649fe492012-04-19 01:07:18 -0700654 break;
655 case MESSAGE_TIMEOUT_BIND: {
656 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700657 synchronized(mConnection) {
658 mBinding = false;
659 }
660 }
fredc649fe492012-04-19 01:07:18 -0700661 break;
fredcbf072a72012-05-09 16:52:50 -0700662 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700663 {
fredcbf072a72012-05-09 16:52:50 -0700664 int prevState = msg.arg1;
665 int newState = msg.arg2;
666 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
667 if (prevState != newState) {
668 //Notify all proxy objects first of adapter state change
669 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
670 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
671 sendBluetoothStateCallback(isUp);
672
673 //If Bluetooth is off, send service down event to proxy objects, and unbind
674 if (!isUp) {
675 sendBluetoothServiceDownCallback();
676 unbindAndFinish();
677 }
fredc0f420372012-04-12 00:02:00 -0700678 }
fredcbf072a72012-05-09 16:52:50 -0700679
680 //Send broadcast message to everyone else
681 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
682 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
683 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
684 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
685 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
686 mContext.sendBroadcast(intent,BLUETOOTH_PERM);
fredc0f420372012-04-12 00:02:00 -0700687 }
fredc0f420372012-04-12 00:02:00 -0700688 }
fredc649fe492012-04-19 01:07:18 -0700689 break;
fredc0f420372012-04-12 00:02:00 -0700690 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
691 {
fredc649fe492012-04-19 01:07:18 -0700692 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredcbf072a72012-05-09 16:52:50 -0700693 sendBluetoothServiceDownCallback();
fredc0f420372012-04-12 00:02:00 -0700694 }
fredc649fe492012-04-19 01:07:18 -0700695 break;
fredc0f420372012-04-12 00:02:00 -0700696 case MESSAGE_TIMEOUT_UNBIND:
697 {
fredc649fe492012-04-19 01:07:18 -0700698 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700699 synchronized(mConnection) {
700 mUnbinding = false;
701 }
702 }
fredc649fe492012-04-19 01:07:18 -0700703 break;
fredc0f420372012-04-12 00:02:00 -0700704 }
705 }
706 };
707}