blob: ac88a6ab62c82b5b1832352e1b0a6d669a4d13e0 [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;
Matthew Xie6fde3092012-07-11 17:10:07 -070062 private final ContentResolver mContentResolver;
63 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
64 private final 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>();
Matthew Xie6fde3092012-07-11 17:10:07 -0700124 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
125 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
126 registerForAirplaneMode(filter);
127 mContext.registerReceiver(mReceiver, filter);
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 }
Matthew Xie6fde3092012-07-11 17:10:07 -0700515 boolean persist = (msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -0700516 if (persist) {
517 persistBluetoothSetting(true);
518 }
Freda8c6df02012-07-11 10:25:23 -0700519
fredc0f420372012-04-12 00:02:00 -0700520 if (mBluetooth == null) {
Freda8c6df02012-07-11 10:25:23 -0700521 //Start bind timeout and bind
522 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
523 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
524 mConnection.setGetNameAddressOnly(false);
525 Intent i = new Intent(IBluetooth.class.getName());
526 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
527 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
528 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
fredc0f420372012-04-12 00:02:00 -0700529 }
530 } else {
531 //Check if name and address is loaded if not get it first.
Freda8c6df02012-07-11 10:25:23 -0700532 if (!isNameAndAddressSet()) {
fredc0f420372012-04-12 00:02:00 -0700533 try {
fredc649fe492012-04-19 01:07:18 -0700534 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
fredc0f420372012-04-12 00:02:00 -0700535 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
536 } catch (RemoteException e) {Log.e(TAG, "", e);};
537 }
Freda8c6df02012-07-11 10:25:23 -0700538
539 //Enable bluetooth
540 try {
541 if(!mBluetooth.enable()) {
542 Log.e(TAG,"IBluetooth.enable() returned false");
543 }
544 } catch (RemoteException e) {
545 Log.e(TAG,"Unable to call enable()",e);
546 }
547
fredc0f420372012-04-12 00:02:00 -0700548 }
549 // TODO(BT) what if service failed to start:
550 // [fc] fixed: watch for bind timeout and handle accordingly
551 // TODO(BT) persist the setting depending on argument
552 // [fc]: let AdapterServiceHandle
553 }
fredc649fe492012-04-19 01:07:18 -0700554 break;
Matthew Xie6fde3092012-07-11 17:10:07 -0700555 case MESSAGE_AIRPLANE_MODE_ON:
fredc649fe492012-04-19 01:07:18 -0700556 if (DBG) {
557 Log.d(TAG, "MESSAGE_AIRPLANE_MODE_ON: mBluetooth = " + mBluetooth +
558 " isConnected = " + isConnected());
559 //Fall through to MESSAGE_DISABLE
560 }
fredc0f420372012-04-12 00:02:00 -0700561 case MESSAGE_DISABLE:
562 if (mBluetooth != null ) {
fredc649fe492012-04-19 01:07:18 -0700563 boolean persist = (1==msg.arg1);
564 if (persist) {
565 persistBluetoothSetting(false);
fredc0f420372012-04-12 00:02:00 -0700566 }
fredc649fe492012-04-19 01:07:18 -0700567 mConnection.setGetNameAddressOnly(false);
568 if (DBG) Log.d(TAG,"Sending off request.");
fredc0f420372012-04-12 00:02:00 -0700569
Freda8c6df02012-07-11 10:25:23 -0700570 try {
571 if(!mBluetooth.disable()) {
572 Log.e(TAG,"IBluetooth.disable() returned false");
573 }
574 } catch (RemoteException e) {
575 Log.e(TAG,"Unable to call disable()",e);
576 }
577 }
fredc0f420372012-04-12 00:02:00 -0700578 break;
579 case MESSAGE_REGISTER_ADAPTER:
580 {
581 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700582 boolean added = mCallbacks.register(callback);
583 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700584 }
585 break;
586 case MESSAGE_UNREGISTER_ADAPTER:
587 {
588 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700589 boolean removed = mCallbacks.unregister(callback);
590 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700591 }
592 break;
593 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
594 {
595 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700596 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700597 }
598 break;
599 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
600 {
601 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700602 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700603 }
604 break;
605 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
606 {
fredc649fe492012-04-19 01:07:18 -0700607 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
608
fredc0f420372012-04-12 00:02:00 -0700609 //Remove timeout
610 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
611
612 IBinder service = (IBinder) msg.obj;
613 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700614 mBinding = false;
615 mBluetooth = IBluetooth.Stub.asInterface(service);
616 }
617
618 if (mConnection.isGetNameAddressOnly()) {
619 //Request GET NAME AND ADDRESS
620 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
621 mHandler.sendMessage(getMsg);
622 return;
623 }
fredc0f420372012-04-12 00:02:00 -0700624
fredcbf072a72012-05-09 16:52:50 -0700625 //Register callback object
626 try {
627 mBluetooth.registerCallback(mBluetoothCallback);
628 } catch (RemoteException re) {
629 Log.e(TAG, "Unable to register BluetoothCallback",re);
630 }
631
632 //Inform BluetoothAdapter instances that service is up
633 int n = mCallbacks.beginBroadcast();
634 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
635 for (int i=0; i <n;i++) {
636 try {
637 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
638 } catch (RemoteException e) {
639 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
640 }
641 }
642 mCallbacks.finishBroadcast();
643
644 //Do enable request
Freda8c6df02012-07-11 10:25:23 -0700645 try {
646 if(!mBluetooth.enable()) {
647 Log.e(TAG,"IBluetooth.enable() returned false");
648 }
649 } catch (RemoteException e) {
650 Log.e(TAG,"Unable to call enable()",e);
651 }
fredc0f420372012-04-12 00:02:00 -0700652 }
fredc649fe492012-04-19 01:07:18 -0700653 break;
654 case MESSAGE_TIMEOUT_BIND: {
655 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700656 synchronized(mConnection) {
657 mBinding = false;
658 }
659 }
fredc649fe492012-04-19 01:07:18 -0700660 break;
fredcbf072a72012-05-09 16:52:50 -0700661 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700662 {
fredcbf072a72012-05-09 16:52:50 -0700663 int prevState = msg.arg1;
664 int newState = msg.arg2;
665 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
666 if (prevState != newState) {
667 //Notify all proxy objects first of adapter state change
668 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
669 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
670 sendBluetoothStateCallback(isUp);
671
672 //If Bluetooth is off, send service down event to proxy objects, and unbind
673 if (!isUp) {
674 sendBluetoothServiceDownCallback();
675 unbindAndFinish();
676 }
fredc0f420372012-04-12 00:02:00 -0700677 }
fredcbf072a72012-05-09 16:52:50 -0700678
679 //Send broadcast message to everyone else
680 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
681 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
682 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
683 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
684 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
685 mContext.sendBroadcast(intent,BLUETOOTH_PERM);
fredc0f420372012-04-12 00:02:00 -0700686 }
fredc0f420372012-04-12 00:02:00 -0700687 }
fredc649fe492012-04-19 01:07:18 -0700688 break;
fredc0f420372012-04-12 00:02:00 -0700689 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
690 {
fredc649fe492012-04-19 01:07:18 -0700691 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredcbf072a72012-05-09 16:52:50 -0700692 sendBluetoothServiceDownCallback();
fredc0f420372012-04-12 00:02:00 -0700693 }
fredc649fe492012-04-19 01:07:18 -0700694 break;
fredc0f420372012-04-12 00:02:00 -0700695 case MESSAGE_TIMEOUT_UNBIND:
696 {
fredc649fe492012-04-19 01:07:18 -0700697 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700698 synchronized(mConnection) {
699 mUnbinding = false;
700 }
701 }
fredc649fe492012-04-19 01:07:18 -0700702 break;
fredc0f420372012-04-12 00:02:00 -0700703 }
704 }
705 };
706}