blob: e7cd2791a498389015d192379655b1b2bf44b50e [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;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -070025import android.os.Binder;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070026import android.os.UserHandle;
fredc0f420372012-04-12 00:02:00 -070027import android.provider.Settings;
28import android.util.Log;
29import java.util.List;
30import java.util.ArrayList;
fredc0f420372012-04-12 00:02:00 -070031class BluetoothManagerService extends IBluetoothManager.Stub {
32 private static final String TAG = "BluetoothManagerService";
33 private static final boolean DBG = true;
34
fredc0f420372012-04-12 00:02:00 -070035 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
36 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070037 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
38 private static final String EXTRA_ACTION="action";
fredc0f420372012-04-12 00:02:00 -070039 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
40 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070041 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
42 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053043 //Maximum msec to wait for service restart
44 private static final int SERVICE_RESTART_TIME_MS = 200;
fredc0f420372012-04-12 00:02:00 -070045
46 private static final int MESSAGE_ENABLE = 1;
47 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070048 private static final int MESSAGE_REGISTER_ADAPTER = 20;
49 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
50 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
51 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
52 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
53 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053054 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070055 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070056 private static final int MESSAGE_TIMEOUT_BIND =100;
57 private static final int MESSAGE_TIMEOUT_UNBIND =101;
58 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
59 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
60 private static final int MAX_SAVE_RETRIES=3;
61
62 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070063
64 // Locks are not provided for mName and mAddress.
65 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070066 private String mAddress;
67 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -070068 private final ContentResolver mContentResolver;
69 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
70 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070071 private IBluetooth mBluetooth;
72 private boolean mBinding;
73 private boolean mUnbinding;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -070074 private boolean mQuietEnable = false;
fredc0f420372012-04-12 00:02:00 -070075
fredc649fe492012-04-19 01:07:18 -070076 private void registerForAirplaneMode(IntentFilter filter) {
77 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -070078 final String airplaneModeRadios = Settings.Global.getString(resolver,
79 Settings.Global.AIRPLANE_MODE_RADIOS);
80 final String toggleableRadios = Settings.Global.getString(resolver,
81 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -070082 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -070083 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -070084 if (mIsAirplaneSensitive) {
85 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
86 }
87 }
88
fredcbf072a72012-05-09 16:52:50 -070089 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
90 @Override
91 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
92 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
93 mHandler.sendMessage(msg);
94 }
95 };
96
97 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -070098 @Override
99 public void onReceive(Context context, Intent intent) {
100 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700101 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700102 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700103 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700104 if (newName != null) {
105 storeNameAndAddress(newName, null);
106 }
fredc649fe492012-04-19 01:07:18 -0700107 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
108 if (isAirplaneModeOn()) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700109 // disable without persisting the setting
110 handleDisable(false);
fredc649fe492012-04-19 01:07:18 -0700111 } else {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700112 if (isBluetoothPersistedStateOn()) {
113 // enable without persisting the setting
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700114 handleEnable(false, false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700115 }
fredc649fe492012-04-19 01:07:18 -0700116 }
fredc0f420372012-04-12 00:02:00 -0700117 }
118 }
119 };
120
121 BluetoothManagerService(Context context) {
122 mContext = context;
123 mBluetooth = null;
124 mBinding = false;
125 mUnbinding = false;
126 mAddress = null;
127 mName = null;
128 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700129 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
130 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Matthew Xie6fde3092012-07-11 17:10:07 -0700131 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
132 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
133 registerForAirplaneMode(filter);
134 mContext.registerReceiver(mReceiver, filter);
fredc649fe492012-04-19 01:07:18 -0700135 boolean airplaneModeOn = isAirplaneModeOn();
136 boolean bluetoothOn = isBluetoothPersistedStateOn();
fredc0f420372012-04-12 00:02:00 -0700137 loadStoredNameAndAddress();
fredc649fe492012-04-19 01:07:18 -0700138 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
Andre Eisenbacha732ffd2012-05-02 00:39:24 -0700139 if (bluetoothOn) {
fredc0f420372012-04-12 00:02:00 -0700140 //Enable
fredc649fe492012-04-19 01:07:18 -0700141 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
fredc0f420372012-04-12 00:02:00 -0700142 enable();
Freda8c6df02012-07-11 10:25:23 -0700143 } else if (!isNameAndAddressSet()) {
fredc649fe492012-04-19 01:07:18 -0700144 //Sync the Bluetooth name and address from the Bluetooth Adapter
145 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
fredc0f420372012-04-12 00:02:00 -0700146 getNameAndAddress();
147 }
148 }
149
fredc649fe492012-04-19 01:07:18 -0700150 /**
151 * Returns true if airplane mode is currently on
152 */
153 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700154 return Settings.Global.getInt(mContext.getContentResolver(),
155 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700156 }
157
158 /**
159 * Returns true if the Bluetooth saved state is "on"
160 */
161 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700162 return Settings.Global.getInt(mContentResolver,
163 Settings.Global.BLUETOOTH_ON, 0) ==1;
fredc649fe492012-04-19 01:07:18 -0700164 }
165
166 /**
167 * Save the Bluetooth on/off state
168 *
169 */
170 private void persistBluetoothSetting(boolean setOn) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700171 Settings.Global.putInt(mContext.getContentResolver(),
172 Settings.Global.BLUETOOTH_ON,
fredc649fe492012-04-19 01:07:18 -0700173 setOn ? 1 : 0);
174 }
175
176 /**
177 * Returns true if the Bluetooth Adapter's name and address is
178 * locally cached
179 * @return
180 */
fredc0f420372012-04-12 00:02:00 -0700181 private boolean isNameAndAddressSet() {
182 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
183 }
184
fredc649fe492012-04-19 01:07:18 -0700185 /**
186 * Retrieve the Bluetooth Adapter's name and address and save it in
187 * in the local cache
188 */
fredc0f420372012-04-12 00:02:00 -0700189 private void loadStoredNameAndAddress() {
190 if (DBG) Log.d(TAG, "Loading stored name and address");
191 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
192 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
193 if (mName == null || mAddress == null) {
194 if (DBG) Log.d(TAG, "Name or address not cached...");
195 }
196 }
197
fredc649fe492012-04-19 01:07:18 -0700198 /**
199 * Save the Bluetooth name and address in the persistent store.
200 * Only non-null values will be saved.
201 * @param name
202 * @param address
203 */
fredc0f420372012-04-12 00:02:00 -0700204 private void storeNameAndAddress(String name, String address) {
205 if (name != null) {
206 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700207 mName = name;
fredc649fe492012-04-19 01:07:18 -0700208 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
209 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700210 }
211
212 if (address != null) {
213 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700214 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700215 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
216 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700217 }
218 }
219
220 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
fredc0f420372012-04-12 00:02:00 -0700221 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
222 msg.obj = callback;
223 mHandler.sendMessage(msg);
224 synchronized(mConnection) {
225 return mBluetooth;
226 }
227 }
228
229 public void unregisterAdapter(IBluetoothManagerCallback callback) {
230 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
231 "Need BLUETOOTH permission");
232 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
233 msg.obj = callback;
234 mHandler.sendMessage(msg);
235 }
236
237 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
238 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
239 "Need BLUETOOTH permission");
240 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
241 msg.obj = callback;
242 mHandler.sendMessage(msg);
243 }
244
245 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
246 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
247 "Need BLUETOOTH permission");
248 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
249 msg.obj = callback;
250 mHandler.sendMessage(msg);
251 }
252
253 public boolean isEnabled() {
254 synchronized(mConnection) {
255 try {
256 return (mBluetooth != null && mBluetooth.isEnabled());
257 } catch (RemoteException e) {
258 Log.e(TAG, "isEnabled()", e);
259 }
260 }
261 return false;
262 }
263
264 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700265 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700266 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
267 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700268 }
fredc0f420372012-04-12 00:02:00 -0700269 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700270 if (mBinding) return;
271 if (mConnection == null) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700272 }
273 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
274 mHandler.sendMessage(msg);
275 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700276 public boolean enableNoAutoConnect()
277 {
278 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
279 "Need BLUETOOTH ADMIN permission");
280 if (DBG) {
281 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
282 " mBinding = " + mBinding);
283 }
284 if (Binder.getCallingUid() != android.os.Process.NFC_UID) {
285 throw new SecurityException("no permission to enable Bluetooth quietly");
286 }
287 synchronized(mConnection) {
288 if (mBinding) {
289 Log.w(TAG,"enableNoAutoConnect(): binding in progress. Returning..");
290 return true;
291 }
292 if (mConnection == null) mBinding = true;
293 }
fredc0f420372012-04-12 00:02:00 -0700294
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700295 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
296 msg.arg1=0; //No persist
297 msg.arg2=1; //Quiet mode
298 mHandler.sendMessage(msg);
299 return true;
300
301 }
fredc0f420372012-04-12 00:02:00 -0700302 public boolean enable() {
303 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
304 "Need BLUETOOTH ADMIN permission");
fredcf2458862012-04-16 15:18:27 -0700305 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700306 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
307 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700308 }
309
fredc0f420372012-04-12 00:02:00 -0700310 synchronized(mConnection) {
fredc649fe492012-04-19 01:07:18 -0700311 if (mBinding) {
312 Log.w(TAG,"enable(): binding in progress. Returning..");
313 return true;
314 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700315 if (mConnection == null) mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700316 }
fredc116d1d462012-04-20 14:47:08 -0700317
fredc0f420372012-04-12 00:02:00 -0700318 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
fredc649fe492012-04-19 01:07:18 -0700319 msg.arg1=1; //persist
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700320 msg.arg2=0; //No Quiet Mode
fredc0f420372012-04-12 00:02:00 -0700321 mHandler.sendMessage(msg);
322 return true;
323 }
324
325 public boolean disable(boolean persist) {
326 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
327 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
fredcf2458862012-04-16 15:18:27 -0700328 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700329 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
330 " mBinding = " + mBinding);
331 }
fredcf2458862012-04-16 15:18:27 -0700332
fredc0f420372012-04-12 00:02:00 -0700333 synchronized(mConnection) {
334 if (mBluetooth == null) return false;
fredc0f420372012-04-12 00:02:00 -0700335 }
336 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700337 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700338 mHandler.sendMessage(msg);
339 return true;
340 }
341
fredc649fe492012-04-19 01:07:18 -0700342 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700343 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700344 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
345 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700346 }
347
fredc0f420372012-04-12 00:02:00 -0700348 synchronized (mConnection) {
349 if (mUnbinding) return;
350 mUnbinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700351 if (mConnection != null) {
fredcbf072a72012-05-09 16:52:50 -0700352 if (!mConnection.isGetNameAddressOnly()) {
353 //Unregister callback object
354 try {
355 mBluetooth.unregisterCallback(mBluetoothCallback);
356 } catch (RemoteException re) {
357 Log.e(TAG, "Unable to register BluetoothCallback",re);
358 }
359 }
fredc0f420372012-04-12 00:02:00 -0700360 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700361 mBluetooth = null;
362 //Unbind
fredc0f420372012-04-12 00:02:00 -0700363 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700364 mUnbinding = false;
fredcf2458862012-04-16 15:18:27 -0700365 } else {
366 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700367 }
368 }
369 }
370
fredcbf072a72012-05-09 16:52:50 -0700371 private void sendBluetoothStateCallback(boolean isUp) {
372 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700373 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700374 for (int i=0; i <n;i++) {
375 try {
376 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
377 } catch (RemoteException e) {
378 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
379 }
380 }
381 mStateChangeCallbacks.finishBroadcast();
382 }
383
384 /**
385 * Inform BluetoothAdapter instances that Adapter service is down
386 */
387 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700388 if (!mConnection.isGetNameAddressOnly()) {
389 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
390 int n = mCallbacks.beginBroadcast();
391 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
392 for (int i=0; i <n;i++) {
393 try {
394 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
395 } catch (RemoteException e) {
396 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
397 }
398 }
399 mCallbacks.finishBroadcast();
400 }
401 }
fredc0f420372012-04-12 00:02:00 -0700402 public String getAddress() {
403 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
404 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700405 synchronized(mConnection) {
406 if (mBluetooth != null) {
407 try {
408 return mBluetooth.getAddress();
409 } catch (RemoteException e) {
410 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
411 }
412 }
413 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700414 // mAddress is accessed from outside.
415 // It is alright without a lock. Here, bluetooth is off, no other thread is
416 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700417 return mAddress;
418 }
fredc649fe492012-04-19 01:07:18 -0700419
fredc0f420372012-04-12 00:02:00 -0700420 public String getName() {
421 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
422 "Need BLUETOOTH ADMIN permission");
fredc116d1d462012-04-20 14:47:08 -0700423 synchronized(mConnection) {
424 if (mBluetooth != null) {
425 try {
426 return mBluetooth.getName();
427 } catch (RemoteException e) {
428 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
429 }
430 }
431 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700432 // mName is accessed from outside.
433 // It alright without a lock. Here, bluetooth is off, no other thread is
434 // changing mName
fredc0f420372012-04-12 00:02:00 -0700435 return mName;
436 }
437
fredc0f420372012-04-12 00:02:00 -0700438 private class BluetoothServiceConnection implements ServiceConnection {
439
440 private boolean mGetNameAddressOnly;
441
442 public void setGetNameAddressOnly(boolean getOnly) {
443 mGetNameAddressOnly = getOnly;
444 }
445
446 public boolean isGetNameAddressOnly() {
447 return mGetNameAddressOnly;
448 }
449
450 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700451 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700452 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
453 msg.obj = service;
454 mHandler.sendMessage(msg);
455 }
456
457 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700458 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700459 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700460 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
461 mHandler.sendMessage(msg);
462 }
463 }
464
465 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
466
467 private final Handler mHandler = new Handler() {
468 @Override
469 public void handleMessage(Message msg) {
470 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700471 switch (msg.what) {
472 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700473 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700474 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700475 //Start bind request
Matthew Xiecdce0b92012-07-12 19:06:15 -0700476 if (mBluetooth == null) {
fredc0f420372012-04-12 00:02:00 -0700477 if (DBG) Log.d(TAG, "Binding to service to get name and address");
478 mConnection.setGetNameAddressOnly(true);
479 //Start bind timeout and bind
480 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
481 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
482 Intent i = new Intent(IBluetooth.class.getName());
483 if (!mContext.bindService(i, mConnection,
Matthew Xiefca9d632012-10-04 12:25:28 -0700484 Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700485 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
486 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
487 }
488 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700489 else {
490 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
491 mHandler.sendMessage(saveMsg);
492 }
fredc0f420372012-04-12 00:02:00 -0700493 }
fredc649fe492012-04-19 01:07:18 -0700494 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700495 }
fredc0f420372012-04-12 00:02:00 -0700496 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700497 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700498 synchronized(mConnection) {
499 if (mBluetooth != null) {
500 String name = null;
501 String address = null;
502 try {
503 name = mBluetooth.getName();
504 address = mBluetooth.getAddress();
505 } catch (RemoteException re) {
506 Log.e(TAG,"",re);
507 }
fredc0f420372012-04-12 00:02:00 -0700508
Matthew Xiecdce0b92012-07-12 19:06:15 -0700509 if (name != null && address != null) {
510 storeNameAndAddress(name,address);
fredcbf072a72012-05-09 16:52:50 -0700511 sendBluetoothServiceDownCallback();
fredc649fe492012-04-19 01:07:18 -0700512 unbindAndFinish();
Matthew Xiecdce0b92012-07-12 19:06:15 -0700513 } else {
514 if (msg.arg1 < MAX_SAVE_RETRIES) {
515 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
516 retryMsg.arg1= 1+msg.arg1;
517 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
518 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
519 } else {
520 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
521 sendBluetoothServiceDownCallback();
522 unbindAndFinish();
523 }
fredc0f420372012-04-12 00:02:00 -0700524 }
525 }
526 }
fredc649fe492012-04-19 01:07:18 -0700527 break;
fredc649fe492012-04-19 01:07:18 -0700528 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700529 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700530 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700531 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700532 }
Freda8c6df02012-07-11 10:25:23 -0700533
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700534 handleEnable(msg.arg1 == 1, msg.arg2 ==1);
fredc649fe492012-04-19 01:07:18 -0700535 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700536
fredc0f420372012-04-12 00:02:00 -0700537 case MESSAGE_DISABLE:
Matthew Xiecdce0b92012-07-12 19:06:15 -0700538 handleDisable(msg.arg1 == 1);
fredc0f420372012-04-12 00:02:00 -0700539 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700540
fredc0f420372012-04-12 00:02:00 -0700541 case MESSAGE_REGISTER_ADAPTER:
542 {
543 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700544 boolean added = mCallbacks.register(callback);
545 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700546 }
547 break;
548 case MESSAGE_UNREGISTER_ADAPTER:
549 {
550 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700551 boolean removed = mCallbacks.unregister(callback);
552 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700553 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700554 }
fredc0f420372012-04-12 00:02:00 -0700555 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
556 {
557 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700558 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700559 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700560 }
fredc0f420372012-04-12 00:02:00 -0700561 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
562 {
563 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700564 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700565 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700566 }
fredc0f420372012-04-12 00:02:00 -0700567 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
568 {
fredc649fe492012-04-19 01:07:18 -0700569 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
570
fredc0f420372012-04-12 00:02:00 -0700571 //Remove timeout
572 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
573
574 IBinder service = (IBinder) msg.obj;
575 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700576 mBinding = false;
577 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700578
Matthew Xiecdce0b92012-07-12 19:06:15 -0700579 if (mConnection.isGetNameAddressOnly()) {
580 //Request GET NAME AND ADDRESS
581 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
582 mHandler.sendMessage(getMsg);
583 return;
584 }
fredc0f420372012-04-12 00:02:00 -0700585
Matthew Xiecdce0b92012-07-12 19:06:15 -0700586 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700587 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700588 mBluetooth.registerCallback(mBluetoothCallback);
589 } catch (RemoteException re) {
590 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700591 }
fredcbf072a72012-05-09 16:52:50 -0700592
Matthew Xiecdce0b92012-07-12 19:06:15 -0700593 //Inform BluetoothAdapter instances that service is up
594 int n = mCallbacks.beginBroadcast();
595 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
596 for (int i=0; i <n;i++) {
597 try {
598 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
599 } catch (RemoteException e) {
600 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
601 }
Freda8c6df02012-07-11 10:25:23 -0700602 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700603 mCallbacks.finishBroadcast();
604
605 //Do enable request
606 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700607 if (mQuietEnable == false) {
608 if(!mBluetooth.enable()) {
609 Log.e(TAG,"IBluetooth.enable() returned false");
610 }
611 }
612 else
613 {
614 if(!mBluetooth.enableNoAutoConnect()) {
615 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
616 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700617 }
618 } catch (RemoteException e) {
619 Log.e(TAG,"Unable to call enable()",e);
620 }
Freda8c6df02012-07-11 10:25:23 -0700621 }
fredc649fe492012-04-19 01:07:18 -0700622 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700623 }
fredc649fe492012-04-19 01:07:18 -0700624 case MESSAGE_TIMEOUT_BIND: {
625 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700626 synchronized(mConnection) {
627 mBinding = false;
628 }
fredc649fe492012-04-19 01:07:18 -0700629 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700630 }
fredcbf072a72012-05-09 16:52:50 -0700631 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700632 {
fredcbf072a72012-05-09 16:52:50 -0700633 int prevState = msg.arg1;
634 int newState = msg.arg2;
635 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
636 if (prevState != newState) {
637 //Notify all proxy objects first of adapter state change
638 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
639 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
640 sendBluetoothStateCallback(isUp);
641
642 //If Bluetooth is off, send service down event to proxy objects, and unbind
643 if (!isUp) {
644 sendBluetoothServiceDownCallback();
645 unbindAndFinish();
646 }
fredc0f420372012-04-12 00:02:00 -0700647 }
fredcbf072a72012-05-09 16:52:50 -0700648
649 //Send broadcast message to everyone else
650 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
651 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
652 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
653 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
654 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700655 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
656 BLUETOOTH_PERM);
fredc0f420372012-04-12 00:02:00 -0700657 }
fredc649fe492012-04-19 01:07:18 -0700658 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700659 }
fredc0f420372012-04-12 00:02:00 -0700660 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
661 {
fredc649fe492012-04-19 01:07:18 -0700662 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
fredcbf072a72012-05-09 16:52:50 -0700663 sendBluetoothServiceDownCallback();
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530664
665 // Send BT state broadcast to update
666 // the BT icon correctly
667 Message stateChangeMsg = mHandler.obtainMessage(
668 MESSAGE_BLUETOOTH_STATE_CHANGE);
669 stateChangeMsg.arg1 = BluetoothAdapter.STATE_ON;
670 stateChangeMsg.arg2 =
671 BluetoothAdapter.STATE_TURNING_OFF;
672 mHandler.sendMessage(stateChangeMsg);
673 synchronized(mConnection) {
674 mBluetooth = null;
675 }
676 // Send a Bluetooth Restart message
677 Message restartMsg = mHandler.obtainMessage(
678 MESSAGE_RESTART_BLUETOOTH_SERVICE);
679 mHandler.sendMessageDelayed(restartMsg,
680 SERVICE_RESTART_TIME_MS);
fredc649fe492012-04-19 01:07:18 -0700681 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700682 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530683 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
684 {
685 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
686 +" Restart IBluetooth service");
687 /* Enable without persisting the setting as
688 it doesnt change when IBluetooth
689 service restarts */
690 handleEnable(false, mQuietEnable);
691 break;
692 }
693
fredc0f420372012-04-12 00:02:00 -0700694 case MESSAGE_TIMEOUT_UNBIND:
695 {
fredc649fe492012-04-19 01:07:18 -0700696 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700697 synchronized(mConnection) {
698 mUnbinding = false;
699 }
fredc649fe492012-04-19 01:07:18 -0700700 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700701 }
fredc0f420372012-04-12 00:02:00 -0700702 }
703 }
704 };
Matthew Xiecdce0b92012-07-12 19:06:15 -0700705
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700706 private void handleEnable(boolean persist, boolean quietMode) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700707 if (persist) {
708 persistBluetoothSetting(true);
709 }
710
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700711 mQuietEnable = quietMode;
712
Matthew Xiecdce0b92012-07-12 19:06:15 -0700713 synchronized(mConnection) {
714 if (mBluetooth == null) {
715 //Start bind timeout and bind
716 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
717 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
718 mConnection.setGetNameAddressOnly(false);
719 Intent i = new Intent(IBluetooth.class.getName());
Matthew Xiefca9d632012-10-04 12:25:28 -0700720 if (!mContext.bindService(i, mConnection, Context.BIND_AUTO_CREATE,
721 UserHandle.USER_CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700722 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
723 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
724 }
725 } else {
726 //Check if name and address is loaded if not get it first.
727 if (!isNameAndAddressSet()) {
728 try {
729 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
730 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
731 } catch (RemoteException e) {Log.e(TAG, "", e);};
732 }
733
734 //Enable bluetooth
735 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700736 if (!mQuietEnable) {
737 if(!mBluetooth.enable()) {
738 Log.e(TAG,"IBluetooth.enable() returned false");
739 }
740 }
741 else {
742 if(!mBluetooth.enableNoAutoConnect()) {
743 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
744 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700745 }
746 } catch (RemoteException e) {
747 Log.e(TAG,"Unable to call enable()",e);
748 }
749 }
750 }
751 }
752
753 private void handleDisable(boolean persist) {
754 synchronized(mConnection) {
755 if (mBluetooth != null ) {
756 if (persist) {
757 persistBluetoothSetting(false);
758 }
759 mConnection.setGetNameAddressOnly(false);
760 if (DBG) Log.d(TAG,"Sending off request.");
761
762 try {
763 if(!mBluetooth.disable()) {
764 Log.e(TAG,"IBluetooth.disable() returned false");
765 }
766 } catch (RemoteException e) {
767 Log.e(TAG,"Unable to call disable()",e);
768 }
769 }
770 }
771 }
fredc0f420372012-04-12 00:02:00 -0700772}