blob: 924b9df3d3e11396d894cb14d8d058020d8c7d33 [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 -070046class BluetoothManagerService extends IBluetoothManager.Stub {
47 private static final String TAG = "BluetoothManagerService";
48 private static final boolean DBG = true;
49
fredc0f420372012-04-12 00:02:00 -070050 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
51 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070052 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
53 private static final String EXTRA_ACTION="action";
Zhihai Xud31c3222012-10-31 16:08:57 -070054 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
fredc0f420372012-04-12 00:02:00 -070055 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
56 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070057 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
58 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053059 //Maximum msec to wait for service restart
60 private static final int SERVICE_RESTART_TIME_MS = 200;
Zhihai Xu40874a02012-10-08 17:57:03 -070061 //Maximum msec to delay MESSAGE_USER_SWITCHED
62 private static final int USER_SWITCHED_TIME_MS = 200;
fredc0f420372012-04-12 00:02:00 -070063
64 private static final int MESSAGE_ENABLE = 1;
65 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070066 private static final int MESSAGE_REGISTER_ADAPTER = 20;
67 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
68 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
69 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
70 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
71 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053072 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070073 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070074 private static final int MESSAGE_TIMEOUT_BIND =100;
75 private static final int MESSAGE_TIMEOUT_UNBIND =101;
76 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
77 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
Zhihai Xu40874a02012-10-08 17:57:03 -070078 private static final int MESSAGE_USER_SWITCHED = 300;
fredc0f420372012-04-12 00:02:00 -070079 private static final int MAX_SAVE_RETRIES=3;
Zhihai Xu401202b2012-12-03 11:36:21 -080080 // Bluetooth persisted setting is off
81 private static final int BLUETOOTH_OFF=0;
82 // Bluetooth persisted setting is on
83 // and Airplane mode won't affect Bluetooth state at start up
84 private static final int BLUETOOTH_ON_BLUETOOTH=1;
85 // Bluetooth persisted setting is on
86 // but Airplane mode will affect Bluetooth state at start up
87 // and Airplane mode will have higher priority.
88 private static final int BLUETOOTH_ON_AIRPLANE=2;
fredc0f420372012-04-12 00:02:00 -070089
90 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070091
92 // Locks are not provided for mName and mAddress.
93 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070094 private String mAddress;
95 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -070096 private final ContentResolver mContentResolver;
97 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
98 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070099 private IBluetooth mBluetooth;
100 private boolean mBinding;
101 private boolean mUnbinding;
Zhihai Xu401202b2012-12-03 11:36:21 -0800102 // used inside handler thread
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700103 private boolean mQuietEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800104 // configuarion from external IBinder call which is used to
105 // synchronize with broadcast receiver.
106 private boolean mQuietEnableExternal;
107 // configuarion from external IBinder call which is used to
108 // synchronize with broadcast receiver.
109 private boolean mEnableExternal;
110 // used inside handler thread
Zhihai Xu40874a02012-10-08 17:57:03 -0700111 private boolean mEnable;
112 private int mState;
113 private HandlerThread mThread;
114 private final BluetoothHandler mHandler;
fredc0f420372012-04-12 00:02:00 -0700115
fredc649fe492012-04-19 01:07:18 -0700116 private void registerForAirplaneMode(IntentFilter filter) {
117 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700118 final String airplaneModeRadios = Settings.Global.getString(resolver,
119 Settings.Global.AIRPLANE_MODE_RADIOS);
120 final String toggleableRadios = Settings.Global.getString(resolver,
121 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700122 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700123 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700124 if (mIsAirplaneSensitive) {
125 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
126 }
127 }
128
fredcbf072a72012-05-09 16:52:50 -0700129 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
130 @Override
131 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
132 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
133 mHandler.sendMessage(msg);
134 }
135 };
136
137 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700138 @Override
139 public void onReceive(Context context, Intent intent) {
140 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700141 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700142 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700143 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700144 if (newName != null) {
145 storeNameAndAddress(newName, null);
146 }
fredc649fe492012-04-19 01:07:18 -0700147 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
Zhihai Xu401202b2012-12-03 11:36:21 -0800148 synchronized(mReceiver) {
149 if (isBluetoothPersistedStateOn()) {
150 if (isAirplaneModeOn()) {
151 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
152 } else {
153 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
154 }
155 }
156 if (isAirplaneModeOn()) {
157 // disable without persisting the setting
158 sendDisableMsg();
159 } else if (mEnableExternal) {
160 // enable without persisting the setting
161 sendEnableMsg(mQuietEnableExternal);
162 }
fredc649fe492012-04-19 01:07:18 -0700163 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700164 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
165 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
166 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Zhihai Xu401202b2012-12-03 11:36:21 -0800167 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
168 synchronized(mReceiver) {
169 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
170 //Enable
171 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
172 sendEnableMsg(mQuietEnableExternal);
173 }
174 }
175
176 if (!isNameAndAddressSet()) {
177 //Sync the Bluetooth name and address from the Bluetooth Adapter
178 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
179 getNameAndAddress();
180 }
fredc0f420372012-04-12 00:02:00 -0700181 }
182 }
183 };
184
185 BluetoothManagerService(Context context) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700186 mThread = new HandlerThread("BluetoothManager");
187 mThread.start();
188 mHandler = new BluetoothHandler(mThread.getLooper());
189
fredc0f420372012-04-12 00:02:00 -0700190 mContext = context;
191 mBluetooth = null;
192 mBinding = false;
193 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700194 mEnable = false;
195 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu401202b2012-12-03 11:36:21 -0800196 mQuietEnableExternal = false;
197 mEnableExternal = false;
fredc0f420372012-04-12 00:02:00 -0700198 mAddress = null;
199 mName = null;
200 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700201 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
202 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Zhihai Xu401202b2012-12-03 11:36:21 -0800203 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700204 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700205 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700206 registerForAirplaneMode(filter);
207 mContext.registerReceiver(mReceiver, filter);
fredc0f420372012-04-12 00:02:00 -0700208 loadStoredNameAndAddress();
Zhihai Xu401202b2012-12-03 11:36:21 -0800209 if (isBluetoothPersistedStateOn()) {
210 mEnableExternal = true;
fredc0f420372012-04-12 00:02:00 -0700211 }
212 }
213
fredc649fe492012-04-19 01:07:18 -0700214 /**
215 * Returns true if airplane mode is currently on
216 */
217 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700218 return Settings.Global.getInt(mContext.getContentResolver(),
219 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700220 }
221
222 /**
223 * Returns true if the Bluetooth saved state is "on"
224 */
225 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700226 return Settings.Global.getInt(mContentResolver,
Zhihai Xu401202b2012-12-03 11:36:21 -0800227 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
228 }
229
230 /**
231 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
232 */
233 private final boolean isBluetoothPersistedStateOnBluetooth() {
234 return Settings.Global.getInt(mContentResolver,
235 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
fredc649fe492012-04-19 01:07:18 -0700236 }
237
238 /**
239 * Save the Bluetooth on/off state
240 *
241 */
Zhihai Xu401202b2012-12-03 11:36:21 -0800242 private void persistBluetoothSetting(int value) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700243 Settings.Global.putInt(mContext.getContentResolver(),
244 Settings.Global.BLUETOOTH_ON,
Zhihai Xu401202b2012-12-03 11:36:21 -0800245 value);
fredc649fe492012-04-19 01:07:18 -0700246 }
247
248 /**
249 * Returns true if the Bluetooth Adapter's name and address is
250 * locally cached
251 * @return
252 */
fredc0f420372012-04-12 00:02:00 -0700253 private boolean isNameAndAddressSet() {
254 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
255 }
256
fredc649fe492012-04-19 01:07:18 -0700257 /**
258 * Retrieve the Bluetooth Adapter's name and address and save it in
259 * in the local cache
260 */
fredc0f420372012-04-12 00:02:00 -0700261 private void loadStoredNameAndAddress() {
262 if (DBG) Log.d(TAG, "Loading stored name and address");
Zhihai Xud31c3222012-10-31 16:08:57 -0700263 if (mContext.getResources().getBoolean
264 (com.android.internal.R.bool.config_bluetooth_address_validation) &&
265 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
266 // if the valid flag is not set, don't load the address and name
267 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
268 return;
269 }
fredc0f420372012-04-12 00:02:00 -0700270 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
271 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
Zhihai Xud31c3222012-10-31 16:08:57 -0700272 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
fredc0f420372012-04-12 00:02:00 -0700273 }
274
fredc649fe492012-04-19 01:07:18 -0700275 /**
276 * Save the Bluetooth name and address in the persistent store.
277 * Only non-null values will be saved.
278 * @param name
279 * @param address
280 */
fredc0f420372012-04-12 00:02:00 -0700281 private void storeNameAndAddress(String name, String address) {
282 if (name != null) {
283 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700284 mName = name;
fredc649fe492012-04-19 01:07:18 -0700285 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
286 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700287 }
288
289 if (address != null) {
290 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700291 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700292 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
293 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700294 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700295
296 if ((name != null) && (address != null)) {
297 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
298 }
fredc0f420372012-04-12 00:02:00 -0700299 }
300
301 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
fredc0f420372012-04-12 00:02:00 -0700302 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
303 msg.obj = callback;
304 mHandler.sendMessage(msg);
305 synchronized(mConnection) {
306 return mBluetooth;
307 }
308 }
309
310 public void unregisterAdapter(IBluetoothManagerCallback callback) {
311 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
312 "Need BLUETOOTH permission");
313 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
314 msg.obj = callback;
315 mHandler.sendMessage(msg);
316 }
317
318 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
319 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
320 "Need BLUETOOTH permission");
321 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
322 msg.obj = callback;
323 mHandler.sendMessage(msg);
324 }
325
326 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
327 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
328 "Need BLUETOOTH permission");
329 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
330 msg.obj = callback;
331 mHandler.sendMessage(msg);
332 }
333
334 public boolean isEnabled() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800335 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
336 (!checkIfCallerIsForegroundUser())) {
337 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700338 return false;
339 }
340
fredc0f420372012-04-12 00:02:00 -0700341 synchronized(mConnection) {
342 try {
343 return (mBluetooth != null && mBluetooth.isEnabled());
344 } catch (RemoteException e) {
345 Log.e(TAG, "isEnabled()", e);
346 }
347 }
348 return false;
349 }
350
351 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700352 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700353 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
354 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700355 }
fredc0f420372012-04-12 00:02:00 -0700356 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
357 mHandler.sendMessage(msg);
358 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700359 public boolean enableNoAutoConnect()
360 {
361 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
362 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700363
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700364 if (DBG) {
365 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
366 " mBinding = " + mBinding);
367 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800368 int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
369
370 if (callingAppId != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700371 throw new SecurityException("no permission to enable Bluetooth quietly");
372 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800373
Zhihai Xu401202b2012-12-03 11:36:21 -0800374 synchronized(mReceiver) {
375 mQuietEnableExternal = true;
376 mEnableExternal = true;
377 sendEnableMsg(true);
378 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700379 return true;
380
381 }
fredc0f420372012-04-12 00:02:00 -0700382 public boolean enable() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800383 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
384 (!checkIfCallerIsForegroundUser())) {
385 Log.w(TAG,"enable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700386 return false;
fredcf2458862012-04-16 15:18:27 -0700387 }
388
Zhihai Xu401202b2012-12-03 11:36:21 -0800389 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
390 "Need BLUETOOTH ADMIN permission");
391 if (DBG) {
392 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
393 " mBinding = " + mBinding);
394 }
395
396 synchronized(mReceiver) {
397 mQuietEnableExternal = false;
398 mEnableExternal = true;
399 // waive WRITE_SECURE_SETTINGS permission check
400 long callingIdentity = Binder.clearCallingIdentity();
401 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
402 Binder.restoreCallingIdentity(callingIdentity);
403 sendEnableMsg(false);
404 }
405 return true;
fredc0f420372012-04-12 00:02:00 -0700406 }
407
408 public boolean disable(boolean persist) {
409 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
410 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700411
Zhihai Xu6eb76522012-11-29 15:41:04 -0800412 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
413 (!checkIfCallerIsForegroundUser())) {
414 Log.w(TAG,"disable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700415 return false;
416 }
417
fredcf2458862012-04-16 15:18:27 -0700418 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700419 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
420 " mBinding = " + mBinding);
421 }
fredcf2458862012-04-16 15:18:27 -0700422
Zhihai Xu401202b2012-12-03 11:36:21 -0800423 synchronized(mReceiver) {
424 if (persist) {
425 // waive WRITE_SECURE_SETTINGS permission check
426 long callingIdentity = Binder.clearCallingIdentity();
427 persistBluetoothSetting(BLUETOOTH_OFF);
428 Binder.restoreCallingIdentity(callingIdentity);
429 }
430 mEnableExternal = false;
431 sendDisableMsg();
432 }
fredc0f420372012-04-12 00:02:00 -0700433 return true;
434 }
435
fredc649fe492012-04-19 01:07:18 -0700436 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700437 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700438 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
439 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700440 }
441
fredc0f420372012-04-12 00:02:00 -0700442 synchronized (mConnection) {
443 if (mUnbinding) return;
444 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700445 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700446 if (!mConnection.isGetNameAddressOnly()) {
447 //Unregister callback object
448 try {
449 mBluetooth.unregisterCallback(mBluetoothCallback);
450 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700451 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700452 }
453 }
fredc0f420372012-04-12 00:02:00 -0700454 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700455 mBluetooth = null;
456 //Unbind
fredc0f420372012-04-12 00:02:00 -0700457 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700458 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700459 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700460 } else {
461 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700462 }
463 }
464 }
465
fredcbf072a72012-05-09 16:52:50 -0700466 private void sendBluetoothStateCallback(boolean isUp) {
467 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700468 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700469 for (int i=0; i <n;i++) {
470 try {
471 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
472 } catch (RemoteException e) {
473 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
474 }
475 }
476 mStateChangeCallbacks.finishBroadcast();
477 }
478
479 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700480 * Inform BluetoothAdapter instances that Adapter service is up
481 */
482 private void sendBluetoothServiceUpCallback() {
483 if (!mConnection.isGetNameAddressOnly()) {
484 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
485 int n = mCallbacks.beginBroadcast();
486 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
487 for (int i=0; i <n;i++) {
488 try {
489 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
490 } catch (RemoteException e) {
491 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
492 }
493 }
494 mCallbacks.finishBroadcast();
495 }
496 }
497 /**
fredcbf072a72012-05-09 16:52:50 -0700498 * Inform BluetoothAdapter instances that Adapter service is down
499 */
500 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700501 if (!mConnection.isGetNameAddressOnly()) {
502 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
503 int n = mCallbacks.beginBroadcast();
504 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
505 for (int i=0; i <n;i++) {
506 try {
507 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
508 } catch (RemoteException e) {
509 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
510 }
511 }
512 mCallbacks.finishBroadcast();
513 }
514 }
fredc0f420372012-04-12 00:02:00 -0700515 public String getAddress() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800516 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
517 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700518
Zhihai Xu6eb76522012-11-29 15:41:04 -0800519 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
520 (!checkIfCallerIsForegroundUser())) {
521 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
522 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700523 }
524
fredc116d1d462012-04-20 14:47:08 -0700525 synchronized(mConnection) {
526 if (mBluetooth != null) {
527 try {
528 return mBluetooth.getAddress();
529 } catch (RemoteException e) {
530 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
531 }
532 }
533 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700534 // mAddress is accessed from outside.
535 // It is alright without a lock. Here, bluetooth is off, no other thread is
536 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700537 return mAddress;
538 }
fredc649fe492012-04-19 01:07:18 -0700539
fredc0f420372012-04-12 00:02:00 -0700540 public String getName() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800541 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
542 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700543
Zhihai Xu6eb76522012-11-29 15:41:04 -0800544 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
545 (!checkIfCallerIsForegroundUser())) {
546 Log.w(TAG,"getName(): not allowed for non-active and non system user");
547 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700548 }
549
fredc116d1d462012-04-20 14:47:08 -0700550 synchronized(mConnection) {
551 if (mBluetooth != null) {
552 try {
553 return mBluetooth.getName();
554 } catch (RemoteException e) {
555 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
556 }
557 }
558 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700559 // mName is accessed from outside.
560 // It alright without a lock. Here, bluetooth is off, no other thread is
561 // changing mName
fredc0f420372012-04-12 00:02:00 -0700562 return mName;
563 }
564
fredc0f420372012-04-12 00:02:00 -0700565 private class BluetoothServiceConnection implements ServiceConnection {
566
567 private boolean mGetNameAddressOnly;
568
569 public void setGetNameAddressOnly(boolean getOnly) {
570 mGetNameAddressOnly = getOnly;
571 }
572
573 public boolean isGetNameAddressOnly() {
574 return mGetNameAddressOnly;
575 }
576
577 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700578 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700579 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
580 msg.obj = service;
581 mHandler.sendMessage(msg);
582 }
583
584 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700585 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700586 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700587 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
588 mHandler.sendMessage(msg);
589 }
590 }
591
592 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
593
Zhihai Xu40874a02012-10-08 17:57:03 -0700594 private class BluetoothHandler extends Handler {
595 public BluetoothHandler(Looper looper) {
596 super(looper);
597 }
598
fredc0f420372012-04-12 00:02:00 -0700599 @Override
600 public void handleMessage(Message msg) {
601 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700602 switch (msg.what) {
603 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700604 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700605 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700606 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -0700607 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -0700608 if (DBG) Log.d(TAG, "Binding to service to get name and address");
609 mConnection.setGetNameAddressOnly(true);
610 //Start bind timeout and bind
611 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
612 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
613 Intent i = new Intent(IBluetooth.class.getName());
Amith Yamasani27b89e62013-01-16 12:30:11 -0800614 if (!mContext.bindServiceAsUser(i, mConnection,
615 Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700616 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
617 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700618 } else {
619 mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700620 }
621 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700622 else {
623 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -0700624 saveMsg.arg1 = 0;
625 if (mBluetooth != null) {
626 mHandler.sendMessage(saveMsg);
627 } else {
628 // if enable is also called to bind the service
629 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
630 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
631 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700632 }
fredc0f420372012-04-12 00:02:00 -0700633 }
fredc649fe492012-04-19 01:07:18 -0700634 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700635 }
fredc0f420372012-04-12 00:02:00 -0700636 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -0700637 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -0700638 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700639 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700640 if (!mEnable && mBluetooth != null) {
641 try {
642 mBluetooth.enable();
643 } catch (RemoteException e) {
644 Log.e(TAG,"Unable to call enable()",e);
645 }
646 }
647 }
648 if (mBluetooth != null) waitForOnOff(true, false);
649 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700650 if (mBluetooth != null) {
651 String name = null;
652 String address = null;
653 try {
654 name = mBluetooth.getName();
655 address = mBluetooth.getAddress();
656 } catch (RemoteException re) {
657 Log.e(TAG,"",re);
658 }
fredc0f420372012-04-12 00:02:00 -0700659
Matthew Xiecdce0b92012-07-12 19:06:15 -0700660 if (name != null && address != null) {
661 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -0700662 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700663 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700664 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700665 } else {
666 if (msg.arg1 < MAX_SAVE_RETRIES) {
667 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
668 retryMsg.arg1= 1+msg.arg1;
669 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
670 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
671 } else {
672 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -0700673 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700674 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700675 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700676 }
fredc0f420372012-04-12 00:02:00 -0700677 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700678 if (!mEnable) {
679 try {
680 mBluetooth.disable();
681 } catch (RemoteException e) {
682 Log.e(TAG,"Unable to call disable()",e);
683 }
684 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700685 } else {
686 // rebind service by Request GET NAME AND ADDRESS
687 // if service is unbinded by disable or
688 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
689 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
690 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -0700691 }
692 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700693 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
694 if (unbind) {
695 unbindAndFinish();
696 }
fredc649fe492012-04-19 01:07:18 -0700697 break;
fredc649fe492012-04-19 01:07:18 -0700698 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700699 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700700 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700701 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700702 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700703 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
704 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800705 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -0700706 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700707
fredc0f420372012-04-12 00:02:00 -0700708 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -0700709 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
710 if (mEnable && mBluetooth != null) {
711 waitForOnOff(true, false);
712 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800713 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700714 waitForOnOff(false, false);
715 } else {
716 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800717 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700718 }
fredc0f420372012-04-12 00:02:00 -0700719 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700720
fredc0f420372012-04-12 00:02:00 -0700721 case MESSAGE_REGISTER_ADAPTER:
722 {
723 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700724 boolean added = mCallbacks.register(callback);
725 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700726 }
727 break;
728 case MESSAGE_UNREGISTER_ADAPTER:
729 {
730 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700731 boolean removed = mCallbacks.unregister(callback);
732 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700733 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700734 }
fredc0f420372012-04-12 00:02:00 -0700735 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
736 {
737 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700738 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700739 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700740 }
fredc0f420372012-04-12 00:02:00 -0700741 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
742 {
743 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700744 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700745 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700746 }
fredc0f420372012-04-12 00:02:00 -0700747 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
748 {
fredc649fe492012-04-19 01:07:18 -0700749 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
750
fredc0f420372012-04-12 00:02:00 -0700751 //Remove timeout
752 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
753
754 IBinder service = (IBinder) msg.obj;
755 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700756 mBinding = false;
757 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700758
Matthew Xiecdce0b92012-07-12 19:06:15 -0700759 if (mConnection.isGetNameAddressOnly()) {
760 //Request GET NAME AND ADDRESS
761 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
762 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -0700763 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700764 }
fredc0f420372012-04-12 00:02:00 -0700765
Zhihai Xu40874a02012-10-08 17:57:03 -0700766 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700767 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700768 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700769 mBluetooth.registerCallback(mBluetoothCallback);
770 } catch (RemoteException re) {
771 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700772 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700773 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -0700774 sendBluetoothServiceUpCallback();
775
Matthew Xiecdce0b92012-07-12 19:06:15 -0700776 //Do enable request
777 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700778 if (mQuietEnable == false) {
779 if(!mBluetooth.enable()) {
780 Log.e(TAG,"IBluetooth.enable() returned false");
781 }
782 }
783 else
784 {
785 if(!mBluetooth.enableNoAutoConnect()) {
786 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
787 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700788 }
789 } catch (RemoteException e) {
790 Log.e(TAG,"Unable to call enable()",e);
791 }
Freda8c6df02012-07-11 10:25:23 -0700792 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700793
794 if (!mEnable) {
795 waitForOnOff(true, false);
Zhihai Xu401202b2012-12-03 11:36:21 -0800796 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700797 waitForOnOff(false, false);
798 }
fredc649fe492012-04-19 01:07:18 -0700799 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700800 }
fredc649fe492012-04-19 01:07:18 -0700801 case MESSAGE_TIMEOUT_BIND: {
802 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700803 synchronized(mConnection) {
804 mBinding = false;
805 }
fredc649fe492012-04-19 01:07:18 -0700806 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700807 }
fredcbf072a72012-05-09 16:52:50 -0700808 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700809 {
fredcbf072a72012-05-09 16:52:50 -0700810 int prevState = msg.arg1;
811 int newState = msg.arg2;
812 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -0700813 mState = newState;
814 bluetoothStateChangeHandler(prevState, newState);
fredc649fe492012-04-19 01:07:18 -0700815 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700816 }
fredc0f420372012-04-12 00:02:00 -0700817 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
818 {
Zhihai Xu40874a02012-10-08 17:57:03 -0700819 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530820 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700821 // if service is unbinded already, do nothing and return
822 if (mBluetooth == null) return;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530823 mBluetooth = null;
824 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700825
826 if (mEnable) {
827 mEnable = false;
828 // Send a Bluetooth Restart message
829 Message restartMsg = mHandler.obtainMessage(
830 MESSAGE_RESTART_BLUETOOTH_SERVICE);
831 mHandler.sendMessageDelayed(restartMsg,
832 SERVICE_RESTART_TIME_MS);
833 }
834
835 if (!mConnection.isGetNameAddressOnly()) {
836 sendBluetoothServiceDownCallback();
837
838 // Send BT state broadcast to update
839 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800840 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
841 (mState == BluetoothAdapter.STATE_ON)) {
842 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
843 BluetoothAdapter.STATE_TURNING_OFF);
844 mState = BluetoothAdapter.STATE_TURNING_OFF;
845 }
846 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
847 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
848 BluetoothAdapter.STATE_OFF);
849 }
850
851 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -0700852 mState = BluetoothAdapter.STATE_OFF;
853 }
fredc649fe492012-04-19 01:07:18 -0700854 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700855 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530856 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
857 {
858 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
859 +" Restart IBluetooth service");
860 /* Enable without persisting the setting as
861 it doesnt change when IBluetooth
862 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -0700863 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800864 handleEnable(mQuietEnable);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530865 break;
866 }
867
fredc0f420372012-04-12 00:02:00 -0700868 case MESSAGE_TIMEOUT_UNBIND:
869 {
fredc649fe492012-04-19 01:07:18 -0700870 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700871 synchronized(mConnection) {
872 mUnbinding = false;
873 }
fredc649fe492012-04-19 01:07:18 -0700874 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700875 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700876
877 case MESSAGE_USER_SWITCHED:
878 {
879 if (DBG) {
880 Log.d(TAG, "MESSAGE_USER_SWITCHED");
881 }
882 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
883 /* disable and enable BT when detect a user switch */
884 if (mEnable && mBluetooth != null) {
885 synchronized (mConnection) {
886 if (mBluetooth != null) {
887 //Unregister callback object
888 try {
889 mBluetooth.unregisterCallback(mBluetoothCallback);
890 } catch (RemoteException re) {
891 Log.e(TAG, "Unable to unregister",re);
892 }
893 }
894 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800895
896 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
897 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
898 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
899 mState = BluetoothAdapter.STATE_OFF;
900 }
901 if (mState == BluetoothAdapter.STATE_OFF) {
902 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
903 mState = BluetoothAdapter.STATE_TURNING_ON;
904 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700905
906 waitForOnOff(true, false);
907
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800908 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
909 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
910 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700911
912 // disable
Zhihai Xu401202b2012-12-03 11:36:21 -0800913 handleDisable();
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800914 // Pbap service need receive STATE_TURNING_OFF intent to close
915 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
916 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700917
918 waitForOnOff(false, true);
919
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800920 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -0700921 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700922 sendBluetoothServiceDownCallback();
923 synchronized (mConnection) {
924 if (mBluetooth != null) {
925 mBluetooth = null;
926 //Unbind
927 mContext.unbindService(mConnection);
928 }
929 }
930 SystemClock.sleep(100);
931
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800932 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
933 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -0700934 // enable
Zhihai Xu401202b2012-12-03 11:36:21 -0800935 handleEnable(mQuietEnable);
Zhihai Xu40874a02012-10-08 17:57:03 -0700936 } else if (mBinding || mBluetooth != null) {
937 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
938 userMsg.arg2 = 1 + msg.arg2;
939 // if user is switched when service is being binding
940 // delay sending MESSAGE_USER_SWITCHED
941 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
942 if (DBG) {
943 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
944 }
945 }
946 break;
947 }
fredc0f420372012-04-12 00:02:00 -0700948 }
949 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700950 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700951
Zhihai Xu401202b2012-12-03 11:36:21 -0800952 private void handleEnable(boolean quietMode) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700953 mQuietEnable = quietMode;
954
Matthew Xiecdce0b92012-07-12 19:06:15 -0700955 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700956 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700957 //Start bind timeout and bind
958 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
959 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
960 mConnection.setGetNameAddressOnly(false);
961 Intent i = new Intent(IBluetooth.class.getName());
Amith Yamasani27b89e62013-01-16 12:30:11 -0800962 if (!mContext.bindServiceAsUser(i, mConnection,Context.BIND_AUTO_CREATE,
963 UserHandle.CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700964 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
965 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700966 } else {
967 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700968 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700969 } else if (mBluetooth != null) {
970 if (mConnection.isGetNameAddressOnly()) {
971 // if GetNameAddressOnly is set, we can clear this flag,
972 // so the service won't be unbind
973 // after name and address are saved
974 mConnection.setGetNameAddressOnly(false);
975 //Register callback object
976 try {
977 mBluetooth.registerCallback(mBluetoothCallback);
978 } catch (RemoteException re) {
979 Log.e(TAG, "Unable to register BluetoothCallback",re);
980 }
981 //Inform BluetoothAdapter instances that service is up
982 sendBluetoothServiceUpCallback();
983 }
984
Matthew Xiecdce0b92012-07-12 19:06:15 -0700985 //Enable bluetooth
986 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700987 if (!mQuietEnable) {
988 if(!mBluetooth.enable()) {
989 Log.e(TAG,"IBluetooth.enable() returned false");
990 }
991 }
992 else {
993 if(!mBluetooth.enableNoAutoConnect()) {
994 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
995 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700996 }
997 } catch (RemoteException e) {
998 Log.e(TAG,"Unable to call enable()",e);
999 }
1000 }
1001 }
1002 }
1003
Zhihai Xu401202b2012-12-03 11:36:21 -08001004 private void handleDisable() {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001005 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001006 // don't need to disable if GetNameAddressOnly is set,
1007 // service will be unbinded after Name and Address are saved
1008 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001009 if (DBG) Log.d(TAG,"Sending off request.");
1010
1011 try {
1012 if(!mBluetooth.disable()) {
1013 Log.e(TAG,"IBluetooth.disable() returned false");
1014 }
1015 } catch (RemoteException e) {
1016 Log.e(TAG,"Unable to call disable()",e);
1017 }
1018 }
1019 }
1020 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001021
1022 private boolean checkIfCallerIsForegroundUser() {
1023 int foregroundUser;
1024 int callingUser = UserHandle.getCallingUserId();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001025 int callingUid = Binder.getCallingUid();
Zhihai Xu40874a02012-10-08 17:57:03 -07001026 long callingIdentity = Binder.clearCallingIdentity();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001027 int callingAppId = UserHandle.getAppId(callingUid);
Zhihai Xu40874a02012-10-08 17:57:03 -07001028 boolean valid = false;
1029 try {
1030 foregroundUser = ActivityManager.getCurrentUser();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001031 valid = (callingUser == foregroundUser) ||
1032 callingAppId == Process.NFC_UID;
Zhihai Xu40874a02012-10-08 17:57:03 -07001033 if (DBG) {
1034 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1035 + " callingUser=" + callingUser
1036 + " foregroundUser=" + foregroundUser);
1037 }
1038 } finally {
1039 Binder.restoreCallingIdentity(callingIdentity);
1040 }
1041 return valid;
1042 }
1043
Zhihai Xu40874a02012-10-08 17:57:03 -07001044 private void bluetoothStateChangeHandler(int prevState, int newState) {
1045 if (prevState != newState) {
1046 //Notify all proxy objects first of adapter state change
1047 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
1048 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1049 sendBluetoothStateCallback(isUp);
1050
1051 //If Bluetooth is off, send service down event to proxy objects, and unbind
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001052 if (!isUp && canUnbindBluetoothService()) {
1053 sendBluetoothServiceDownCallback();
1054 unbindAndFinish();
Zhihai Xu40874a02012-10-08 17:57:03 -07001055 }
1056 }
1057
1058 //Send broadcast message to everyone else
1059 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1060 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1061 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1062 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1063 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
1064 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1065 BLUETOOTH_PERM);
1066 }
1067 }
1068
1069 /**
1070 * if on is true, wait for state become ON
1071 * if off is true, wait for state become OFF
1072 * if both on and off are false, wait for state not ON
1073 */
1074 private boolean waitForOnOff(boolean on, boolean off) {
1075 int i = 0;
1076 while (i < 10) {
1077 synchronized(mConnection) {
1078 try {
1079 if (mBluetooth == null) break;
1080 if (on) {
1081 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1082 } else if (off) {
1083 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001084 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001085 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001086 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001087 } catch (RemoteException e) {
1088 Log.e(TAG, "getState()", e);
1089 break;
1090 }
1091 }
1092 if (on || off) {
1093 SystemClock.sleep(300);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001094 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001095 SystemClock.sleep(50);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001096 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001097 i++;
1098 }
1099 Log.e(TAG,"waitForOnOff time out");
1100 return false;
1101 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001102
Zhihai Xu401202b2012-12-03 11:36:21 -08001103 private void sendDisableMsg() {
1104 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1105 }
1106
1107 private void sendEnableMsg(boolean quietMode) {
1108 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1109 quietMode ? 1 : 0, 0));
1110 }
1111
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001112 private boolean canUnbindBluetoothService() {
1113 synchronized(mConnection) {
1114 //Only unbind with mEnable flag not set
1115 //For race condition: disable and enable back-to-back
1116 //Avoid unbind right after enable due to callback from disable
1117 //Only unbind with Bluetooth at OFF state
1118 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1119 try {
1120 if (mEnable || (mBluetooth == null)) return false;
1121 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1122 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1123 } catch (RemoteException e) {
1124 Log.e(TAG, "getState()", e);
1125 }
1126 }
1127 return false;
1128 }
fredc0f420372012-04-12 00:02:00 -07001129}