blob: 6ff33d74ac399221539fa13bf5d605bf04fb2eeb [file] [log] [blame]
fredc0f420372012-04-12 00:02:00 -07001/*
Zhihai Xufa0fd392012-10-23 17:31:56 -07002 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
fredc0f420372012-04-12 00:02:00 -070015 */
16
17package com.android.server;
18
Zhihai Xu40874a02012-10-08 17:57:03 -070019import android.app.ActivityManager;
fredc0f420372012-04-12 00:02:00 -070020import android.bluetooth.BluetoothAdapter;
21import android.bluetooth.IBluetooth;
fredcbf072a72012-05-09 16:52:50 -070022import android.bluetooth.IBluetoothCallback;
fredc0f420372012-04-12 00:02:00 -070023import android.bluetooth.IBluetoothManager;
24import android.bluetooth.IBluetoothManagerCallback;
25import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070026import android.content.BroadcastReceiver;
27import android.content.ComponentName;
28import android.content.ContentResolver;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.ServiceConnection;
Zhihai Xu40874a02012-10-08 17:57:03 -070033import android.os.Binder;
fredc0f420372012-04-12 00:02:00 -070034import android.os.Handler;
Zhihai Xu40874a02012-10-08 17:57:03 -070035import android.os.HandlerThread;
fredc0f420372012-04-12 00:02:00 -070036import android.os.IBinder;
Zhihai Xu40874a02012-10-08 17:57:03 -070037import android.os.Looper;
fredc0f420372012-04-12 00:02:00 -070038import android.os.Message;
Zhihai Xu40874a02012-10-08 17:57:03 -070039import android.os.Process;
fredcd6883532012-04-25 17:46:13 -070040import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070041import android.os.RemoteException;
Zhihai Xu40874a02012-10-08 17:57:03 -070042import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070043import android.os.UserHandle;
fredc0f420372012-04-12 00:02:00 -070044import android.provider.Settings;
45import android.util.Log;
fredc0f420372012-04-12 00:02:00 -070046import java.util.ArrayList;
Zhihai Xu40874a02012-10-08 17:57:03 -070047import java.util.List;
fredc0f420372012-04-12 00:02:00 -070048class BluetoothManagerService extends IBluetoothManager.Stub {
49 private static final String TAG = "BluetoothManagerService";
50 private static final boolean DBG = true;
51
fredc0f420372012-04-12 00:02:00 -070052 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
53 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070054 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
55 private static final String EXTRA_ACTION="action";
fredc0f420372012-04-12 00:02:00 -070056 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
57 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070058 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
59 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053060 //Maximum msec to wait for service restart
61 private static final int SERVICE_RESTART_TIME_MS = 200;
Zhihai Xu40874a02012-10-08 17:57:03 -070062 //Maximum msec to delay MESSAGE_USER_SWITCHED
63 private static final int USER_SWITCHED_TIME_MS = 200;
fredc0f420372012-04-12 00:02:00 -070064
65 private static final int MESSAGE_ENABLE = 1;
66 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070067 private static final int MESSAGE_REGISTER_ADAPTER = 20;
68 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
69 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
70 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
71 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
72 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053073 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070074 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070075 private static final int MESSAGE_TIMEOUT_BIND =100;
76 private static final int MESSAGE_TIMEOUT_UNBIND =101;
77 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
78 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
Zhihai Xu40874a02012-10-08 17:57:03 -070079 private static final int MESSAGE_USER_SWITCHED = 300;
fredc0f420372012-04-12 00:02:00 -070080 private static final int MAX_SAVE_RETRIES=3;
81
82 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070083
84 // Locks are not provided for mName and mAddress.
85 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070086 private String mAddress;
87 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -070088 private final ContentResolver mContentResolver;
89 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
90 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070091 private IBluetooth mBluetooth;
92 private boolean mBinding;
93 private boolean mUnbinding;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -070094 private boolean mQuietEnable = false;
Zhihai Xu40874a02012-10-08 17:57:03 -070095 private boolean mEnable;
96 private int mState;
97 private HandlerThread mThread;
98 private final BluetoothHandler mHandler;
fredc0f420372012-04-12 00:02:00 -070099
fredc649fe492012-04-19 01:07:18 -0700100 private void registerForAirplaneMode(IntentFilter filter) {
101 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700102 final String airplaneModeRadios = Settings.Global.getString(resolver,
103 Settings.Global.AIRPLANE_MODE_RADIOS);
104 final String toggleableRadios = Settings.Global.getString(resolver,
105 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700106 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700107 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700108 if (mIsAirplaneSensitive) {
109 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
110 }
111 }
112
fredcbf072a72012-05-09 16:52:50 -0700113 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
114 @Override
115 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
116 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
117 mHandler.sendMessage(msg);
118 }
119 };
120
121 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700122 @Override
123 public void onReceive(Context context, Intent intent) {
124 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700125 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700126 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700127 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700128 if (newName != null) {
129 storeNameAndAddress(newName, null);
130 }
fredc649fe492012-04-19 01:07:18 -0700131 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
132 if (isAirplaneModeOn()) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700133 // disable without persisting the setting
134 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE,
135 0, 0));
136 } else if (isBluetoothPersistedStateOn()) {
137 // enable without persisting the setting
138 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
139 0, 0));
fredc649fe492012-04-19 01:07:18 -0700140 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700141 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
142 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
143 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
fredc0f420372012-04-12 00:02:00 -0700144 }
145 }
146 };
147
148 BluetoothManagerService(Context context) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700149 mThread = new HandlerThread("BluetoothManager");
150 mThread.start();
151 mHandler = new BluetoothHandler(mThread.getLooper());
152
fredc0f420372012-04-12 00:02:00 -0700153 mContext = context;
154 mBluetooth = null;
155 mBinding = false;
156 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700157 mEnable = false;
158 mState = BluetoothAdapter.STATE_OFF;
fredc0f420372012-04-12 00:02:00 -0700159 mAddress = null;
160 mName = null;
161 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700162 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
163 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Matthew Xie6fde3092012-07-11 17:10:07 -0700164 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
165 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700166 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700167 registerForAirplaneMode(filter);
168 mContext.registerReceiver(mReceiver, filter);
fredc649fe492012-04-19 01:07:18 -0700169 boolean airplaneModeOn = isAirplaneModeOn();
170 boolean bluetoothOn = isBluetoothPersistedStateOn();
fredc0f420372012-04-12 00:02:00 -0700171 loadStoredNameAndAddress();
fredc649fe492012-04-19 01:07:18 -0700172 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
Andre Eisenbacha732ffd2012-05-02 00:39:24 -0700173 if (bluetoothOn) {
fredc0f420372012-04-12 00:02:00 -0700174 //Enable
fredc649fe492012-04-19 01:07:18 -0700175 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
Zhihai Xu40874a02012-10-08 17:57:03 -0700176 enableHelper();
Freda8c6df02012-07-11 10:25:23 -0700177 } else if (!isNameAndAddressSet()) {
fredc649fe492012-04-19 01:07:18 -0700178 //Sync the Bluetooth name and address from the Bluetooth Adapter
179 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
fredc0f420372012-04-12 00:02:00 -0700180 getNameAndAddress();
181 }
182 }
183
fredc649fe492012-04-19 01:07:18 -0700184 /**
185 * Returns true if airplane mode is currently on
186 */
187 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700188 return Settings.Global.getInt(mContext.getContentResolver(),
189 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700190 }
191
192 /**
193 * Returns true if the Bluetooth saved state is "on"
194 */
195 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700196 return Settings.Global.getInt(mContentResolver,
197 Settings.Global.BLUETOOTH_ON, 0) ==1;
fredc649fe492012-04-19 01:07:18 -0700198 }
199
200 /**
201 * Save the Bluetooth on/off state
202 *
203 */
204 private void persistBluetoothSetting(boolean setOn) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700205 Settings.Global.putInt(mContext.getContentResolver(),
206 Settings.Global.BLUETOOTH_ON,
fredc649fe492012-04-19 01:07:18 -0700207 setOn ? 1 : 0);
208 }
209
210 /**
211 * Returns true if the Bluetooth Adapter's name and address is
212 * locally cached
213 * @return
214 */
fredc0f420372012-04-12 00:02:00 -0700215 private boolean isNameAndAddressSet() {
216 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
217 }
218
fredc649fe492012-04-19 01:07:18 -0700219 /**
220 * Retrieve the Bluetooth Adapter's name and address and save it in
221 * in the local cache
222 */
fredc0f420372012-04-12 00:02:00 -0700223 private void loadStoredNameAndAddress() {
224 if (DBG) Log.d(TAG, "Loading stored name and address");
225 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
226 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
227 if (mName == null || mAddress == null) {
228 if (DBG) Log.d(TAG, "Name or address not cached...");
229 }
230 }
231
fredc649fe492012-04-19 01:07:18 -0700232 /**
233 * Save the Bluetooth name and address in the persistent store.
234 * Only non-null values will be saved.
235 * @param name
236 * @param address
237 */
fredc0f420372012-04-12 00:02:00 -0700238 private void storeNameAndAddress(String name, String address) {
239 if (name != null) {
240 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700241 mName = name;
fredc649fe492012-04-19 01:07:18 -0700242 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
243 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700244 }
245
246 if (address != null) {
247 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700248 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700249 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
250 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700251 }
252 }
253
254 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
fredc0f420372012-04-12 00:02:00 -0700255 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
256 msg.obj = callback;
257 mHandler.sendMessage(msg);
258 synchronized(mConnection) {
259 return mBluetooth;
260 }
261 }
262
263 public void unregisterAdapter(IBluetoothManagerCallback callback) {
264 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
265 "Need BLUETOOTH permission");
266 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
267 msg.obj = callback;
268 mHandler.sendMessage(msg);
269 }
270
271 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
272 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
273 "Need BLUETOOTH permission");
274 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
275 msg.obj = callback;
276 mHandler.sendMessage(msg);
277 }
278
279 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
280 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
281 "Need BLUETOOTH permission");
282 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
283 msg.obj = callback;
284 mHandler.sendMessage(msg);
285 }
286
287 public boolean isEnabled() {
Zhihai Xu40874a02012-10-08 17:57:03 -0700288 if (!checkIfCallerIsForegroundUser()) {
289 Log.w(TAG,"isEnabled(): not allowed for non-active user");
290 return false;
291 }
292
fredc0f420372012-04-12 00:02:00 -0700293 synchronized(mConnection) {
294 try {
295 return (mBluetooth != null && mBluetooth.isEnabled());
296 } catch (RemoteException e) {
297 Log.e(TAG, "isEnabled()", e);
298 }
299 }
300 return false;
301 }
302
303 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700304 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700305 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
306 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700307 }
fredc0f420372012-04-12 00:02:00 -0700308 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
309 mHandler.sendMessage(msg);
310 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700311 public boolean enableNoAutoConnect()
312 {
313 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
314 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700315
316 if (!checkIfCallerIsForegroundUser()) {
317 Log.w(TAG,"enableNoAutoConnect(): not allowed for non-active user");
318 return false;
319 }
320
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700321 if (DBG) {
322 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
323 " mBinding = " + mBinding);
324 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700325 if (Binder.getCallingUid() != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700326 throw new SecurityException("no permission to enable Bluetooth quietly");
327 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700328 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
329 msg.arg1=0; //No persist
330 msg.arg2=1; //Quiet mode
331 mHandler.sendMessage(msg);
332 return true;
333
334 }
fredc0f420372012-04-12 00:02:00 -0700335 public boolean enable() {
Zhihai Xu40874a02012-10-08 17:57:03 -0700336 if (!checkIfCallerIsForegroundUser()) {
337 Log.w(TAG,"enable(): not allowed for non-active user");
338 return false;
fredcf2458862012-04-16 15:18:27 -0700339 }
340
Zhihai Xu40874a02012-10-08 17:57:03 -0700341 return enableHelper();
fredc0f420372012-04-12 00:02:00 -0700342 }
343
344 public boolean disable(boolean persist) {
345 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
346 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700347
348 if (!checkIfCallerIsForegroundUser()) {
349 Log.w(TAG,"disable(): not allowed for non-active user");
350 return false;
351 }
352
fredcf2458862012-04-16 15:18:27 -0700353 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700354 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
355 " mBinding = " + mBinding);
356 }
fredcf2458862012-04-16 15:18:27 -0700357
fredc0f420372012-04-12 00:02:00 -0700358 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700359 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700360 mHandler.sendMessage(msg);
361 return true;
362 }
363
fredc649fe492012-04-19 01:07:18 -0700364 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700365 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700366 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
367 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700368 }
369
fredc0f420372012-04-12 00:02:00 -0700370 synchronized (mConnection) {
371 if (mUnbinding) return;
372 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700373 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700374 if (!mConnection.isGetNameAddressOnly()) {
375 //Unregister callback object
376 try {
377 mBluetooth.unregisterCallback(mBluetoothCallback);
378 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700379 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700380 }
381 }
fredc0f420372012-04-12 00:02:00 -0700382 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700383 mBluetooth = null;
384 //Unbind
fredc0f420372012-04-12 00:02:00 -0700385 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700386 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700387 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700388 } else {
389 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700390 }
391 }
392 }
393
fredcbf072a72012-05-09 16:52:50 -0700394 private void sendBluetoothStateCallback(boolean isUp) {
395 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700396 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700397 for (int i=0; i <n;i++) {
398 try {
399 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
400 } catch (RemoteException e) {
401 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
402 }
403 }
404 mStateChangeCallbacks.finishBroadcast();
405 }
406
407 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700408 * Inform BluetoothAdapter instances that Adapter service is up
409 */
410 private void sendBluetoothServiceUpCallback() {
411 if (!mConnection.isGetNameAddressOnly()) {
412 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
413 int n = mCallbacks.beginBroadcast();
414 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
415 for (int i=0; i <n;i++) {
416 try {
417 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
418 } catch (RemoteException e) {
419 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
420 }
421 }
422 mCallbacks.finishBroadcast();
423 }
424 }
425 /**
fredcbf072a72012-05-09 16:52:50 -0700426 * Inform BluetoothAdapter instances that Adapter service is down
427 */
428 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700429 if (!mConnection.isGetNameAddressOnly()) {
430 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
431 int n = mCallbacks.beginBroadcast();
432 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
433 for (int i=0; i <n;i++) {
434 try {
435 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
436 } catch (RemoteException e) {
437 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
438 }
439 }
440 mCallbacks.finishBroadcast();
441 }
442 }
fredc0f420372012-04-12 00:02:00 -0700443 public String getAddress() {
444 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
445 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700446
447 if (!checkIfCallerIsForegroundUser()) {
448 Log.w(TAG,"getAddress(): not allowed for non-active user");
449 return mAddress;
450 }
451
fredc116d1d462012-04-20 14:47:08 -0700452 synchronized(mConnection) {
453 if (mBluetooth != null) {
454 try {
455 return mBluetooth.getAddress();
456 } catch (RemoteException e) {
457 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
458 }
459 }
460 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700461 // mAddress is accessed from outside.
462 // It is alright without a lock. Here, bluetooth is off, no other thread is
463 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700464 return mAddress;
465 }
fredc649fe492012-04-19 01:07:18 -0700466
fredc0f420372012-04-12 00:02:00 -0700467 public String getName() {
468 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
469 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700470
471 if (!checkIfCallerIsForegroundUser()) {
472 Log.w(TAG,"getName(): not allowed for non-active user");
473 return mName;
474 }
475
fredc116d1d462012-04-20 14:47:08 -0700476 synchronized(mConnection) {
477 if (mBluetooth != null) {
478 try {
479 return mBluetooth.getName();
480 } catch (RemoteException e) {
481 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
482 }
483 }
484 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700485 // mName is accessed from outside.
486 // It alright without a lock. Here, bluetooth is off, no other thread is
487 // changing mName
fredc0f420372012-04-12 00:02:00 -0700488 return mName;
489 }
490
fredc0f420372012-04-12 00:02:00 -0700491 private class BluetoothServiceConnection implements ServiceConnection {
492
493 private boolean mGetNameAddressOnly;
494
495 public void setGetNameAddressOnly(boolean getOnly) {
496 mGetNameAddressOnly = getOnly;
497 }
498
499 public boolean isGetNameAddressOnly() {
500 return mGetNameAddressOnly;
501 }
502
503 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700504 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700505 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
506 msg.obj = service;
507 mHandler.sendMessage(msg);
508 }
509
510 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700511 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700512 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700513 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
514 mHandler.sendMessage(msg);
515 }
516 }
517
518 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
519
Zhihai Xu40874a02012-10-08 17:57:03 -0700520 private class BluetoothHandler extends Handler {
521 public BluetoothHandler(Looper looper) {
522 super(looper);
523 }
524
fredc0f420372012-04-12 00:02:00 -0700525 @Override
526 public void handleMessage(Message msg) {
527 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700528 switch (msg.what) {
529 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700530 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700531 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700532 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -0700533 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -0700534 if (DBG) Log.d(TAG, "Binding to service to get name and address");
535 mConnection.setGetNameAddressOnly(true);
536 //Start bind timeout and bind
537 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
538 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
539 Intent i = new Intent(IBluetooth.class.getName());
540 if (!mContext.bindService(i, mConnection,
Matthew Xiefca9d632012-10-04 12:25:28 -0700541 Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700542 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
543 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700544 } else {
545 mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700546 }
547 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700548 else {
549 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -0700550 saveMsg.arg1 = 0;
551 if (mBluetooth != null) {
552 mHandler.sendMessage(saveMsg);
553 } else {
554 // if enable is also called to bind the service
555 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
556 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
557 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700558 }
fredc0f420372012-04-12 00:02:00 -0700559 }
fredc649fe492012-04-19 01:07:18 -0700560 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700561 }
fredc0f420372012-04-12 00:02:00 -0700562 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700563 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700564 synchronized(mConnection) {
565 if (mBluetooth != null) {
566 String name = null;
567 String address = null;
568 try {
569 name = mBluetooth.getName();
570 address = mBluetooth.getAddress();
571 } catch (RemoteException re) {
572 Log.e(TAG,"",re);
573 }
fredc0f420372012-04-12 00:02:00 -0700574
Matthew Xiecdce0b92012-07-12 19:06:15 -0700575 if (name != null && address != null) {
576 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -0700577 if (mConnection.isGetNameAddressOnly()) {
578 unbindAndFinish();
579 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700580 } else {
581 if (msg.arg1 < MAX_SAVE_RETRIES) {
582 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
583 retryMsg.arg1= 1+msg.arg1;
584 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
585 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
586 } else {
587 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -0700588 if (mConnection.isGetNameAddressOnly()) {
589 unbindAndFinish();
590 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700591 }
fredc0f420372012-04-12 00:02:00 -0700592 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700593 } else {
594 // rebind service by Request GET NAME AND ADDRESS
595 // if service is unbinded by disable or
596 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
597 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
598 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -0700599 }
600 }
fredc649fe492012-04-19 01:07:18 -0700601 break;
fredc649fe492012-04-19 01:07:18 -0700602 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700603 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700604 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700605 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700606 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700607 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
608 mEnable = true;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700609 handleEnable(msg.arg1 == 1, msg.arg2 ==1);
fredc649fe492012-04-19 01:07:18 -0700610 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700611
fredc0f420372012-04-12 00:02:00 -0700612 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -0700613 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
614 if (mEnable && mBluetooth != null) {
615 waitForOnOff(true, false);
616 mEnable = false;
617 handleDisable(msg.arg1 == 1);
618 waitForOnOff(false, false);
619 } else {
620 mEnable = false;
621 handleDisable(msg.arg1 == 1);
622 }
fredc0f420372012-04-12 00:02:00 -0700623 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700624
fredc0f420372012-04-12 00:02:00 -0700625 case MESSAGE_REGISTER_ADAPTER:
626 {
627 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700628 boolean added = mCallbacks.register(callback);
629 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700630 }
631 break;
632 case MESSAGE_UNREGISTER_ADAPTER:
633 {
634 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700635 boolean removed = mCallbacks.unregister(callback);
636 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
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_REGISTER_STATE_CHANGE_CALLBACK:
640 {
641 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700642 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700643 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700644 }
fredc0f420372012-04-12 00:02:00 -0700645 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
646 {
647 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700648 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700649 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700650 }
fredc0f420372012-04-12 00:02:00 -0700651 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
652 {
fredc649fe492012-04-19 01:07:18 -0700653 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
654
fredc0f420372012-04-12 00:02:00 -0700655 //Remove timeout
656 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
657
658 IBinder service = (IBinder) msg.obj;
659 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700660 mBinding = false;
661 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700662
Matthew Xiecdce0b92012-07-12 19:06:15 -0700663 if (mConnection.isGetNameAddressOnly()) {
664 //Request GET NAME AND ADDRESS
665 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
666 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -0700667 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700668 }
fredc0f420372012-04-12 00:02:00 -0700669
Zhihai Xu40874a02012-10-08 17:57:03 -0700670 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700671 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700672 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700673 mBluetooth.registerCallback(mBluetoothCallback);
674 } catch (RemoteException re) {
675 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700676 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700677 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -0700678 sendBluetoothServiceUpCallback();
679
680 //Check if name and address is loaded if not get it first.
681 if (!isNameAndAddressSet()) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700682 try {
Zhihai Xu40874a02012-10-08 17:57:03 -0700683 storeNameAndAddress(mBluetooth.getName(),
684 mBluetooth.getAddress());
685 } catch (RemoteException e) {Log.e(TAG, "", e);};
Freda8c6df02012-07-11 10:25:23 -0700686 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700687
688 //Do enable request
689 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700690 if (mQuietEnable == false) {
691 if(!mBluetooth.enable()) {
692 Log.e(TAG,"IBluetooth.enable() returned false");
693 }
694 }
695 else
696 {
697 if(!mBluetooth.enableNoAutoConnect()) {
698 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
699 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700700 }
701 } catch (RemoteException e) {
702 Log.e(TAG,"Unable to call enable()",e);
703 }
Freda8c6df02012-07-11 10:25:23 -0700704 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700705
706 if (!mEnable) {
707 waitForOnOff(true, false);
708 handleDisable(false);
709 waitForOnOff(false, false);
710 }
fredc649fe492012-04-19 01:07:18 -0700711 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700712 }
fredc649fe492012-04-19 01:07:18 -0700713 case MESSAGE_TIMEOUT_BIND: {
714 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700715 synchronized(mConnection) {
716 mBinding = false;
717 }
fredc649fe492012-04-19 01:07:18 -0700718 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700719 }
fredcbf072a72012-05-09 16:52:50 -0700720 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700721 {
fredcbf072a72012-05-09 16:52:50 -0700722 int prevState = msg.arg1;
723 int newState = msg.arg2;
724 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -0700725 mState = newState;
726 bluetoothStateChangeHandler(prevState, newState);
fredc649fe492012-04-19 01:07:18 -0700727 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700728 }
fredc0f420372012-04-12 00:02:00 -0700729 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
730 {
Zhihai Xu40874a02012-10-08 17:57:03 -0700731 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530732 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700733 // if service is unbinded already, do nothing and return
734 if (mBluetooth == null) return;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530735 mBluetooth = null;
736 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700737
738 if (mEnable) {
739 mEnable = false;
740 // Send a Bluetooth Restart message
741 Message restartMsg = mHandler.obtainMessage(
742 MESSAGE_RESTART_BLUETOOTH_SERVICE);
743 mHandler.sendMessageDelayed(restartMsg,
744 SERVICE_RESTART_TIME_MS);
745 }
746
747 if (!mConnection.isGetNameAddressOnly()) {
748 sendBluetoothServiceDownCallback();
749
750 // Send BT state broadcast to update
751 // the BT icon correctly
752 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
753 BluetoothAdapter.STATE_TURNING_OFF);
754 mState = BluetoothAdapter.STATE_OFF;
755 }
fredc649fe492012-04-19 01:07:18 -0700756 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700757 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530758 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
759 {
760 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
761 +" Restart IBluetooth service");
762 /* Enable without persisting the setting as
763 it doesnt change when IBluetooth
764 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -0700765 mEnable = true;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530766 handleEnable(false, mQuietEnable);
767 break;
768 }
769
fredc0f420372012-04-12 00:02:00 -0700770 case MESSAGE_TIMEOUT_UNBIND:
771 {
fredc649fe492012-04-19 01:07:18 -0700772 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700773 synchronized(mConnection) {
774 mUnbinding = false;
775 }
fredc649fe492012-04-19 01:07:18 -0700776 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700777 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700778
779 case MESSAGE_USER_SWITCHED:
780 {
781 if (DBG) {
782 Log.d(TAG, "MESSAGE_USER_SWITCHED");
783 }
784 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
785 /* disable and enable BT when detect a user switch */
786 if (mEnable && mBluetooth != null) {
787 synchronized (mConnection) {
788 if (mBluetooth != null) {
789 //Unregister callback object
790 try {
791 mBluetooth.unregisterCallback(mBluetoothCallback);
792 } catch (RemoteException re) {
793 Log.e(TAG, "Unable to unregister",re);
794 }
795 }
796 }
797 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
798
799 waitForOnOff(true, false);
800
801 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
802
803 // disable
804 handleDisable(false);
805
806 waitForOnOff(false, true);
807
808 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
809 BluetoothAdapter.STATE_OFF);
810 mState = BluetoothAdapter.STATE_OFF;
811 sendBluetoothServiceDownCallback();
812 synchronized (mConnection) {
813 if (mBluetooth != null) {
814 mBluetooth = null;
815 //Unbind
816 mContext.unbindService(mConnection);
817 }
818 }
819 SystemClock.sleep(100);
820
821 // enable
822 handleEnable(false, mQuietEnable);
823 } else if (mBinding || mBluetooth != null) {
824 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
825 userMsg.arg2 = 1 + msg.arg2;
826 // if user is switched when service is being binding
827 // delay sending MESSAGE_USER_SWITCHED
828 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
829 if (DBG) {
830 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
831 }
832 }
833 break;
834 }
fredc0f420372012-04-12 00:02:00 -0700835 }
836 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700837 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700838
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700839 private void handleEnable(boolean persist, boolean quietMode) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700840 if (persist) {
841 persistBluetoothSetting(true);
842 }
843
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700844 mQuietEnable = quietMode;
845
Matthew Xiecdce0b92012-07-12 19:06:15 -0700846 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700847 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700848 //Start bind timeout and bind
849 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
850 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
851 mConnection.setGetNameAddressOnly(false);
852 Intent i = new Intent(IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700853 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE,
Matthew Xiefca9d632012-10-04 12:25:28 -0700854 UserHandle.USER_CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700855 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
856 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700857 } else {
858 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700859 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700860 } else if (mBluetooth != null) {
861 if (mConnection.isGetNameAddressOnly()) {
862 // if GetNameAddressOnly is set, we can clear this flag,
863 // so the service won't be unbind
864 // after name and address are saved
865 mConnection.setGetNameAddressOnly(false);
866 //Register callback object
867 try {
868 mBluetooth.registerCallback(mBluetoothCallback);
869 } catch (RemoteException re) {
870 Log.e(TAG, "Unable to register BluetoothCallback",re);
871 }
872 //Inform BluetoothAdapter instances that service is up
873 sendBluetoothServiceUpCallback();
874 }
875
Matthew Xiecdce0b92012-07-12 19:06:15 -0700876 //Check if name and address is loaded if not get it first.
877 if (!isNameAndAddressSet()) {
878 try {
879 if (DBG) Log.d(TAG,"Getting and storing Bluetooth name and address prior to enable.");
880 storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
881 } catch (RemoteException e) {Log.e(TAG, "", e);};
882 }
883
884 //Enable bluetooth
885 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700886 if (!mQuietEnable) {
887 if(!mBluetooth.enable()) {
888 Log.e(TAG,"IBluetooth.enable() returned false");
889 }
890 }
891 else {
892 if(!mBluetooth.enableNoAutoConnect()) {
893 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
894 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700895 }
896 } catch (RemoteException e) {
897 Log.e(TAG,"Unable to call enable()",e);
898 }
899 }
900 }
901 }
902
903 private void handleDisable(boolean persist) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700904 if (persist) {
905 persistBluetoothSetting(false);
906 }
907
Matthew Xiecdce0b92012-07-12 19:06:15 -0700908 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700909 // don't need to disable if GetNameAddressOnly is set,
910 // service will be unbinded after Name and Address are saved
911 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700912 if (DBG) Log.d(TAG,"Sending off request.");
913
914 try {
915 if(!mBluetooth.disable()) {
916 Log.e(TAG,"IBluetooth.disable() returned false");
917 }
918 } catch (RemoteException e) {
919 Log.e(TAG,"Unable to call disable()",e);
920 }
921 }
922 }
923 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700924
925 private boolean checkIfCallerIsForegroundUser() {
926 int foregroundUser;
927 int callingUser = UserHandle.getCallingUserId();
928 long callingIdentity = Binder.clearCallingIdentity();
929 boolean valid = false;
930 try {
931 foregroundUser = ActivityManager.getCurrentUser();
932 valid = (callingUser == foregroundUser);
933 if (DBG) {
934 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
935 + " callingUser=" + callingUser
936 + " foregroundUser=" + foregroundUser);
937 }
938 } finally {
939 Binder.restoreCallingIdentity(callingIdentity);
940 }
941 return valid;
942 }
943
944 private boolean enableHelper() {
945 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
946 "Need BLUETOOTH ADMIN permission");
947 if (DBG) {
948 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
949 " mBinding = " + mBinding);
950 }
951
952 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
953 msg.arg1=1; //persist
954 msg.arg2=0; //No Quiet Mode
955 mHandler.sendMessage(msg);
956 return true;
957 }
958
959 private void bluetoothStateChangeHandler(int prevState, int newState) {
960 if (prevState != newState) {
961 //Notify all proxy objects first of adapter state change
962 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
963 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
964 sendBluetoothStateCallback(isUp);
965
966 //If Bluetooth is off, send service down event to proxy objects, and unbind
967 if (!isUp) {
968 //Only unbind with mEnable flag not set
969 //For race condition: disable and enable back-to-back
970 //Avoid unbind right after enable due to callback from disable
971 if ((!mEnable) && (mBluetooth != null)) {
972 sendBluetoothServiceDownCallback();
973 unbindAndFinish();
974 }
975 }
976 }
977
978 //Send broadcast message to everyone else
979 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
980 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
981 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
982 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
983 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
984 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
985 BLUETOOTH_PERM);
986 }
987 }
988
989 /**
990 * if on is true, wait for state become ON
991 * if off is true, wait for state become OFF
992 * if both on and off are false, wait for state not ON
993 */
994 private boolean waitForOnOff(boolean on, boolean off) {
995 int i = 0;
996 while (i < 10) {
997 synchronized(mConnection) {
998 try {
999 if (mBluetooth == null) break;
1000 if (on) {
1001 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1002 } else if (off) {
1003 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
1004 } else {
1005 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
1006 }
1007 } catch (RemoteException e) {
1008 Log.e(TAG, "getState()", e);
1009 break;
1010 }
1011 }
1012 if (on || off) {
1013 SystemClock.sleep(300);
1014 } else {
1015 SystemClock.sleep(50);
1016 }
1017 i++;
1018 }
1019 Log.e(TAG,"waitForOnOff time out");
1020 return false;
1021 }
fredc0f420372012-04-12 00:02:00 -07001022}