blob: 18182cd9079d99521e56faa1f7a2f0ba1e0d7c35 [file] [log] [blame]
fredc0f420372012-04-12 00:02:00 -07001/*
2 * Copyright (C) 2012 Google Inc.
3 */
4
5package com.android.server;
6
Zhihai Xu40874a02012-10-08 17:57:03 -07007import android.app.ActivityManager;
fredc0f420372012-04-12 00:02:00 -07008import android.bluetooth.BluetoothAdapter;
9import android.bluetooth.IBluetooth;
fredcbf072a72012-05-09 16:52:50 -070010import android.bluetooth.IBluetoothCallback;
fredc0f420372012-04-12 00:02:00 -070011import android.bluetooth.IBluetoothManager;
12import android.bluetooth.IBluetoothManagerCallback;
13import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070014import android.content.BroadcastReceiver;
15import android.content.ComponentName;
16import android.content.ContentResolver;
17import android.content.Context;
18import android.content.Intent;
19import android.content.IntentFilter;
20import android.content.ServiceConnection;
Zhihai Xu40874a02012-10-08 17:57:03 -070021import android.os.Binder;
fredc0f420372012-04-12 00:02:00 -070022import android.os.Handler;
Zhihai Xu40874a02012-10-08 17:57:03 -070023import android.os.HandlerThread;
fredc0f420372012-04-12 00:02:00 -070024import android.os.IBinder;
Zhihai Xu40874a02012-10-08 17:57:03 -070025import android.os.Looper;
fredc0f420372012-04-12 00:02:00 -070026import android.os.Message;
Zhihai Xu40874a02012-10-08 17:57:03 -070027import android.os.Process;
fredcd6883532012-04-25 17:46:13 -070028import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070029import android.os.RemoteException;
Zhihai Xu40874a02012-10-08 17:57:03 -070030import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070031import android.os.UserHandle;
fredc0f420372012-04-12 00:02:00 -070032import android.provider.Settings;
33import android.util.Log;
fredc0f420372012-04-12 00:02:00 -070034import java.util.ArrayList;
Zhihai Xu40874a02012-10-08 17:57:03 -070035import java.util.List;
fredc0f420372012-04-12 00:02:00 -070036class BluetoothManagerService extends IBluetoothManager.Stub {
37 private static final String TAG = "BluetoothManagerService";
38 private static final boolean DBG = true;
39
fredc0f420372012-04-12 00:02:00 -070040 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
41 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070042 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
43 private static final String EXTRA_ACTION="action";
fredc0f420372012-04-12 00:02:00 -070044 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
45 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070046 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
47 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053048 //Maximum msec to wait for service restart
49 private static final int SERVICE_RESTART_TIME_MS = 200;
Zhihai Xu40874a02012-10-08 17:57:03 -070050 //Maximum msec to delay MESSAGE_USER_SWITCHED
51 private static final int USER_SWITCHED_TIME_MS = 200;
fredc0f420372012-04-12 00:02:00 -070052
53 private static final int MESSAGE_ENABLE = 1;
54 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070055 private static final int MESSAGE_REGISTER_ADAPTER = 20;
56 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
57 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
58 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
59 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
60 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053061 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070062 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070063 private static final int MESSAGE_TIMEOUT_BIND =100;
64 private static final int MESSAGE_TIMEOUT_UNBIND =101;
65 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
66 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
Zhihai Xu40874a02012-10-08 17:57:03 -070067 private static final int MESSAGE_USER_SWITCHED = 300;
fredc0f420372012-04-12 00:02:00 -070068 private static final int MAX_SAVE_RETRIES=3;
69
70 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070071
72 // Locks are not provided for mName and mAddress.
73 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070074 private String mAddress;
75 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -070076 private final ContentResolver mContentResolver;
77 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
78 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070079 private IBluetooth mBluetooth;
80 private boolean mBinding;
81 private boolean mUnbinding;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -070082 private boolean mQuietEnable = false;
Zhihai Xu40874a02012-10-08 17:57:03 -070083 private boolean mEnable;
84 private int mState;
85 private HandlerThread mThread;
86 private final BluetoothHandler mHandler;
fredc0f420372012-04-12 00:02:00 -070087
fredc649fe492012-04-19 01:07:18 -070088 private void registerForAirplaneMode(IntentFilter filter) {
89 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -070090 final String airplaneModeRadios = Settings.Global.getString(resolver,
91 Settings.Global.AIRPLANE_MODE_RADIOS);
92 final String toggleableRadios = Settings.Global.getString(resolver,
93 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -070094 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -070095 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -070096 if (mIsAirplaneSensitive) {
97 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
98 }
99 }
100
fredcbf072a72012-05-09 16:52:50 -0700101 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
102 @Override
103 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
104 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
105 mHandler.sendMessage(msg);
106 }
107 };
108
109 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700110 @Override
111 public void onReceive(Context context, Intent intent) {
112 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700113 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700114 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700115 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700116 if (newName != null) {
117 storeNameAndAddress(newName, null);
118 }
fredc649fe492012-04-19 01:07:18 -0700119 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
120 if (isAirplaneModeOn()) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700121 // disable without persisting the setting
122 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE,
123 0, 0));
124 } else if (isBluetoothPersistedStateOn()) {
125 // enable without persisting the setting
126 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
127 0, 0));
fredc649fe492012-04-19 01:07:18 -0700128 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700129 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
130 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
131 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
fredc0f420372012-04-12 00:02:00 -0700132 }
133 }
134 };
135
136 BluetoothManagerService(Context context) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700137 mThread = new HandlerThread("BluetoothManager");
138 mThread.start();
139 mHandler = new BluetoothHandler(mThread.getLooper());
140
fredc0f420372012-04-12 00:02:00 -0700141 mContext = context;
142 mBluetooth = null;
143 mBinding = false;
144 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700145 mEnable = false;
146 mState = BluetoothAdapter.STATE_OFF;
fredc0f420372012-04-12 00:02:00 -0700147 mAddress = null;
148 mName = null;
149 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700150 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
151 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Matthew Xie6fde3092012-07-11 17:10:07 -0700152 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
153 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700154 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700155 registerForAirplaneMode(filter);
156 mContext.registerReceiver(mReceiver, filter);
fredc649fe492012-04-19 01:07:18 -0700157 boolean airplaneModeOn = isAirplaneModeOn();
158 boolean bluetoothOn = isBluetoothPersistedStateOn();
fredc0f420372012-04-12 00:02:00 -0700159 loadStoredNameAndAddress();
fredc649fe492012-04-19 01:07:18 -0700160 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
Andre Eisenbacha732ffd2012-05-02 00:39:24 -0700161 if (bluetoothOn) {
fredc0f420372012-04-12 00:02:00 -0700162 //Enable
fredc649fe492012-04-19 01:07:18 -0700163 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
Zhihai Xu40874a02012-10-08 17:57:03 -0700164 enableHelper();
Freda8c6df02012-07-11 10:25:23 -0700165 } else if (!isNameAndAddressSet()) {
fredc649fe492012-04-19 01:07:18 -0700166 //Sync the Bluetooth name and address from the Bluetooth Adapter
167 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
fredc0f420372012-04-12 00:02:00 -0700168 getNameAndAddress();
169 }
170 }
171
fredc649fe492012-04-19 01:07:18 -0700172 /**
173 * Returns true if airplane mode is currently on
174 */
175 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700176 return Settings.Global.getInt(mContext.getContentResolver(),
177 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700178 }
179
180 /**
181 * Returns true if the Bluetooth saved state is "on"
182 */
183 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700184 return Settings.Global.getInt(mContentResolver,
185 Settings.Global.BLUETOOTH_ON, 0) ==1;
fredc649fe492012-04-19 01:07:18 -0700186 }
187
188 /**
189 * Save the Bluetooth on/off state
190 *
191 */
192 private void persistBluetoothSetting(boolean setOn) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700193 Settings.Global.putInt(mContext.getContentResolver(),
194 Settings.Global.BLUETOOTH_ON,
fredc649fe492012-04-19 01:07:18 -0700195 setOn ? 1 : 0);
196 }
197
198 /**
199 * Returns true if the Bluetooth Adapter's name and address is
200 * locally cached
201 * @return
202 */
fredc0f420372012-04-12 00:02:00 -0700203 private boolean isNameAndAddressSet() {
204 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
205 }
206
fredc649fe492012-04-19 01:07:18 -0700207 /**
208 * Retrieve the Bluetooth Adapter's name and address and save it in
209 * in the local cache
210 */
fredc0f420372012-04-12 00:02:00 -0700211 private void loadStoredNameAndAddress() {
212 if (DBG) Log.d(TAG, "Loading stored name and address");
213 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
214 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
215 if (mName == null || mAddress == null) {
216 if (DBG) Log.d(TAG, "Name or address not cached...");
217 }
218 }
219
fredc649fe492012-04-19 01:07:18 -0700220 /**
221 * Save the Bluetooth name and address in the persistent store.
222 * Only non-null values will be saved.
223 * @param name
224 * @param address
225 */
fredc0f420372012-04-12 00:02:00 -0700226 private void storeNameAndAddress(String name, String address) {
227 if (name != null) {
228 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700229 mName = name;
fredc649fe492012-04-19 01:07:18 -0700230 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
231 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700232 }
233
234 if (address != null) {
235 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700236 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700237 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
238 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700239 }
240 }
241
242 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
fredc0f420372012-04-12 00:02:00 -0700243 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
244 msg.obj = callback;
245 mHandler.sendMessage(msg);
246 synchronized(mConnection) {
247 return mBluetooth;
248 }
249 }
250
251 public void unregisterAdapter(IBluetoothManagerCallback callback) {
252 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
253 "Need BLUETOOTH permission");
254 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
255 msg.obj = callback;
256 mHandler.sendMessage(msg);
257 }
258
259 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
260 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
261 "Need BLUETOOTH permission");
262 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
263 msg.obj = callback;
264 mHandler.sendMessage(msg);
265 }
266
267 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
268 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
269 "Need BLUETOOTH permission");
270 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
271 msg.obj = callback;
272 mHandler.sendMessage(msg);
273 }
274
275 public boolean isEnabled() {
Zhihai Xu40874a02012-10-08 17:57:03 -0700276 if (!checkIfCallerIsForegroundUser()) {
277 Log.w(TAG,"isEnabled(): not allowed for non-active user");
278 return false;
279 }
280
fredc0f420372012-04-12 00:02:00 -0700281 synchronized(mConnection) {
282 try {
283 return (mBluetooth != null && mBluetooth.isEnabled());
284 } catch (RemoteException e) {
285 Log.e(TAG, "isEnabled()", e);
286 }
287 }
288 return false;
289 }
290
291 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700292 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700293 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
294 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700295 }
fredc0f420372012-04-12 00:02:00 -0700296 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
297 mHandler.sendMessage(msg);
298 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700299 public boolean enableNoAutoConnect()
300 {
301 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
302 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700303
304 if (!checkIfCallerIsForegroundUser()) {
305 Log.w(TAG,"enableNoAutoConnect(): not allowed for non-active user");
306 return false;
307 }
308
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700309 if (DBG) {
310 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
311 " mBinding = " + mBinding);
312 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700313 if (Binder.getCallingUid() != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700314 throw new SecurityException("no permission to enable Bluetooth quietly");
315 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700316 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
317 msg.arg1=0; //No persist
318 msg.arg2=1; //Quiet mode
319 mHandler.sendMessage(msg);
320 return true;
321
322 }
fredc0f420372012-04-12 00:02:00 -0700323 public boolean enable() {
Zhihai Xu40874a02012-10-08 17:57:03 -0700324 if (!checkIfCallerIsForegroundUser()) {
325 Log.w(TAG,"enable(): not allowed for non-active user");
326 return false;
fredcf2458862012-04-16 15:18:27 -0700327 }
328
Zhihai Xu40874a02012-10-08 17:57:03 -0700329 return enableHelper();
fredc0f420372012-04-12 00:02:00 -0700330 }
331
332 public boolean disable(boolean persist) {
333 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
334 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700335
336 if (!checkIfCallerIsForegroundUser()) {
337 Log.w(TAG,"disable(): not allowed for non-active user");
338 return false;
339 }
340
fredcf2458862012-04-16 15:18:27 -0700341 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700342 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
343 " mBinding = " + mBinding);
344 }
fredcf2458862012-04-16 15:18:27 -0700345
fredc0f420372012-04-12 00:02:00 -0700346 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700347 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700348 mHandler.sendMessage(msg);
349 return true;
350 }
351
fredc649fe492012-04-19 01:07:18 -0700352 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700353 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700354 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
355 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700356 }
357
fredc0f420372012-04-12 00:02:00 -0700358 synchronized (mConnection) {
359 if (mUnbinding) return;
360 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700361 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700362 if (!mConnection.isGetNameAddressOnly()) {
363 //Unregister callback object
364 try {
365 mBluetooth.unregisterCallback(mBluetoothCallback);
366 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700367 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700368 }
369 }
fredc0f420372012-04-12 00:02:00 -0700370 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700371 mBluetooth = null;
372 //Unbind
fredc0f420372012-04-12 00:02:00 -0700373 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700374 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700375 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700376 } else {
377 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700378 }
379 }
380 }
381
fredcbf072a72012-05-09 16:52:50 -0700382 private void sendBluetoothStateCallback(boolean isUp) {
383 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700384 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700385 for (int i=0; i <n;i++) {
386 try {
387 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
388 } catch (RemoteException e) {
389 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
390 }
391 }
392 mStateChangeCallbacks.finishBroadcast();
393 }
394
395 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700396 * Inform BluetoothAdapter instances that Adapter service is up
397 */
398 private void sendBluetoothServiceUpCallback() {
399 if (!mConnection.isGetNameAddressOnly()) {
400 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
401 int n = mCallbacks.beginBroadcast();
402 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
403 for (int i=0; i <n;i++) {
404 try {
405 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
406 } catch (RemoteException e) {
407 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
408 }
409 }
410 mCallbacks.finishBroadcast();
411 }
412 }
413 /**
fredcbf072a72012-05-09 16:52:50 -0700414 * Inform BluetoothAdapter instances that Adapter service is down
415 */
416 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700417 if (!mConnection.isGetNameAddressOnly()) {
418 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
419 int n = mCallbacks.beginBroadcast();
420 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
421 for (int i=0; i <n;i++) {
422 try {
423 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
424 } catch (RemoteException e) {
425 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
426 }
427 }
428 mCallbacks.finishBroadcast();
429 }
430 }
fredc0f420372012-04-12 00:02:00 -0700431 public String getAddress() {
432 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
433 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700434
435 if (!checkIfCallerIsForegroundUser()) {
436 Log.w(TAG,"getAddress(): not allowed for non-active user");
437 return mAddress;
438 }
439
fredc116d1d462012-04-20 14:47:08 -0700440 synchronized(mConnection) {
441 if (mBluetooth != null) {
442 try {
443 return mBluetooth.getAddress();
444 } catch (RemoteException e) {
445 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
446 }
447 }
448 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700449 // mAddress is accessed from outside.
450 // It is alright without a lock. Here, bluetooth is off, no other thread is
451 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700452 return mAddress;
453 }
fredc649fe492012-04-19 01:07:18 -0700454
fredc0f420372012-04-12 00:02:00 -0700455 public String getName() {
456 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
457 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700458
459 if (!checkIfCallerIsForegroundUser()) {
460 Log.w(TAG,"getName(): not allowed for non-active user");
461 return mName;
462 }
463
fredc116d1d462012-04-20 14:47:08 -0700464 synchronized(mConnection) {
465 if (mBluetooth != null) {
466 try {
467 return mBluetooth.getName();
468 } catch (RemoteException e) {
469 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
470 }
471 }
472 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700473 // mName is accessed from outside.
474 // It alright without a lock. Here, bluetooth is off, no other thread is
475 // changing mName
fredc0f420372012-04-12 00:02:00 -0700476 return mName;
477 }
478
fredc0f420372012-04-12 00:02:00 -0700479 private class BluetoothServiceConnection implements ServiceConnection {
480
481 private boolean mGetNameAddressOnly;
482
483 public void setGetNameAddressOnly(boolean getOnly) {
484 mGetNameAddressOnly = getOnly;
485 }
486
487 public boolean isGetNameAddressOnly() {
488 return mGetNameAddressOnly;
489 }
490
491 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700492 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700493 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
494 msg.obj = service;
495 mHandler.sendMessage(msg);
496 }
497
498 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700499 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700500 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700501 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
502 mHandler.sendMessage(msg);
503 }
504 }
505
506 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
507
Zhihai Xu40874a02012-10-08 17:57:03 -0700508 private class BluetoothHandler extends Handler {
509 public BluetoothHandler(Looper looper) {
510 super(looper);
511 }
512
fredc0f420372012-04-12 00:02:00 -0700513 @Override
514 public void handleMessage(Message msg) {
515 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700516 switch (msg.what) {
517 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700518 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700519 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700520 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -0700521 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -0700522 if (DBG) Log.d(TAG, "Binding to service to get name and address");
523 mConnection.setGetNameAddressOnly(true);
524 //Start bind timeout and bind
525 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
526 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
527 Intent i = new Intent(IBluetooth.class.getName());
528 if (!mContext.bindService(i, mConnection,
Matthew Xiefca9d632012-10-04 12:25:28 -0700529 Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700530 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
531 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700532 } else {
533 mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700534 }
535 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700536 else {
537 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -0700538 saveMsg.arg1 = 0;
539 if (mBluetooth != null) {
540 mHandler.sendMessage(saveMsg);
541 } else {
542 // if enable is also called to bind the service
543 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
544 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
545 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700546 }
fredc0f420372012-04-12 00:02:00 -0700547 }
fredc649fe492012-04-19 01:07:18 -0700548 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700549 }
fredc0f420372012-04-12 00:02:00 -0700550 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700551 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700552 synchronized(mConnection) {
553 if (mBluetooth != null) {
554 String name = null;
555 String address = null;
556 try {
557 name = mBluetooth.getName();
558 address = mBluetooth.getAddress();
559 } catch (RemoteException re) {
560 Log.e(TAG,"",re);
561 }
fredc0f420372012-04-12 00:02:00 -0700562
Matthew Xiecdce0b92012-07-12 19:06:15 -0700563 if (name != null && address != null) {
564 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -0700565 if (mConnection.isGetNameAddressOnly()) {
566 unbindAndFinish();
567 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700568 } else {
569 if (msg.arg1 < MAX_SAVE_RETRIES) {
570 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
571 retryMsg.arg1= 1+msg.arg1;
572 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
573 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
574 } else {
575 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -0700576 if (mConnection.isGetNameAddressOnly()) {
577 unbindAndFinish();
578 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700579 }
fredc0f420372012-04-12 00:02:00 -0700580 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700581 } else {
582 // rebind service by Request GET NAME AND ADDRESS
583 // if service is unbinded by disable or
584 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
585 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
586 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -0700587 }
588 }
fredc649fe492012-04-19 01:07:18 -0700589 break;
fredc649fe492012-04-19 01:07:18 -0700590 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700591 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700592 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700593 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700594 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700595 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
596 mEnable = true;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700597 handleEnable(msg.arg1 == 1, msg.arg2 ==1);
fredc649fe492012-04-19 01:07:18 -0700598 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700599
fredc0f420372012-04-12 00:02:00 -0700600 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -0700601 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
602 if (mEnable && mBluetooth != null) {
603 waitForOnOff(true, false);
604 mEnable = false;
605 handleDisable(msg.arg1 == 1);
606 waitForOnOff(false, false);
607 } else {
608 mEnable = false;
609 handleDisable(msg.arg1 == 1);
610 }
fredc0f420372012-04-12 00:02:00 -0700611 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700612
fredc0f420372012-04-12 00:02:00 -0700613 case MESSAGE_REGISTER_ADAPTER:
614 {
615 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700616 boolean added = mCallbacks.register(callback);
617 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700618 }
619 break;
620 case MESSAGE_UNREGISTER_ADAPTER:
621 {
622 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700623 boolean removed = mCallbacks.unregister(callback);
624 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700625 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700626 }
fredc0f420372012-04-12 00:02:00 -0700627 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
628 {
629 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700630 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700631 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700632 }
fredc0f420372012-04-12 00:02:00 -0700633 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
634 {
635 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700636 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700637 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700638 }
fredc0f420372012-04-12 00:02:00 -0700639 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
640 {
fredc649fe492012-04-19 01:07:18 -0700641 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
642
fredc0f420372012-04-12 00:02:00 -0700643 //Remove timeout
644 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
645
646 IBinder service = (IBinder) msg.obj;
647 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700648 mBinding = false;
649 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700650
Matthew Xiecdce0b92012-07-12 19:06:15 -0700651 if (mConnection.isGetNameAddressOnly()) {
652 //Request GET NAME AND ADDRESS
653 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
654 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -0700655 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700656 }
fredc0f420372012-04-12 00:02:00 -0700657
Zhihai Xu40874a02012-10-08 17:57:03 -0700658 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700659 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700660 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700661 mBluetooth.registerCallback(mBluetoothCallback);
662 } catch (RemoteException re) {
663 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700664 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700665 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -0700666 sendBluetoothServiceUpCallback();
667
668 //Check if name and address is loaded if not get it first.
669 if (!isNameAndAddressSet()) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700670 try {
Zhihai Xu40874a02012-10-08 17:57:03 -0700671 storeNameAndAddress(mBluetooth.getName(),
672 mBluetooth.getAddress());
673 } catch (RemoteException e) {Log.e(TAG, "", e);};
Freda8c6df02012-07-11 10:25:23 -0700674 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700675
676 //Do enable request
677 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700678 if (mQuietEnable == false) {
679 if(!mBluetooth.enable()) {
680 Log.e(TAG,"IBluetooth.enable() returned false");
681 }
682 }
683 else
684 {
685 if(!mBluetooth.enableNoAutoConnect()) {
686 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
687 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700688 }
689 } catch (RemoteException e) {
690 Log.e(TAG,"Unable to call enable()",e);
691 }
Freda8c6df02012-07-11 10:25:23 -0700692 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700693
694 if (!mEnable) {
695 waitForOnOff(true, false);
696 handleDisable(false);
697 waitForOnOff(false, false);
698 }
fredc649fe492012-04-19 01:07:18 -0700699 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700700 }
fredc649fe492012-04-19 01:07:18 -0700701 case MESSAGE_TIMEOUT_BIND: {
702 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700703 synchronized(mConnection) {
704 mBinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700705 mEnable = false;
fredc0f420372012-04-12 00:02:00 -0700706 }
fredc649fe492012-04-19 01:07:18 -0700707 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700708 }
fredcbf072a72012-05-09 16:52:50 -0700709 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700710 {
fredcbf072a72012-05-09 16:52:50 -0700711 int prevState = msg.arg1;
712 int newState = msg.arg2;
713 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -0700714 mState = newState;
715 bluetoothStateChangeHandler(prevState, newState);
fredc649fe492012-04-19 01:07:18 -0700716 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700717 }
fredc0f420372012-04-12 00:02:00 -0700718 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
719 {
Zhihai Xu40874a02012-10-08 17:57:03 -0700720 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530721 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700722 // if service is unbinded already, do nothing and return
723 if (mBluetooth == null) return;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530724 mBluetooth = null;
725 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700726
727 if (mEnable) {
728 mEnable = false;
729 // Send a Bluetooth Restart message
730 Message restartMsg = mHandler.obtainMessage(
731 MESSAGE_RESTART_BLUETOOTH_SERVICE);
732 mHandler.sendMessageDelayed(restartMsg,
733 SERVICE_RESTART_TIME_MS);
734 }
735
736 if (!mConnection.isGetNameAddressOnly()) {
737 sendBluetoothServiceDownCallback();
738
739 // Send BT state broadcast to update
740 // the BT icon correctly
741 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
742 BluetoothAdapter.STATE_TURNING_OFF);
743 mState = BluetoothAdapter.STATE_OFF;
744 }
fredc649fe492012-04-19 01:07:18 -0700745 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700746 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530747 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
748 {
749 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
750 +" Restart IBluetooth service");
751 /* Enable without persisting the setting as
752 it doesnt change when IBluetooth
753 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -0700754 mEnable = true;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530755 handleEnable(false, mQuietEnable);
756 break;
757 }
758
fredc0f420372012-04-12 00:02:00 -0700759 case MESSAGE_TIMEOUT_UNBIND:
760 {
fredc649fe492012-04-19 01:07:18 -0700761 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700762 synchronized(mConnection) {
763 mUnbinding = false;
764 }
fredc649fe492012-04-19 01:07:18 -0700765 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700766 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700767
768 case MESSAGE_USER_SWITCHED:
769 {
770 if (DBG) {
771 Log.d(TAG, "MESSAGE_USER_SWITCHED");
772 }
773 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
774 /* disable and enable BT when detect a user switch */
775 if (mEnable && mBluetooth != null) {
776 synchronized (mConnection) {
777 if (mBluetooth != null) {
778 //Unregister callback object
779 try {
780 mBluetooth.unregisterCallback(mBluetoothCallback);
781 } catch (RemoteException re) {
782 Log.e(TAG, "Unable to unregister",re);
783 }
784 }
785 }
786 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
787
788 waitForOnOff(true, false);
789
790 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
791
792 // disable
793 handleDisable(false);
794
795 waitForOnOff(false, true);
796
797 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
798 BluetoothAdapter.STATE_OFF);
799 mState = BluetoothAdapter.STATE_OFF;
800 sendBluetoothServiceDownCallback();
801 synchronized (mConnection) {
802 if (mBluetooth != null) {
803 mBluetooth = null;
804 //Unbind
805 mContext.unbindService(mConnection);
806 }
807 }
808 SystemClock.sleep(100);
809
810 // enable
811 handleEnable(false, mQuietEnable);
812 } else if (mBinding || mBluetooth != null) {
813 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
814 userMsg.arg2 = 1 + msg.arg2;
815 // if user is switched when service is being binding
816 // delay sending MESSAGE_USER_SWITCHED
817 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
818 if (DBG) {
819 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
820 }
821 }
822 break;
823 }
fredc0f420372012-04-12 00:02:00 -0700824 }
825 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700826 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700827
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700828 private void handleEnable(boolean persist, boolean quietMode) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700829 if (persist) {
830 persistBluetoothSetting(true);
831 }
832
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700833 mQuietEnable = quietMode;
834
Matthew Xiecdce0b92012-07-12 19:06:15 -0700835 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700836 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700837 //Start bind timeout and bind
838 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
839 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
840 mConnection.setGetNameAddressOnly(false);
841 Intent i = new Intent(IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700842 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE,
Matthew Xiefca9d632012-10-04 12:25:28 -0700843 UserHandle.USER_CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700844 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
845 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700846 } else {
847 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700848 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700849 } else if (mBluetooth != null) {
850 if (mConnection.isGetNameAddressOnly()) {
851 // if GetNameAddressOnly is set, we can clear this flag,
852 // so the service won't be unbind
853 // after name and address are saved
854 mConnection.setGetNameAddressOnly(false);
855 //Register callback object
856 try {
857 mBluetooth.registerCallback(mBluetoothCallback);
858 } catch (RemoteException re) {
859 Log.e(TAG, "Unable to register BluetoothCallback",re);
860 }
861 //Inform BluetoothAdapter instances that service is up
862 sendBluetoothServiceUpCallback();
863 }
864
Matthew Xiecdce0b92012-07-12 19:06:15 -0700865 //Check if name and address is loaded if not get it first.
866 if (!isNameAndAddressSet()) {
867 try {
868 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
869 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
870 } catch (RemoteException e) {Log.e(TAG, "", e);};
871 }
872
873 //Enable bluetooth
874 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700875 if (!mQuietEnable) {
876 if(!mBluetooth.enable()) {
877 Log.e(TAG,"IBluetooth.enable() returned false");
878 }
879 }
880 else {
881 if(!mBluetooth.enableNoAutoConnect()) {
882 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
883 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700884 }
885 } catch (RemoteException e) {
886 Log.e(TAG,"Unable to call enable()",e);
887 }
888 }
889 }
890 }
891
892 private void handleDisable(boolean persist) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700893 if (persist) {
894 persistBluetoothSetting(false);
895 }
896
Matthew Xiecdce0b92012-07-12 19:06:15 -0700897 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700898 // don't need to disable if GetNameAddressOnly is set,
899 // service will be unbinded after Name and Address are saved
900 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700901 if (DBG) Log.d(TAG,"Sending off request.");
902
903 try {
904 if(!mBluetooth.disable()) {
905 Log.e(TAG,"IBluetooth.disable() returned false");
906 }
907 } catch (RemoteException e) {
908 Log.e(TAG,"Unable to call disable()",e);
909 }
910 }
911 }
912 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700913
914 private boolean checkIfCallerIsForegroundUser() {
915 int foregroundUser;
916 int callingUser = UserHandle.getCallingUserId();
917 long callingIdentity = Binder.clearCallingIdentity();
918 boolean valid = false;
919 try {
920 foregroundUser = ActivityManager.getCurrentUser();
921 valid = (callingUser == foregroundUser);
922 if (DBG) {
923 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
924 + " callingUser=" + callingUser
925 + " foregroundUser=" + foregroundUser);
926 }
927 } finally {
928 Binder.restoreCallingIdentity(callingIdentity);
929 }
930 return valid;
931 }
932
933 private boolean enableHelper() {
934 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
935 "Need BLUETOOTH ADMIN permission");
936 if (DBG) {
937 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
938 " mBinding = " + mBinding);
939 }
940
941 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
942 msg.arg1=1; //persist
943 msg.arg2=0; //No Quiet Mode
944 mHandler.sendMessage(msg);
945 return true;
946 }
947
948 private void bluetoothStateChangeHandler(int prevState, int newState) {
949 if (prevState != newState) {
950 //Notify all proxy objects first of adapter state change
951 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
952 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
953 sendBluetoothStateCallback(isUp);
954
955 //If Bluetooth is off, send service down event to proxy objects, and unbind
956 if (!isUp) {
957 //Only unbind with mEnable flag not set
958 //For race condition: disable and enable back-to-back
959 //Avoid unbind right after enable due to callback from disable
960 if ((!mEnable) && (mBluetooth != null)) {
961 sendBluetoothServiceDownCallback();
962 unbindAndFinish();
963 }
964 }
965 }
966
967 //Send broadcast message to everyone else
968 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
969 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
970 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
971 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
972 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
973 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
974 BLUETOOTH_PERM);
975 }
976 }
977
978 /**
979 * if on is true, wait for state become ON
980 * if off is true, wait for state become OFF
981 * if both on and off are false, wait for state not ON
982 */
983 private boolean waitForOnOff(boolean on, boolean off) {
984 int i = 0;
985 while (i < 10) {
986 synchronized(mConnection) {
987 try {
988 if (mBluetooth == null) break;
989 if (on) {
990 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
991 } else if (off) {
992 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
993 } else {
994 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
995 }
996 } catch (RemoteException e) {
997 Log.e(TAG, "getState()", e);
998 break;
999 }
1000 }
1001 if (on || off) {
1002 SystemClock.sleep(300);
1003 } else {
1004 SystemClock.sleep(50);
1005 }
1006 i++;
1007 }
1008 Log.e(TAG,"waitForOnOff time out");
1009 return false;
1010 }
fredc0f420372012-04-12 00:02:00 -07001011}