blob: 8684e5b76fdbeefdd6a5ff4bbbdccf534947326f [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;
Matthew Xieddf7e472013-03-01 18:41:02 -080022import android.bluetooth.IBluetoothGatt;
fredcbf072a72012-05-09 16:52:50 -070023import android.bluetooth.IBluetoothCallback;
fredc0f420372012-04-12 00:02:00 -070024import android.bluetooth.IBluetoothManager;
25import android.bluetooth.IBluetoothManagerCallback;
26import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070027import android.content.BroadcastReceiver;
28import android.content.ComponentName;
29import android.content.ContentResolver;
30import android.content.Context;
31import android.content.Intent;
32import android.content.IntentFilter;
33import android.content.ServiceConnection;
Zhihai Xu40874a02012-10-08 17:57:03 -070034import android.os.Binder;
fredc0f420372012-04-12 00:02:00 -070035import android.os.Handler;
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
Matthew Xieddf7e472013-03-01 18:41:02 -080090 private static final int SERVICE_IBLUETOOTH = 1;
91 private static final int SERVICE_IBLUETOOTHGATT = 2;
92
fredc0f420372012-04-12 00:02:00 -070093 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070094
95 // Locks are not provided for mName and mAddress.
96 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070097 private String mAddress;
98 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -070099 private final ContentResolver mContentResolver;
100 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
101 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -0700102 private IBluetooth mBluetooth;
Matthew Xieddf7e472013-03-01 18:41:02 -0800103 private IBluetoothGatt mBluetoothGatt;
fredc649fe492012-04-19 01:07:18 -0700104 private boolean mBinding;
105 private boolean mUnbinding;
Zhihai Xu401202b2012-12-03 11:36:21 -0800106 // used inside handler thread
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700107 private boolean mQuietEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800108 // configuarion from external IBinder call which is used to
109 // synchronize with broadcast receiver.
110 private boolean mQuietEnableExternal;
111 // configuarion from external IBinder call which is used to
112 // synchronize with broadcast receiver.
113 private boolean mEnableExternal;
114 // used inside handler thread
Zhihai Xu40874a02012-10-08 17:57:03 -0700115 private boolean mEnable;
116 private int mState;
Zhihai Xu40874a02012-10-08 17:57:03 -0700117 private final BluetoothHandler mHandler;
fredc0f420372012-04-12 00:02:00 -0700118
fredc649fe492012-04-19 01:07:18 -0700119 private void registerForAirplaneMode(IntentFilter filter) {
120 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700121 final String airplaneModeRadios = Settings.Global.getString(resolver,
122 Settings.Global.AIRPLANE_MODE_RADIOS);
123 final String toggleableRadios = Settings.Global.getString(resolver,
124 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700125 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700126 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700127 if (mIsAirplaneSensitive) {
128 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
129 }
130 }
131
fredcbf072a72012-05-09 16:52:50 -0700132 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
133 @Override
134 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
135 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
136 mHandler.sendMessage(msg);
137 }
138 };
139
140 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700141 @Override
142 public void onReceive(Context context, Intent intent) {
143 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700144 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700145 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700146 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700147 if (newName != null) {
148 storeNameAndAddress(newName, null);
149 }
fredc649fe492012-04-19 01:07:18 -0700150 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
Zhihai Xu401202b2012-12-03 11:36:21 -0800151 synchronized(mReceiver) {
152 if (isBluetoothPersistedStateOn()) {
153 if (isAirplaneModeOn()) {
154 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
155 } else {
156 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
157 }
158 }
159 if (isAirplaneModeOn()) {
160 // disable without persisting the setting
161 sendDisableMsg();
162 } else if (mEnableExternal) {
163 // enable without persisting the setting
164 sendEnableMsg(mQuietEnableExternal);
165 }
fredc649fe492012-04-19 01:07:18 -0700166 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700167 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
168 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
169 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Zhihai Xu401202b2012-12-03 11:36:21 -0800170 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
171 synchronized(mReceiver) {
172 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
173 //Enable
174 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
175 sendEnableMsg(mQuietEnableExternal);
176 }
177 }
178
179 if (!isNameAndAddressSet()) {
180 //Sync the Bluetooth name and address from the Bluetooth Adapter
181 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
182 getNameAndAddress();
183 }
fredc0f420372012-04-12 00:02:00 -0700184 }
185 }
186 };
187
188 BluetoothManagerService(Context context) {
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700189 mHandler = new BluetoothHandler(IoThread.get().getLooper());
Zhihai Xu40874a02012-10-08 17:57:03 -0700190
fredc0f420372012-04-12 00:02:00 -0700191 mContext = context;
192 mBluetooth = null;
193 mBinding = false;
194 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700195 mEnable = false;
196 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu401202b2012-12-03 11:36:21 -0800197 mQuietEnableExternal = false;
198 mEnableExternal = false;
fredc0f420372012-04-12 00:02:00 -0700199 mAddress = null;
200 mName = null;
201 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700202 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
203 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Zhihai Xu401202b2012-12-03 11:36:21 -0800204 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700205 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700206 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700207 registerForAirplaneMode(filter);
208 mContext.registerReceiver(mReceiver, filter);
fredc0f420372012-04-12 00:02:00 -0700209 loadStoredNameAndAddress();
Zhihai Xu401202b2012-12-03 11:36:21 -0800210 if (isBluetoothPersistedStateOn()) {
211 mEnableExternal = true;
fredc0f420372012-04-12 00:02:00 -0700212 }
213 }
214
fredc649fe492012-04-19 01:07:18 -0700215 /**
216 * Returns true if airplane mode is currently on
217 */
218 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700219 return Settings.Global.getInt(mContext.getContentResolver(),
220 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700221 }
222
223 /**
224 * Returns true if the Bluetooth saved state is "on"
225 */
226 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700227 return Settings.Global.getInt(mContentResolver,
Zhihai Xu401202b2012-12-03 11:36:21 -0800228 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
229 }
230
231 /**
232 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
233 */
234 private final boolean isBluetoothPersistedStateOnBluetooth() {
235 return Settings.Global.getInt(mContentResolver,
236 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
fredc649fe492012-04-19 01:07:18 -0700237 }
238
239 /**
240 * Save the Bluetooth on/off state
241 *
242 */
Zhihai Xu401202b2012-12-03 11:36:21 -0800243 private void persistBluetoothSetting(int value) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700244 Settings.Global.putInt(mContext.getContentResolver(),
245 Settings.Global.BLUETOOTH_ON,
Zhihai Xu401202b2012-12-03 11:36:21 -0800246 value);
fredc649fe492012-04-19 01:07:18 -0700247 }
248
249 /**
250 * Returns true if the Bluetooth Adapter's name and address is
251 * locally cached
252 * @return
253 */
fredc0f420372012-04-12 00:02:00 -0700254 private boolean isNameAndAddressSet() {
255 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
256 }
257
fredc649fe492012-04-19 01:07:18 -0700258 /**
259 * Retrieve the Bluetooth Adapter's name and address and save it in
260 * in the local cache
261 */
fredc0f420372012-04-12 00:02:00 -0700262 private void loadStoredNameAndAddress() {
263 if (DBG) Log.d(TAG, "Loading stored name and address");
Zhihai Xud31c3222012-10-31 16:08:57 -0700264 if (mContext.getResources().getBoolean
265 (com.android.internal.R.bool.config_bluetooth_address_validation) &&
266 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
267 // if the valid flag is not set, don't load the address and name
268 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
269 return;
270 }
fredc0f420372012-04-12 00:02:00 -0700271 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
272 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
Zhihai Xud31c3222012-10-31 16:08:57 -0700273 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
fredc0f420372012-04-12 00:02:00 -0700274 }
275
fredc649fe492012-04-19 01:07:18 -0700276 /**
277 * Save the Bluetooth name and address in the persistent store.
278 * Only non-null values will be saved.
279 * @param name
280 * @param address
281 */
fredc0f420372012-04-12 00:02:00 -0700282 private void storeNameAndAddress(String name, String address) {
283 if (name != null) {
284 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700285 mName = name;
fredc649fe492012-04-19 01:07:18 -0700286 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
287 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700288 }
289
290 if (address != null) {
291 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700292 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700293 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
294 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700295 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700296
297 if ((name != null) && (address != null)) {
298 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
299 }
fredc0f420372012-04-12 00:02:00 -0700300 }
301
302 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
fredc0f420372012-04-12 00:02:00 -0700303 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
304 msg.obj = callback;
305 mHandler.sendMessage(msg);
306 synchronized(mConnection) {
307 return mBluetooth;
308 }
309 }
310
311 public void unregisterAdapter(IBluetoothManagerCallback callback) {
312 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
313 "Need BLUETOOTH permission");
314 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
315 msg.obj = callback;
316 mHandler.sendMessage(msg);
317 }
318
319 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
320 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
321 "Need BLUETOOTH permission");
322 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
323 msg.obj = callback;
324 mHandler.sendMessage(msg);
325 }
326
327 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
328 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
329 "Need BLUETOOTH permission");
330 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
331 msg.obj = callback;
332 mHandler.sendMessage(msg);
333 }
334
335 public boolean isEnabled() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800336 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
337 (!checkIfCallerIsForegroundUser())) {
338 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700339 return false;
340 }
341
fredc0f420372012-04-12 00:02:00 -0700342 synchronized(mConnection) {
343 try {
344 return (mBluetooth != null && mBluetooth.isEnabled());
345 } catch (RemoteException e) {
346 Log.e(TAG, "isEnabled()", e);
347 }
348 }
349 return false;
350 }
351
352 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700353 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700354 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
355 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700356 }
fredc0f420372012-04-12 00:02:00 -0700357 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
358 mHandler.sendMessage(msg);
359 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700360 public boolean enableNoAutoConnect()
361 {
362 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
363 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700364
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700365 if (DBG) {
366 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
367 " mBinding = " + mBinding);
368 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800369 int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
370
371 if (callingAppId != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700372 throw new SecurityException("no permission to enable Bluetooth quietly");
373 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800374
Zhihai Xu401202b2012-12-03 11:36:21 -0800375 synchronized(mReceiver) {
376 mQuietEnableExternal = true;
377 mEnableExternal = true;
378 sendEnableMsg(true);
379 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700380 return true;
381
382 }
fredc0f420372012-04-12 00:02:00 -0700383 public boolean enable() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800384 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
385 (!checkIfCallerIsForegroundUser())) {
386 Log.w(TAG,"enable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700387 return false;
fredcf2458862012-04-16 15:18:27 -0700388 }
389
Zhihai Xu401202b2012-12-03 11:36:21 -0800390 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
391 "Need BLUETOOTH ADMIN permission");
392 if (DBG) {
393 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
394 " mBinding = " + mBinding);
395 }
396
397 synchronized(mReceiver) {
398 mQuietEnableExternal = false;
399 mEnableExternal = true;
400 // waive WRITE_SECURE_SETTINGS permission check
401 long callingIdentity = Binder.clearCallingIdentity();
402 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
403 Binder.restoreCallingIdentity(callingIdentity);
404 sendEnableMsg(false);
405 }
406 return true;
fredc0f420372012-04-12 00:02:00 -0700407 }
408
409 public boolean disable(boolean persist) {
410 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
411 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700412
Zhihai Xu6eb76522012-11-29 15:41:04 -0800413 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
414 (!checkIfCallerIsForegroundUser())) {
415 Log.w(TAG,"disable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700416 return false;
417 }
418
fredcf2458862012-04-16 15:18:27 -0700419 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700420 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
421 " mBinding = " + mBinding);
422 }
fredcf2458862012-04-16 15:18:27 -0700423
Zhihai Xu401202b2012-12-03 11:36:21 -0800424 synchronized(mReceiver) {
425 if (persist) {
426 // waive WRITE_SECURE_SETTINGS permission check
427 long callingIdentity = Binder.clearCallingIdentity();
428 persistBluetoothSetting(BLUETOOTH_OFF);
429 Binder.restoreCallingIdentity(callingIdentity);
430 }
431 mEnableExternal = false;
432 sendDisableMsg();
433 }
fredc0f420372012-04-12 00:02:00 -0700434 return true;
435 }
436
fredc649fe492012-04-19 01:07:18 -0700437 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700438 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700439 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
440 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700441 }
442
fredc0f420372012-04-12 00:02:00 -0700443 synchronized (mConnection) {
444 if (mUnbinding) return;
445 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700446 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700447 if (!mConnection.isGetNameAddressOnly()) {
448 //Unregister callback object
449 try {
450 mBluetooth.unregisterCallback(mBluetoothCallback);
451 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700452 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700453 }
454 }
fredc0f420372012-04-12 00:02:00 -0700455 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700456 mBluetooth = null;
457 //Unbind
fredc0f420372012-04-12 00:02:00 -0700458 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700459 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700460 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700461 } else {
462 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700463 }
464 }
465 }
466
Matthew Xieddf7e472013-03-01 18:41:02 -0800467 public IBluetoothGatt getBluetoothGatt() {
468 // sync protection
469 return mBluetoothGatt;
470 }
471
fredcbf072a72012-05-09 16:52:50 -0700472 private void sendBluetoothStateCallback(boolean isUp) {
473 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700474 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700475 for (int i=0; i <n;i++) {
476 try {
477 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
478 } catch (RemoteException e) {
479 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
480 }
481 }
482 mStateChangeCallbacks.finishBroadcast();
483 }
484
485 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700486 * Inform BluetoothAdapter instances that Adapter service is up
487 */
488 private void sendBluetoothServiceUpCallback() {
489 if (!mConnection.isGetNameAddressOnly()) {
490 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
491 int n = mCallbacks.beginBroadcast();
492 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
493 for (int i=0; i <n;i++) {
494 try {
495 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
496 } catch (RemoteException e) {
497 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
498 }
499 }
500 mCallbacks.finishBroadcast();
501 }
502 }
503 /**
fredcbf072a72012-05-09 16:52:50 -0700504 * Inform BluetoothAdapter instances that Adapter service is down
505 */
506 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700507 if (!mConnection.isGetNameAddressOnly()) {
508 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
509 int n = mCallbacks.beginBroadcast();
510 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
511 for (int i=0; i <n;i++) {
512 try {
513 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
514 } catch (RemoteException e) {
515 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
516 }
517 }
518 mCallbacks.finishBroadcast();
519 }
520 }
fredc0f420372012-04-12 00:02:00 -0700521 public String getAddress() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800522 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
523 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700524
Zhihai Xu6eb76522012-11-29 15:41:04 -0800525 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
526 (!checkIfCallerIsForegroundUser())) {
527 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
528 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700529 }
530
fredc116d1d462012-04-20 14:47:08 -0700531 synchronized(mConnection) {
532 if (mBluetooth != null) {
533 try {
534 return mBluetooth.getAddress();
535 } catch (RemoteException e) {
536 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
537 }
538 }
539 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700540 // mAddress is accessed from outside.
541 // It is alright without a lock. Here, bluetooth is off, no other thread is
542 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700543 return mAddress;
544 }
fredc649fe492012-04-19 01:07:18 -0700545
fredc0f420372012-04-12 00:02:00 -0700546 public String getName() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800547 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
548 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700549
Zhihai Xu6eb76522012-11-29 15:41:04 -0800550 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
551 (!checkIfCallerIsForegroundUser())) {
552 Log.w(TAG,"getName(): not allowed for non-active and non system user");
553 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700554 }
555
fredc116d1d462012-04-20 14:47:08 -0700556 synchronized(mConnection) {
557 if (mBluetooth != null) {
558 try {
559 return mBluetooth.getName();
560 } catch (RemoteException e) {
561 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
562 }
563 }
564 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700565 // mName is accessed from outside.
566 // It alright without a lock. Here, bluetooth is off, no other thread is
567 // changing mName
fredc0f420372012-04-12 00:02:00 -0700568 return mName;
569 }
570
fredc0f420372012-04-12 00:02:00 -0700571 private class BluetoothServiceConnection implements ServiceConnection {
572
573 private boolean mGetNameAddressOnly;
574
575 public void setGetNameAddressOnly(boolean getOnly) {
576 mGetNameAddressOnly = getOnly;
577 }
578
579 public boolean isGetNameAddressOnly() {
580 return mGetNameAddressOnly;
581 }
582
583 public void onServiceConnected(ComponentName className, IBinder service) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800584 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700585 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800586 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
587 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
588 msg.arg1 = SERVICE_IBLUETOOTH;
589 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
590 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
591 msg.arg1 = SERVICE_IBLUETOOTHGATT;
592 } else {
593 Log.e(TAG, "Unknown service connected: " + className.getClassName());
594 return;
595 }
fredc0f420372012-04-12 00:02:00 -0700596 msg.obj = service;
597 mHandler.sendMessage(msg);
598 }
599
600 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700601 // Called if we unexpected disconnected.
Matthew Xieddf7e472013-03-01 18:41:02 -0800602 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
603 className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700604 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800605 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
606 msg.arg1 = SERVICE_IBLUETOOTH;
607 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
608 msg.arg1 = SERVICE_IBLUETOOTHGATT;
609 } else {
610 Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
611 return;
612 }
fredc0f420372012-04-12 00:02:00 -0700613 mHandler.sendMessage(msg);
614 }
615 }
616
617 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
618
Zhihai Xu40874a02012-10-08 17:57:03 -0700619 private class BluetoothHandler extends Handler {
620 public BluetoothHandler(Looper looper) {
621 super(looper);
622 }
623
fredc0f420372012-04-12 00:02:00 -0700624 @Override
625 public void handleMessage(Message msg) {
626 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700627 switch (msg.what) {
628 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700629 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700630 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700631 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -0700632 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -0700633 if (DBG) Log.d(TAG, "Binding to service to get name and address");
634 mConnection.setGetNameAddressOnly(true);
635 //Start bind timeout and bind
636 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
637 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
638 Intent i = new Intent(IBluetooth.class.getName());
Amith Yamasani27b89e62013-01-16 12:30:11 -0800639 if (!mContext.bindServiceAsUser(i, mConnection,
640 Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700641 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
642 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700643 } else {
644 mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700645 }
646 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700647 else {
648 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -0700649 saveMsg.arg1 = 0;
650 if (mBluetooth != null) {
651 mHandler.sendMessage(saveMsg);
652 } else {
653 // if enable is also called to bind the service
654 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
655 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
656 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700657 }
fredc0f420372012-04-12 00:02:00 -0700658 }
fredc649fe492012-04-19 01:07:18 -0700659 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700660 }
fredc0f420372012-04-12 00:02:00 -0700661 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -0700662 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -0700663 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700664 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700665 if (!mEnable && mBluetooth != null) {
666 try {
667 mBluetooth.enable();
668 } catch (RemoteException e) {
669 Log.e(TAG,"Unable to call enable()",e);
670 }
671 }
672 }
673 if (mBluetooth != null) waitForOnOff(true, false);
674 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700675 if (mBluetooth != null) {
676 String name = null;
677 String address = null;
678 try {
679 name = mBluetooth.getName();
680 address = mBluetooth.getAddress();
681 } catch (RemoteException re) {
682 Log.e(TAG,"",re);
683 }
fredc0f420372012-04-12 00:02:00 -0700684
Matthew Xiecdce0b92012-07-12 19:06:15 -0700685 if (name != null && address != null) {
686 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -0700687 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700688 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700689 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700690 } else {
691 if (msg.arg1 < MAX_SAVE_RETRIES) {
692 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
693 retryMsg.arg1= 1+msg.arg1;
694 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
695 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
696 } else {
697 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -0700698 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700699 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700700 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700701 }
fredc0f420372012-04-12 00:02:00 -0700702 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700703 if (!mEnable) {
704 try {
705 mBluetooth.disable();
706 } catch (RemoteException e) {
707 Log.e(TAG,"Unable to call disable()",e);
708 }
709 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700710 } else {
711 // rebind service by Request GET NAME AND ADDRESS
712 // if service is unbinded by disable or
713 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
714 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
715 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -0700716 }
717 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700718 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
719 if (unbind) {
720 unbindAndFinish();
721 }
fredc649fe492012-04-19 01:07:18 -0700722 break;
fredc649fe492012-04-19 01:07:18 -0700723 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700724 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700725 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700726 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700727 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700728 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
729 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800730 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -0700731 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700732
fredc0f420372012-04-12 00:02:00 -0700733 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -0700734 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
735 if (mEnable && mBluetooth != null) {
736 waitForOnOff(true, false);
737 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800738 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700739 waitForOnOff(false, false);
740 } else {
741 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800742 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700743 }
fredc0f420372012-04-12 00:02:00 -0700744 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700745
fredc0f420372012-04-12 00:02:00 -0700746 case MESSAGE_REGISTER_ADAPTER:
747 {
748 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700749 boolean added = mCallbacks.register(callback);
750 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700751 }
752 break;
753 case MESSAGE_UNREGISTER_ADAPTER:
754 {
755 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700756 boolean removed = mCallbacks.unregister(callback);
757 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700758 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700759 }
fredc0f420372012-04-12 00:02:00 -0700760 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
761 {
762 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700763 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700764 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700765 }
fredc0f420372012-04-12 00:02:00 -0700766 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
767 {
768 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700769 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700770 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700771 }
fredc0f420372012-04-12 00:02:00 -0700772 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
773 {
Matthew Xieddf7e472013-03-01 18:41:02 -0800774 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
fredc0f420372012-04-12 00:02:00 -0700775
776 IBinder service = (IBinder) msg.obj;
777 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800778 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
779 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
780 break;
781 } // else must be SERVICE_IBLUETOOTH
782
783 //Remove timeout
784 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
785
fredc0f420372012-04-12 00:02:00 -0700786 mBinding = false;
787 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700788
Matthew Xiecdce0b92012-07-12 19:06:15 -0700789 if (mConnection.isGetNameAddressOnly()) {
790 //Request GET NAME AND ADDRESS
791 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
792 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -0700793 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700794 }
fredc0f420372012-04-12 00:02:00 -0700795
Zhihai Xu40874a02012-10-08 17:57:03 -0700796 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700797 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700798 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700799 mBluetooth.registerCallback(mBluetoothCallback);
800 } catch (RemoteException re) {
801 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700802 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700803 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -0700804 sendBluetoothServiceUpCallback();
805
Matthew Xiecdce0b92012-07-12 19:06:15 -0700806 //Do enable request
807 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700808 if (mQuietEnable == false) {
809 if(!mBluetooth.enable()) {
810 Log.e(TAG,"IBluetooth.enable() returned false");
811 }
812 }
813 else
814 {
815 if(!mBluetooth.enableNoAutoConnect()) {
816 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
817 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700818 }
819 } catch (RemoteException e) {
820 Log.e(TAG,"Unable to call enable()",e);
821 }
Freda8c6df02012-07-11 10:25:23 -0700822 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700823
824 if (!mEnable) {
825 waitForOnOff(true, false);
Zhihai Xu401202b2012-12-03 11:36:21 -0800826 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700827 waitForOnOff(false, false);
828 }
fredc649fe492012-04-19 01:07:18 -0700829 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700830 }
fredc649fe492012-04-19 01:07:18 -0700831 case MESSAGE_TIMEOUT_BIND: {
832 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700833 synchronized(mConnection) {
834 mBinding = false;
835 }
fredc649fe492012-04-19 01:07:18 -0700836 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700837 }
fredcbf072a72012-05-09 16:52:50 -0700838 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700839 {
fredcbf072a72012-05-09 16:52:50 -0700840 int prevState = msg.arg1;
841 int newState = msg.arg2;
842 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -0700843 mState = newState;
844 bluetoothStateChangeHandler(prevState, newState);
fredc649fe492012-04-19 01:07:18 -0700845 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700846 }
fredc0f420372012-04-12 00:02:00 -0700847 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
848 {
Matthew Xieddf7e472013-03-01 18:41:02 -0800849 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530850 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800851 if (msg.arg1 == SERVICE_IBLUETOOTH) {
852 // if service is unbinded already, do nothing and return
853 if (mBluetooth == null) break;
854 mBluetooth = null;
855 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
856 mBluetoothGatt = null;
857 break;
858 } else {
859 Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
860 break;
861 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530862 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700863
864 if (mEnable) {
865 mEnable = false;
866 // Send a Bluetooth Restart message
867 Message restartMsg = mHandler.obtainMessage(
868 MESSAGE_RESTART_BLUETOOTH_SERVICE);
869 mHandler.sendMessageDelayed(restartMsg,
870 SERVICE_RESTART_TIME_MS);
871 }
872
873 if (!mConnection.isGetNameAddressOnly()) {
874 sendBluetoothServiceDownCallback();
875
876 // Send BT state broadcast to update
877 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800878 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
879 (mState == BluetoothAdapter.STATE_ON)) {
880 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
881 BluetoothAdapter.STATE_TURNING_OFF);
882 mState = BluetoothAdapter.STATE_TURNING_OFF;
883 }
884 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
885 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
886 BluetoothAdapter.STATE_OFF);
887 }
888
889 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -0700890 mState = BluetoothAdapter.STATE_OFF;
891 }
fredc649fe492012-04-19 01:07:18 -0700892 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700893 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530894 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
895 {
896 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
897 +" Restart IBluetooth service");
898 /* Enable without persisting the setting as
899 it doesnt change when IBluetooth
900 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -0700901 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800902 handleEnable(mQuietEnable);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530903 break;
904 }
905
fredc0f420372012-04-12 00:02:00 -0700906 case MESSAGE_TIMEOUT_UNBIND:
907 {
fredc649fe492012-04-19 01:07:18 -0700908 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700909 synchronized(mConnection) {
910 mUnbinding = false;
911 }
fredc649fe492012-04-19 01:07:18 -0700912 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700913 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700914
915 case MESSAGE_USER_SWITCHED:
916 {
917 if (DBG) {
918 Log.d(TAG, "MESSAGE_USER_SWITCHED");
919 }
920 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
921 /* disable and enable BT when detect a user switch */
922 if (mEnable && mBluetooth != null) {
923 synchronized (mConnection) {
924 if (mBluetooth != null) {
925 //Unregister callback object
926 try {
927 mBluetooth.unregisterCallback(mBluetoothCallback);
928 } catch (RemoteException re) {
929 Log.e(TAG, "Unable to unregister",re);
930 }
931 }
932 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800933
934 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
935 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
936 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
937 mState = BluetoothAdapter.STATE_OFF;
938 }
939 if (mState == BluetoothAdapter.STATE_OFF) {
940 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
941 mState = BluetoothAdapter.STATE_TURNING_ON;
942 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700943
944 waitForOnOff(true, false);
945
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800946 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
947 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
948 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700949
950 // disable
Zhihai Xu401202b2012-12-03 11:36:21 -0800951 handleDisable();
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800952 // Pbap service need receive STATE_TURNING_OFF intent to close
953 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
954 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700955
956 waitForOnOff(false, true);
957
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800958 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -0700959 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700960 sendBluetoothServiceDownCallback();
961 synchronized (mConnection) {
962 if (mBluetooth != null) {
963 mBluetooth = null;
964 //Unbind
965 mContext.unbindService(mConnection);
966 }
967 }
968 SystemClock.sleep(100);
969
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800970 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
971 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -0700972 // enable
Zhihai Xu401202b2012-12-03 11:36:21 -0800973 handleEnable(mQuietEnable);
Zhihai Xu40874a02012-10-08 17:57:03 -0700974 } else if (mBinding || mBluetooth != null) {
975 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
976 userMsg.arg2 = 1 + msg.arg2;
977 // if user is switched when service is being binding
978 // delay sending MESSAGE_USER_SWITCHED
979 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
980 if (DBG) {
981 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
982 }
983 }
984 break;
985 }
fredc0f420372012-04-12 00:02:00 -0700986 }
987 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700988 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700989
Zhihai Xu401202b2012-12-03 11:36:21 -0800990 private void handleEnable(boolean quietMode) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700991 mQuietEnable = quietMode;
992
Matthew Xiecdce0b92012-07-12 19:06:15 -0700993 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700994 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700995 //Start bind timeout and bind
996 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
997 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
998 mConnection.setGetNameAddressOnly(false);
999 Intent i = new Intent(IBluetooth.class.getName());
Amith Yamasani27b89e62013-01-16 12:30:11 -08001000 if (!mContext.bindServiceAsUser(i, mConnection,Context.BIND_AUTO_CREATE,
1001 UserHandle.CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001002 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1003 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -07001004 } else {
1005 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001006 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001007 } else if (mBluetooth != null) {
1008 if (mConnection.isGetNameAddressOnly()) {
1009 // if GetNameAddressOnly is set, we can clear this flag,
1010 // so the service won't be unbind
1011 // after name and address are saved
1012 mConnection.setGetNameAddressOnly(false);
1013 //Register callback object
1014 try {
1015 mBluetooth.registerCallback(mBluetoothCallback);
1016 } catch (RemoteException re) {
1017 Log.e(TAG, "Unable to register BluetoothCallback",re);
1018 }
1019 //Inform BluetoothAdapter instances that service is up
1020 sendBluetoothServiceUpCallback();
1021 }
1022
Matthew Xiecdce0b92012-07-12 19:06:15 -07001023 //Enable bluetooth
1024 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001025 if (!mQuietEnable) {
1026 if(!mBluetooth.enable()) {
1027 Log.e(TAG,"IBluetooth.enable() returned false");
1028 }
1029 }
1030 else {
1031 if(!mBluetooth.enableNoAutoConnect()) {
1032 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1033 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001034 }
1035 } catch (RemoteException e) {
1036 Log.e(TAG,"Unable to call enable()",e);
1037 }
1038 }
1039 }
1040 }
1041
Zhihai Xu401202b2012-12-03 11:36:21 -08001042 private void handleDisable() {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001043 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001044 // don't need to disable if GetNameAddressOnly is set,
1045 // service will be unbinded after Name and Address are saved
1046 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001047 if (DBG) Log.d(TAG,"Sending off request.");
1048
1049 try {
1050 if(!mBluetooth.disable()) {
1051 Log.e(TAG,"IBluetooth.disable() returned false");
1052 }
1053 } catch (RemoteException e) {
1054 Log.e(TAG,"Unable to call disable()",e);
1055 }
1056 }
1057 }
1058 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001059
1060 private boolean checkIfCallerIsForegroundUser() {
1061 int foregroundUser;
1062 int callingUser = UserHandle.getCallingUserId();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001063 int callingUid = Binder.getCallingUid();
Zhihai Xu40874a02012-10-08 17:57:03 -07001064 long callingIdentity = Binder.clearCallingIdentity();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001065 int callingAppId = UserHandle.getAppId(callingUid);
Zhihai Xu40874a02012-10-08 17:57:03 -07001066 boolean valid = false;
1067 try {
1068 foregroundUser = ActivityManager.getCurrentUser();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001069 valid = (callingUser == foregroundUser) ||
1070 callingAppId == Process.NFC_UID;
Zhihai Xu40874a02012-10-08 17:57:03 -07001071 if (DBG) {
1072 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1073 + " callingUser=" + callingUser
1074 + " foregroundUser=" + foregroundUser);
1075 }
1076 } finally {
1077 Binder.restoreCallingIdentity(callingIdentity);
1078 }
1079 return valid;
1080 }
1081
Zhihai Xu40874a02012-10-08 17:57:03 -07001082 private void bluetoothStateChangeHandler(int prevState, int newState) {
1083 if (prevState != newState) {
1084 //Notify all proxy objects first of adapter state change
1085 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
1086 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1087 sendBluetoothStateCallback(isUp);
1088
Matthew Xieddf7e472013-03-01 18:41:02 -08001089 if (isUp) {
1090 // connect to GattService
1091 Intent i = new Intent(IBluetoothGatt.class.getName());
1092 if (!mContext.bindServiceAsUser(i, mConnection, Context.BIND_AUTO_CREATE,
1093 UserHandle.CURRENT)) {
1094 Log.e(TAG, "Fail to bind to: " + IBluetoothGatt.class.getName());
1095 }
1096 } else {
1097 //If Bluetooth is off, send service down event to proxy objects, and unbind
1098 if (!isUp && canUnbindBluetoothService()) {
1099 sendBluetoothServiceDownCallback();
1100 unbindAndFinish();
1101 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001102 }
1103 }
1104
1105 //Send broadcast message to everyone else
1106 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1107 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1108 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1109 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1110 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
1111 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1112 BLUETOOTH_PERM);
1113 }
1114 }
1115
1116 /**
1117 * if on is true, wait for state become ON
1118 * if off is true, wait for state become OFF
1119 * if both on and off are false, wait for state not ON
1120 */
1121 private boolean waitForOnOff(boolean on, boolean off) {
1122 int i = 0;
1123 while (i < 10) {
1124 synchronized(mConnection) {
1125 try {
1126 if (mBluetooth == null) break;
1127 if (on) {
1128 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1129 } else if (off) {
1130 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001131 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001132 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001133 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001134 } catch (RemoteException e) {
1135 Log.e(TAG, "getState()", e);
1136 break;
1137 }
1138 }
1139 if (on || off) {
1140 SystemClock.sleep(300);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001141 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001142 SystemClock.sleep(50);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001143 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001144 i++;
1145 }
1146 Log.e(TAG,"waitForOnOff time out");
1147 return false;
1148 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001149
Zhihai Xu401202b2012-12-03 11:36:21 -08001150 private void sendDisableMsg() {
1151 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1152 }
1153
1154 private void sendEnableMsg(boolean quietMode) {
1155 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1156 quietMode ? 1 : 0, 0));
1157 }
1158
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001159 private boolean canUnbindBluetoothService() {
1160 synchronized(mConnection) {
1161 //Only unbind with mEnable flag not set
1162 //For race condition: disable and enable back-to-back
1163 //Avoid unbind right after enable due to callback from disable
1164 //Only unbind with Bluetooth at OFF state
1165 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1166 try {
1167 if (mEnable || (mBluetooth == null)) return false;
1168 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1169 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1170 } catch (RemoteException e) {
1171 Log.e(TAG, "getState()", e);
1172 }
1173 }
1174 return false;
1175 }
fredc0f420372012-04-12 00:02:00 -07001176}