blob: c2fb68524fba5e4a141600d461d62a53ff1c13ed [file] [log] [blame]
fredc0f420372012-04-12 00:02:00 -07001/*
2 * Copyright (C) 2012 Google Inc.
3 */
4
5package com.android.server;
6
7import android.bluetooth.BluetoothAdapter;
8import android.bluetooth.IBluetooth;
9import android.bluetooth.IBluetoothManager;
10import android.bluetooth.IBluetoothManagerCallback;
11import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070012import android.content.BroadcastReceiver;
13import android.content.ComponentName;
14import android.content.ContentResolver;
15import android.content.Context;
16import android.content.Intent;
17import android.content.IntentFilter;
18import android.content.ServiceConnection;
19import android.os.Handler;
fredc0f420372012-04-12 00:02:00 -070020import android.os.IBinder;
21import android.os.Message;
22import android.os.RemoteException;
23import android.provider.Settings;
24import android.util.Log;
25import java.util.List;
26import java.util.ArrayList;
27
28class BluetoothManagerService extends IBluetoothManager.Stub {
29 private static final String TAG = "BluetoothManagerService";
30 private static final boolean DBG = true;
31
32 private static final boolean ALWAYS_SYNC_NAME_ADDRESS=true; //If true, always load name and address
fredc0f420372012-04-12 00:02:00 -070033 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
34 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070035 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
36 private static final String EXTRA_ACTION="action";
fredc0f420372012-04-12 00:02:00 -070037 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
38 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070039 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
40 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
41
42 private static final int MESSAGE_ENABLE = 1;
43 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070044 private static final int MESSAGE_AIRPLANE_MODE_OFF=10;
45 private static final int MESSAGE_AIRPLANE_MODE_ON=11;
46 private static final int MESSAGE_REGISTER_ADAPTER = 20;
47 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
48 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
49 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
50 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
51 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
52 private static final int MESSAGE_BLUETOOTH_ON = 50;
53 private static final int MESSAGE_BLUETOOTH_OFF = 51;
fredc0f420372012-04-12 00:02:00 -070054 private static final int MESSAGE_TIMEOUT_BIND =100;
55 private static final int MESSAGE_TIMEOUT_UNBIND =101;
56 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
57 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
58 private static final int MAX_SAVE_RETRIES=3;
59
60 private final Context mContext;
61 private String mAddress;
62 private String mName;
63 private ContentResolver mContentResolver;
64 private List<IBluetoothManagerCallback> mCallbacks;
65 private List<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070066 private IBluetooth mBluetooth;
67 private boolean mBinding;
68 private boolean mUnbinding;
fredc0f420372012-04-12 00:02:00 -070069
fredc649fe492012-04-19 01:07:18 -070070 private void registerForAirplaneMode(IntentFilter filter) {
71 final ContentResolver resolver = mContext.getContentResolver();
72 final String airplaneModeRadios = Settings.System.getString(resolver,
73 Settings.System.AIRPLANE_MODE_RADIOS);
74 final String toggleableRadios = Settings.System.getString(resolver,
75 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
76 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
77 airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
78 if (mIsAirplaneSensitive) {
79 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
80 }
81 }
82
fredc0f420372012-04-12 00:02:00 -070083 private BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -070084 @Override
85 public void onReceive(Context context, Intent intent) {
86 String action = intent.getAction();
87 if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
88 int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
89 if (state == BluetoothAdapter.STATE_OFF) {
90 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_OFF);
91 mHandler.sendMessage(msg);
92 } else if (state == BluetoothAdapter.STATE_ON) {
93 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_ON);
94 mHandler.sendMessage(msg);
95 }
96 } else if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
97 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
98 Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
99 if (newName != null) {
100 storeNameAndAddress(newName, null);
101 }
fredc649fe492012-04-19 01:07:18 -0700102 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
103 if (isAirplaneModeOn()) {
104 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_ON);
105 msg.arg1=0;
106 mHandler.sendMessage(msg);
107 } else {
108 Message msg = mHandler.obtainMessage(MESSAGE_AIRPLANE_MODE_OFF);
109 msg.arg1=0;
110 mHandler.sendMessage(msg);
111 }
fredc0f420372012-04-12 00:02:00 -0700112 }
113 }
114 };
115
116 BluetoothManagerService(Context context) {
117 mContext = context;
118 mBluetooth = null;
119 mBinding = false;
120 mUnbinding = false;
121 mAddress = null;
122 mName = null;
123 mContentResolver = context.getContentResolver();
124 mCallbacks = new ArrayList<IBluetoothManagerCallback>();
125 mStateChangeCallbacks = new ArrayList<IBluetoothStateChangeCallback>();
fredc649fe492012-04-19 01:07:18 -0700126 IntentFilter mFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
127 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);
133 if (!airplaneModeOn && 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 }
297 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()) {
fredc0f420372012-04-12 00:02:00 -0700333 if (DBG) Log.d(TAG, "Sending unbind request.");
334 mContext.unbindService(mConnection);
335 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED));
fredcf2458862012-04-16 15:18:27 -0700336 } else {
337 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700338 }
339 }
340 }
341
342 public String getAddress() {
343 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
344 "Need BLUETOOTH ADMIN permission");
345 return mAddress;
346 }
fredc649fe492012-04-19 01:07:18 -0700347
fredc0f420372012-04-12 00:02:00 -0700348 public String getName() {
349 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
350 "Need BLUETOOTH ADMIN permission");
351 return mName;
352 }
353
fredc0f420372012-04-12 00:02:00 -0700354 private class BluetoothServiceConnection implements ServiceConnection {
355
356 private boolean mGetNameAddressOnly;
357
358 public void setGetNameAddressOnly(boolean getOnly) {
359 mGetNameAddressOnly = getOnly;
360 }
361
362 public boolean isGetNameAddressOnly() {
363 return mGetNameAddressOnly;
364 }
365
366 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700367 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700368 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
369 msg.obj = service;
370 mHandler.sendMessage(msg);
371 }
372
373 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700374 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700375 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700376 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
377 mHandler.sendMessage(msg);
378 }
379 }
380
381 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
382
383 private final Handler mHandler = new Handler() {
384 @Override
385 public void handleMessage(Message msg) {
386 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700387 switch (msg.what) {
388 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700389 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700390 if (mBluetooth == null) {
391 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700392 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700393 if (DBG) Log.d(TAG, "Binding to service to get name and address");
394 mConnection.setGetNameAddressOnly(true);
395 //Start bind timeout and bind
396 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
397 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
398 Intent i = new Intent(IBluetooth.class.getName());
399 if (!mContext.bindService(i, mConnection,
400 Context.BIND_AUTO_CREATE)) {
401 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
402 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
403 }
404 }
405 } else {
406 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
407 mHandler.sendMessage(saveMsg);
408 }
409 }
fredc649fe492012-04-19 01:07:18 -0700410 break;
fredc0f420372012-04-12 00:02:00 -0700411 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700412 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
fredc0f420372012-04-12 00:02:00 -0700413 if (mBluetooth != null) {
414 String name = null;
415 String address = null;
416 try {
417 name = mBluetooth.getName();
418 address = mBluetooth.getAddress();
419 } catch (RemoteException re) {
420 Log.e(TAG,"",re);
421 }
422
423 if (name != null && address != null) {
424 storeNameAndAddress(name,address);
fredc649fe492012-04-19 01:07:18 -0700425 Intent i = new Intent(IBluetooth.class.getName());
426 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
427 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
428 mContext.startService(i);
429 unbindAndFinish();
430 } else {
fredc0f420372012-04-12 00:02:00 -0700431 if (msg.arg1 < MAX_SAVE_RETRIES) {
432 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
433 retryMsg.arg1= 1+msg.arg1;
434 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
435 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
436 } else {
437 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
fredc649fe492012-04-19 01:07:18 -0700438 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700439 }
440 }
441 }
442 }
fredc649fe492012-04-19 01:07:18 -0700443 break;
444 case MESSAGE_AIRPLANE_MODE_OFF: {
445 if (DBG) Log.d(TAG,"MESSAGE_AIRPLANE_MODE_OFF");
446 //Check if we should turn on bluetooth
447 if (!isBluetoothPersistedStateOn()) {
448 if (DBG)Log.d(TAG, "Bluetooth persisted state is off. Not turning on Bluetooth.");
449 return;
450 }
451 //Fall through to MESSAGE_ENABLE
452 }
fredc0f420372012-04-12 00:02:00 -0700453 case MESSAGE_ENABLE: {
fredcf2458862012-04-16 15:18:27 -0700454 if (DBG) {
fredc649fe492012-04-19 01:07:18 -0700455 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth +
456 " isConnected = " + isConnected());
457 }
458 boolean persist = (1==msg.arg1);
459 if (persist) {
460 persistBluetoothSetting(true);
461 }
fredc0f420372012-04-12 00:02:00 -0700462 if (mBluetooth == null) {
463 //Start bind request
fredcf2458862012-04-16 15:18:27 -0700464 if (!isConnected()) {
fredc0f420372012-04-12 00:02:00 -0700465 //Start bind timeout and bind
466 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
467 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
468 Intent i = new Intent(IBluetooth.class.getName());
469 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
470 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
471 mContext.startService(i);
472 mConnection.setGetNameAddressOnly(false);
fredc649fe492012-04-19 01:07:18 -0700473 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE)) {
fredc0f420372012-04-12 00:02:00 -0700474 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
fredc649fe492012-04-19 01:07:18 -0700475 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
fredc0f420372012-04-12 00:02:00 -0700476 }
477 }
478 } else {
479 //Check if name and address is loaded if not get it first.
480 if (ALWAYS_SYNC_NAME_ADDRESS || !isNameAndAddressSet()) {
481 try {
fredc649fe492012-04-19 01:07:18 -0700482 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
fredc0f420372012-04-12 00:02:00 -0700483 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
484 } catch (RemoteException e) {Log.e(TAG, "", e);};
485 }
fredc649fe492012-04-19 01:07:18 -0700486 Intent i = new Intent(IBluetooth.class.getName());
487 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
488 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
489 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700490 }
491 // TODO(BT) what if service failed to start:
492 // [fc] fixed: watch for bind timeout and handle accordingly
493 // TODO(BT) persist the setting depending on argument
494 // [fc]: let AdapterServiceHandle
495 }
fredc649fe492012-04-19 01:07:18 -0700496 break;
497 case MESSAGE_AIRPLANE_MODE_ON:;
498 if (DBG) {
499 Log.d(TAG, "MESSAGE_AIRPLANE_MODE_ON: mBluetooth = " + mBluetooth +
500 " isConnected = " + isConnected());
501 //Fall through to MESSAGE_DISABLE
502 }
fredc0f420372012-04-12 00:02:00 -0700503 case MESSAGE_DISABLE:
504 if (mBluetooth != null ) {
fredc649fe492012-04-19 01:07:18 -0700505 boolean persist = (1==msg.arg1);
506 if (persist) {
507 persistBluetoothSetting(false);
fredc0f420372012-04-12 00:02:00 -0700508 }
fredc649fe492012-04-19 01:07:18 -0700509 mConnection.setGetNameAddressOnly(false);
510 if (DBG) Log.d(TAG,"Sending off request.");
511 Intent i = new Intent(IBluetooth.class.getName());
512 i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
513 i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
514 mContext.startService(i);
fredc0f420372012-04-12 00:02:00 -0700515 }
fredc0f420372012-04-12 00:02:00 -0700516 // TODO(BT) what if service failed to stop:
517 // [fc] fixed: watch for disable event and unbind accordingly
518 // TODO(BT) persist the setting depending on argument
519 // [fc]: let AdapterServiceHandle
520
521 break;
522 case MESSAGE_REGISTER_ADAPTER:
523 {
524 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
525 mCallbacks.add(callback);
526 }
527 break;
528 case MESSAGE_UNREGISTER_ADAPTER:
529 {
530 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
531 mCallbacks.remove(callback);
532 }
533 break;
534 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
535 {
536 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
537 mStateChangeCallbacks.add(callback);
538 }
539 break;
540 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
541 {
542 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
543 mStateChangeCallbacks.remove(callback);
544 }
545 break;
546 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
547 {
fredc649fe492012-04-19 01:07:18 -0700548 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
549
fredc0f420372012-04-12 00:02:00 -0700550 //Remove timeout
551 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
552
553 IBinder service = (IBinder) msg.obj;
554 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700555 mBinding = false;
556 mBluetooth = IBluetooth.Stub.asInterface(service);
557 }
558
559 if (mConnection.isGetNameAddressOnly()) {
560 //Request GET NAME AND ADDRESS
561 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
562 mHandler.sendMessage(getMsg);
563 return;
564 }
565
fredc0f420372012-04-12 00:02:00 -0700566 try {
567 for (IBluetoothManagerCallback callback : mCallbacks) {
568 callback.onBluetoothServiceUp(mBluetooth);
569 }
570 } catch (RemoteException e) {
571 Log.e(TAG, "", e);
572 }
573
fredc0f420372012-04-12 00:02:00 -0700574 }
fredc649fe492012-04-19 01:07:18 -0700575 break;
576 case MESSAGE_TIMEOUT_BIND: {
577 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700578 synchronized(mConnection) {
579 mBinding = false;
580 }
581 }
fredc649fe492012-04-19 01:07:18 -0700582 break;
fredc0f420372012-04-12 00:02:00 -0700583 case MESSAGE_BLUETOOTH_ON:
584 {
fredc649fe492012-04-19 01:07:18 -0700585 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_ON");
586 try {
fredc0f420372012-04-12 00:02:00 -0700587 for (IBluetoothStateChangeCallback callback : mStateChangeCallbacks) {
588 callback.onBluetoothStateChange(true);
589 }
590 } catch (RemoteException e) {
591 Log.e(TAG, "", e);
592 }
593 }
594 break;
fredc0f420372012-04-12 00:02:00 -0700595 case MESSAGE_BLUETOOTH_OFF:
596 {
fredc649fe492012-04-19 01:07:18 -0700597 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_OFF");
fredc0f420372012-04-12 00:02:00 -0700598 try {
599 for (IBluetoothStateChangeCallback callback : mStateChangeCallbacks) {
600 callback.onBluetoothStateChange(false);
601 }
602 } catch (RemoteException e) {
603 Log.e(TAG, "", e);
604 }
fredc649fe492012-04-19 01:07:18 -0700605 unbindAndFinish();
fredc0f420372012-04-12 00:02:00 -0700606 }
fredc649fe492012-04-19 01:07:18 -0700607 break;
fredc0f420372012-04-12 00:02:00 -0700608 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
609 {
fredc649fe492012-04-19 01:07:18 -0700610 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredc0f420372012-04-12 00:02:00 -0700611 boolean isUnexpectedDisconnect = false;
612 synchronized(mConnection) {
613 mBluetooth = null;
fredc0f420372012-04-12 00:02:00 -0700614 if (mUnbinding) {
615 mUnbinding = false;
616 } else {
617 isUnexpectedDisconnect = true;
618 }
619 }
fredc649fe492012-04-19 01:07:18 -0700620 if (!mConnection.isGetNameAddressOnly()) {
621 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: Calling onBluetoothSerivceDown callbacks");
fredc0f420372012-04-12 00:02:00 -0700622 try {
623 for (IBluetoothManagerCallback callback : mCallbacks) {
624 callback.onBluetoothServiceDown();
625 }
626 } catch (RemoteException e) {
627 Log.e(TAG, "", e);
628 }
629 }
630 }
fredc649fe492012-04-19 01:07:18 -0700631 break;
fredc0f420372012-04-12 00:02:00 -0700632 case MESSAGE_TIMEOUT_UNBIND:
633 {
fredc649fe492012-04-19 01:07:18 -0700634 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700635 synchronized(mConnection) {
636 mUnbinding = false;
637 }
638 }
fredc649fe492012-04-19 01:07:18 -0700639 break;
fredc0f420372012-04-12 00:02:00 -0700640 }
641 }
642 };
643}