blob: f7a7fdf5a41a622ce121e01f1bdec2b27c00e74d [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;
Matthew Xie32ab77b2013-05-08 19:26:57 -070034import android.content.pm.PackageManager;
Zhihai Xu40874a02012-10-08 17:57:03 -070035import android.os.Binder;
fredc0f420372012-04-12 00:02:00 -070036import android.os.Handler;
Zhihai Xu40874a02012-10-08 17:57:03 -070037import android.os.HandlerThread;
fredc0f420372012-04-12 00:02:00 -070038import android.os.IBinder;
Zhihai Xu40874a02012-10-08 17:57:03 -070039import android.os.Looper;
fredc0f420372012-04-12 00:02:00 -070040import android.os.Message;
Zhihai Xu40874a02012-10-08 17:57:03 -070041import android.os.Process;
fredcd6883532012-04-25 17:46:13 -070042import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070043import android.os.RemoteException;
Zhihai Xu40874a02012-10-08 17:57:03 -070044import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070045import android.os.UserHandle;
fredc0f420372012-04-12 00:02:00 -070046import android.provider.Settings;
47import android.util.Log;
fredc0f420372012-04-12 00:02:00 -070048class BluetoothManagerService extends IBluetoothManager.Stub {
49 private static final String TAG = "BluetoothManagerService";
50 private static final boolean DBG = true;
51
fredc0f420372012-04-12 00:02:00 -070052 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
53 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070054 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
55 private static final String EXTRA_ACTION="action";
Zhihai Xud31c3222012-10-31 16:08:57 -070056 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
fredc0f420372012-04-12 00:02:00 -070057 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
58 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070059 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
60 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053061 //Maximum msec to wait for service restart
62 private static final int SERVICE_RESTART_TIME_MS = 200;
Zhihai Xu40874a02012-10-08 17:57:03 -070063 //Maximum msec to delay MESSAGE_USER_SWITCHED
64 private static final int USER_SWITCHED_TIME_MS = 200;
fredc0f420372012-04-12 00:02:00 -070065
66 private static final int MESSAGE_ENABLE = 1;
67 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070068 private static final int MESSAGE_REGISTER_ADAPTER = 20;
69 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
70 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
71 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
72 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
73 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053074 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070075 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070076 private static final int MESSAGE_TIMEOUT_BIND =100;
77 private static final int MESSAGE_TIMEOUT_UNBIND =101;
78 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
79 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
Zhihai Xu40874a02012-10-08 17:57:03 -070080 private static final int MESSAGE_USER_SWITCHED = 300;
fredc0f420372012-04-12 00:02:00 -070081 private static final int MAX_SAVE_RETRIES=3;
Zhihai Xu401202b2012-12-03 11:36:21 -080082 // Bluetooth persisted setting is off
83 private static final int BLUETOOTH_OFF=0;
84 // Bluetooth persisted setting is on
85 // and Airplane mode won't affect Bluetooth state at start up
86 private static final int BLUETOOTH_ON_BLUETOOTH=1;
87 // Bluetooth persisted setting is on
88 // but Airplane mode will affect Bluetooth state at start up
89 // and Airplane mode will have higher priority.
90 private static final int BLUETOOTH_ON_AIRPLANE=2;
fredc0f420372012-04-12 00:02:00 -070091
Matthew Xieddf7e472013-03-01 18:41:02 -080092 private static final int SERVICE_IBLUETOOTH = 1;
93 private static final int SERVICE_IBLUETOOTHGATT = 2;
94
fredc0f420372012-04-12 00:02:00 -070095 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070096
97 // Locks are not provided for mName and mAddress.
98 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070099 private String mAddress;
100 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -0700101 private final ContentResolver mContentResolver;
102 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
103 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -0700104 private IBluetooth mBluetooth;
Matthew Xieddf7e472013-03-01 18:41:02 -0800105 private IBluetoothGatt mBluetoothGatt;
fredc649fe492012-04-19 01:07:18 -0700106 private boolean mBinding;
107 private boolean mUnbinding;
Zhihai Xu401202b2012-12-03 11:36:21 -0800108 // used inside handler thread
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700109 private boolean mQuietEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800110 // configuarion from external IBinder call which is used to
111 // synchronize with broadcast receiver.
112 private boolean mQuietEnableExternal;
113 // configuarion from external IBinder call which is used to
114 // synchronize with broadcast receiver.
115 private boolean mEnableExternal;
116 // used inside handler thread
Zhihai Xu40874a02012-10-08 17:57:03 -0700117 private boolean mEnable;
118 private int mState;
119 private HandlerThread mThread;
120 private final BluetoothHandler mHandler;
fredc0f420372012-04-12 00:02:00 -0700121
fredc649fe492012-04-19 01:07:18 -0700122 private void registerForAirplaneMode(IntentFilter filter) {
123 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700124 final String airplaneModeRadios = Settings.Global.getString(resolver,
125 Settings.Global.AIRPLANE_MODE_RADIOS);
126 final String toggleableRadios = Settings.Global.getString(resolver,
127 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700128 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700129 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700130 if (mIsAirplaneSensitive) {
131 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
132 }
133 }
134
fredcbf072a72012-05-09 16:52:50 -0700135 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
136 @Override
137 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
138 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
139 mHandler.sendMessage(msg);
140 }
141 };
142
143 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700144 @Override
145 public void onReceive(Context context, Intent intent) {
146 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700147 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700148 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700149 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700150 if (newName != null) {
151 storeNameAndAddress(newName, null);
152 }
fredc649fe492012-04-19 01:07:18 -0700153 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
Zhihai Xu401202b2012-12-03 11:36:21 -0800154 synchronized(mReceiver) {
155 if (isBluetoothPersistedStateOn()) {
156 if (isAirplaneModeOn()) {
157 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
158 } else {
159 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
160 }
161 }
162 if (isAirplaneModeOn()) {
163 // disable without persisting the setting
164 sendDisableMsg();
165 } else if (mEnableExternal) {
166 // enable without persisting the setting
167 sendEnableMsg(mQuietEnableExternal);
168 }
fredc649fe492012-04-19 01:07:18 -0700169 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700170 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
171 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
172 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Zhihai Xu401202b2012-12-03 11:36:21 -0800173 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
174 synchronized(mReceiver) {
175 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
176 //Enable
177 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
178 sendEnableMsg(mQuietEnableExternal);
179 }
180 }
181
182 if (!isNameAndAddressSet()) {
183 //Sync the Bluetooth name and address from the Bluetooth Adapter
184 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
185 getNameAndAddress();
186 }
fredc0f420372012-04-12 00:02:00 -0700187 }
188 }
189 };
190
191 BluetoothManagerService(Context context) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700192 mThread = new HandlerThread("BluetoothManager");
193 mThread.start();
194 mHandler = new BluetoothHandler(mThread.getLooper());
195
fredc0f420372012-04-12 00:02:00 -0700196 mContext = context;
197 mBluetooth = null;
198 mBinding = false;
199 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700200 mEnable = false;
201 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu401202b2012-12-03 11:36:21 -0800202 mQuietEnableExternal = false;
203 mEnableExternal = false;
fredc0f420372012-04-12 00:02:00 -0700204 mAddress = null;
205 mName = null;
206 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700207 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
208 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Zhihai Xu401202b2012-12-03 11:36:21 -0800209 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700210 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700211 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700212 registerForAirplaneMode(filter);
213 mContext.registerReceiver(mReceiver, filter);
fredc0f420372012-04-12 00:02:00 -0700214 loadStoredNameAndAddress();
Zhihai Xu401202b2012-12-03 11:36:21 -0800215 if (isBluetoothPersistedStateOn()) {
216 mEnableExternal = true;
fredc0f420372012-04-12 00:02:00 -0700217 }
218 }
219
fredc649fe492012-04-19 01:07:18 -0700220 /**
221 * Returns true if airplane mode is currently on
222 */
223 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700224 return Settings.Global.getInt(mContext.getContentResolver(),
225 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700226 }
227
228 /**
229 * Returns true if the Bluetooth saved state is "on"
230 */
231 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700232 return Settings.Global.getInt(mContentResolver,
Zhihai Xu401202b2012-12-03 11:36:21 -0800233 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
234 }
235
236 /**
237 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
238 */
239 private final boolean isBluetoothPersistedStateOnBluetooth() {
240 return Settings.Global.getInt(mContentResolver,
241 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
fredc649fe492012-04-19 01:07:18 -0700242 }
243
244 /**
245 * Save the Bluetooth on/off state
246 *
247 */
Zhihai Xu401202b2012-12-03 11:36:21 -0800248 private void persistBluetoothSetting(int value) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700249 Settings.Global.putInt(mContext.getContentResolver(),
250 Settings.Global.BLUETOOTH_ON,
Zhihai Xu401202b2012-12-03 11:36:21 -0800251 value);
fredc649fe492012-04-19 01:07:18 -0700252 }
253
254 /**
255 * Returns true if the Bluetooth Adapter's name and address is
256 * locally cached
257 * @return
258 */
fredc0f420372012-04-12 00:02:00 -0700259 private boolean isNameAndAddressSet() {
260 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
261 }
262
fredc649fe492012-04-19 01:07:18 -0700263 /**
264 * Retrieve the Bluetooth Adapter's name and address and save it in
265 * in the local cache
266 */
fredc0f420372012-04-12 00:02:00 -0700267 private void loadStoredNameAndAddress() {
268 if (DBG) Log.d(TAG, "Loading stored name and address");
Zhihai Xud31c3222012-10-31 16:08:57 -0700269 if (mContext.getResources().getBoolean
270 (com.android.internal.R.bool.config_bluetooth_address_validation) &&
271 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
272 // if the valid flag is not set, don't load the address and name
273 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
274 return;
275 }
fredc0f420372012-04-12 00:02:00 -0700276 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
277 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
Zhihai Xud31c3222012-10-31 16:08:57 -0700278 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
fredc0f420372012-04-12 00:02:00 -0700279 }
280
fredc649fe492012-04-19 01:07:18 -0700281 /**
282 * Save the Bluetooth name and address in the persistent store.
283 * Only non-null values will be saved.
284 * @param name
285 * @param address
286 */
fredc0f420372012-04-12 00:02:00 -0700287 private void storeNameAndAddress(String name, String address) {
288 if (name != null) {
289 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700290 mName = name;
fredc649fe492012-04-19 01:07:18 -0700291 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
292 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700293 }
294
295 if (address != null) {
296 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700297 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700298 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
299 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700300 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700301
302 if ((name != null) && (address != null)) {
303 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
304 }
fredc0f420372012-04-12 00:02:00 -0700305 }
306
307 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
fredc0f420372012-04-12 00:02:00 -0700308 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
309 msg.obj = callback;
310 mHandler.sendMessage(msg);
311 synchronized(mConnection) {
312 return mBluetooth;
313 }
314 }
315
316 public void unregisterAdapter(IBluetoothManagerCallback callback) {
317 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
318 "Need BLUETOOTH permission");
319 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
320 msg.obj = callback;
321 mHandler.sendMessage(msg);
322 }
323
324 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
325 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
326 "Need BLUETOOTH permission");
327 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
328 msg.obj = callback;
329 mHandler.sendMessage(msg);
330 }
331
332 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
333 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
334 "Need BLUETOOTH permission");
335 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
336 msg.obj = callback;
337 mHandler.sendMessage(msg);
338 }
339
340 public boolean isEnabled() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800341 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
342 (!checkIfCallerIsForegroundUser())) {
343 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700344 return false;
345 }
346
fredc0f420372012-04-12 00:02:00 -0700347 synchronized(mConnection) {
348 try {
349 return (mBluetooth != null && mBluetooth.isEnabled());
350 } catch (RemoteException e) {
351 Log.e(TAG, "isEnabled()", e);
352 }
353 }
354 return false;
355 }
356
357 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700358 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700359 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
360 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700361 }
fredc0f420372012-04-12 00:02:00 -0700362 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
363 mHandler.sendMessage(msg);
364 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700365 public boolean enableNoAutoConnect()
366 {
367 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
368 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700369
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700370 if (DBG) {
371 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
372 " mBinding = " + mBinding);
373 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800374 int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
375
376 if (callingAppId != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700377 throw new SecurityException("no permission to enable Bluetooth quietly");
378 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800379
Zhihai Xu401202b2012-12-03 11:36:21 -0800380 synchronized(mReceiver) {
381 mQuietEnableExternal = true;
382 mEnableExternal = true;
383 sendEnableMsg(true);
384 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700385 return true;
386
387 }
fredc0f420372012-04-12 00:02:00 -0700388 public boolean enable() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800389 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
390 (!checkIfCallerIsForegroundUser())) {
391 Log.w(TAG,"enable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700392 return false;
fredcf2458862012-04-16 15:18:27 -0700393 }
394
Zhihai Xu401202b2012-12-03 11:36:21 -0800395 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
396 "Need BLUETOOTH ADMIN permission");
397 if (DBG) {
398 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
399 " mBinding = " + mBinding);
400 }
401
402 synchronized(mReceiver) {
403 mQuietEnableExternal = false;
404 mEnableExternal = true;
405 // waive WRITE_SECURE_SETTINGS permission check
406 long callingIdentity = Binder.clearCallingIdentity();
407 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
408 Binder.restoreCallingIdentity(callingIdentity);
409 sendEnableMsg(false);
410 }
411 return true;
fredc0f420372012-04-12 00:02:00 -0700412 }
413
414 public boolean disable(boolean persist) {
415 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
416 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700417
Zhihai Xu6eb76522012-11-29 15:41:04 -0800418 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
419 (!checkIfCallerIsForegroundUser())) {
420 Log.w(TAG,"disable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700421 return false;
422 }
423
fredcf2458862012-04-16 15:18:27 -0700424 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700425 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
426 " mBinding = " + mBinding);
427 }
fredcf2458862012-04-16 15:18:27 -0700428
Zhihai Xu401202b2012-12-03 11:36:21 -0800429 synchronized(mReceiver) {
430 if (persist) {
431 // waive WRITE_SECURE_SETTINGS permission check
432 long callingIdentity = Binder.clearCallingIdentity();
433 persistBluetoothSetting(BLUETOOTH_OFF);
434 Binder.restoreCallingIdentity(callingIdentity);
435 }
436 mEnableExternal = false;
437 sendDisableMsg();
438 }
fredc0f420372012-04-12 00:02:00 -0700439 return true;
440 }
441
fredc649fe492012-04-19 01:07:18 -0700442 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700443 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700444 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
445 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700446 }
447
fredc0f420372012-04-12 00:02:00 -0700448 synchronized (mConnection) {
449 if (mUnbinding) return;
450 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700451 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700452 if (!mConnection.isGetNameAddressOnly()) {
453 //Unregister callback object
454 try {
455 mBluetooth.unregisterCallback(mBluetoothCallback);
456 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700457 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700458 }
459 }
fredc0f420372012-04-12 00:02:00 -0700460 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700461 mBluetooth = null;
462 //Unbind
fredc0f420372012-04-12 00:02:00 -0700463 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700464 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700465 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700466 } else {
467 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700468 }
469 }
470 }
471
Matthew Xieddf7e472013-03-01 18:41:02 -0800472 public IBluetoothGatt getBluetoothGatt() {
473 // sync protection
474 return mBluetoothGatt;
475 }
476
fredcbf072a72012-05-09 16:52:50 -0700477 private void sendBluetoothStateCallback(boolean isUp) {
478 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700479 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700480 for (int i=0; i <n;i++) {
481 try {
482 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
483 } catch (RemoteException e) {
484 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
485 }
486 }
487 mStateChangeCallbacks.finishBroadcast();
488 }
489
490 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700491 * Inform BluetoothAdapter instances that Adapter service is up
492 */
493 private void sendBluetoothServiceUpCallback() {
494 if (!mConnection.isGetNameAddressOnly()) {
495 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
496 int n = mCallbacks.beginBroadcast();
497 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
498 for (int i=0; i <n;i++) {
499 try {
500 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
501 } catch (RemoteException e) {
502 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
503 }
504 }
505 mCallbacks.finishBroadcast();
506 }
507 }
508 /**
fredcbf072a72012-05-09 16:52:50 -0700509 * Inform BluetoothAdapter instances that Adapter service is down
510 */
511 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700512 if (!mConnection.isGetNameAddressOnly()) {
513 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
514 int n = mCallbacks.beginBroadcast();
515 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
516 for (int i=0; i <n;i++) {
517 try {
518 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
519 } catch (RemoteException e) {
520 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
521 }
522 }
523 mCallbacks.finishBroadcast();
524 }
525 }
fredc0f420372012-04-12 00:02:00 -0700526 public String getAddress() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800527 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
528 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700529
Zhihai Xu6eb76522012-11-29 15:41:04 -0800530 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
531 (!checkIfCallerIsForegroundUser())) {
532 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
533 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700534 }
535
fredc116d1d462012-04-20 14:47:08 -0700536 synchronized(mConnection) {
537 if (mBluetooth != null) {
538 try {
539 return mBluetooth.getAddress();
540 } catch (RemoteException e) {
541 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
542 }
543 }
544 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700545 // mAddress is accessed from outside.
546 // It is alright without a lock. Here, bluetooth is off, no other thread is
547 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700548 return mAddress;
549 }
fredc649fe492012-04-19 01:07:18 -0700550
fredc0f420372012-04-12 00:02:00 -0700551 public String getName() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800552 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
553 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700554
Zhihai Xu6eb76522012-11-29 15:41:04 -0800555 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
556 (!checkIfCallerIsForegroundUser())) {
557 Log.w(TAG,"getName(): not allowed for non-active and non system user");
558 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700559 }
560
fredc116d1d462012-04-20 14:47:08 -0700561 synchronized(mConnection) {
562 if (mBluetooth != null) {
563 try {
564 return mBluetooth.getName();
565 } catch (RemoteException e) {
566 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
567 }
568 }
569 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700570 // mName is accessed from outside.
571 // It alright without a lock. Here, bluetooth is off, no other thread is
572 // changing mName
fredc0f420372012-04-12 00:02:00 -0700573 return mName;
574 }
575
fredc0f420372012-04-12 00:02:00 -0700576 private class BluetoothServiceConnection implements ServiceConnection {
577
578 private boolean mGetNameAddressOnly;
579
580 public void setGetNameAddressOnly(boolean getOnly) {
581 mGetNameAddressOnly = getOnly;
582 }
583
584 public boolean isGetNameAddressOnly() {
585 return mGetNameAddressOnly;
586 }
587
588 public void onServiceConnected(ComponentName className, IBinder service) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800589 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700590 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800591 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
592 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
593 msg.arg1 = SERVICE_IBLUETOOTH;
594 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
595 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
596 msg.arg1 = SERVICE_IBLUETOOTHGATT;
597 } else {
598 Log.e(TAG, "Unknown service connected: " + className.getClassName());
599 return;
600 }
fredc0f420372012-04-12 00:02:00 -0700601 msg.obj = service;
602 mHandler.sendMessage(msg);
603 }
604
605 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700606 // Called if we unexpected disconnected.
Matthew Xieddf7e472013-03-01 18:41:02 -0800607 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
608 className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700609 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800610 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
611 msg.arg1 = SERVICE_IBLUETOOTH;
612 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
613 msg.arg1 = SERVICE_IBLUETOOTHGATT;
614 } else {
615 Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
616 return;
617 }
fredc0f420372012-04-12 00:02:00 -0700618 mHandler.sendMessage(msg);
619 }
620 }
621
622 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
623
Zhihai Xu40874a02012-10-08 17:57:03 -0700624 private class BluetoothHandler extends Handler {
625 public BluetoothHandler(Looper looper) {
626 super(looper);
627 }
628
fredc0f420372012-04-12 00:02:00 -0700629 @Override
630 public void handleMessage(Message msg) {
631 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700632 switch (msg.what) {
633 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700634 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700635 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700636 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -0700637 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -0700638 if (DBG) Log.d(TAG, "Binding to service to get name and address");
639 mConnection.setGetNameAddressOnly(true);
640 //Start bind timeout and bind
641 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
642 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
643 Intent i = new Intent(IBluetooth.class.getName());
Amith Yamasani27b89e62013-01-16 12:30:11 -0800644 if (!mContext.bindServiceAsUser(i, mConnection,
645 Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700646 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
647 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700648 } else {
649 mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700650 }
651 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700652 else {
653 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -0700654 saveMsg.arg1 = 0;
655 if (mBluetooth != null) {
656 mHandler.sendMessage(saveMsg);
657 } else {
658 // if enable is also called to bind the service
659 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
660 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
661 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700662 }
fredc0f420372012-04-12 00:02:00 -0700663 }
fredc649fe492012-04-19 01:07:18 -0700664 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700665 }
fredc0f420372012-04-12 00:02:00 -0700666 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -0700667 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -0700668 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700669 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700670 if (!mEnable && mBluetooth != null) {
671 try {
672 mBluetooth.enable();
673 } catch (RemoteException e) {
674 Log.e(TAG,"Unable to call enable()",e);
675 }
676 }
677 }
678 if (mBluetooth != null) waitForOnOff(true, false);
679 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700680 if (mBluetooth != null) {
681 String name = null;
682 String address = null;
683 try {
684 name = mBluetooth.getName();
685 address = mBluetooth.getAddress();
686 } catch (RemoteException re) {
687 Log.e(TAG,"",re);
688 }
fredc0f420372012-04-12 00:02:00 -0700689
Matthew Xiecdce0b92012-07-12 19:06:15 -0700690 if (name != null && address != null) {
691 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -0700692 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700693 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700694 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700695 } else {
696 if (msg.arg1 < MAX_SAVE_RETRIES) {
697 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
698 retryMsg.arg1= 1+msg.arg1;
699 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
700 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
701 } else {
702 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -0700703 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700704 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700705 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700706 }
fredc0f420372012-04-12 00:02:00 -0700707 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700708 if (!mEnable) {
709 try {
710 mBluetooth.disable();
711 } catch (RemoteException e) {
712 Log.e(TAG,"Unable to call disable()",e);
713 }
714 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700715 } else {
716 // rebind service by Request GET NAME AND ADDRESS
717 // if service is unbinded by disable or
718 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
719 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
720 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -0700721 }
722 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700723 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
724 if (unbind) {
725 unbindAndFinish();
726 }
fredc649fe492012-04-19 01:07:18 -0700727 break;
fredc649fe492012-04-19 01:07:18 -0700728 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700729 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700730 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700731 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700732 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700733 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
734 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800735 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -0700736 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700737
fredc0f420372012-04-12 00:02:00 -0700738 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -0700739 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
740 if (mEnable && mBluetooth != null) {
741 waitForOnOff(true, false);
742 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800743 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700744 waitForOnOff(false, false);
745 } else {
746 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800747 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700748 }
fredc0f420372012-04-12 00:02:00 -0700749 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700750
fredc0f420372012-04-12 00:02:00 -0700751 case MESSAGE_REGISTER_ADAPTER:
752 {
753 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700754 boolean added = mCallbacks.register(callback);
755 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700756 }
757 break;
758 case MESSAGE_UNREGISTER_ADAPTER:
759 {
760 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700761 boolean removed = mCallbacks.unregister(callback);
762 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700763 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700764 }
fredc0f420372012-04-12 00:02:00 -0700765 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
766 {
767 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700768 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700769 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700770 }
fredc0f420372012-04-12 00:02:00 -0700771 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
772 {
773 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700774 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700775 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700776 }
fredc0f420372012-04-12 00:02:00 -0700777 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
778 {
Matthew Xieddf7e472013-03-01 18:41:02 -0800779 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
fredc0f420372012-04-12 00:02:00 -0700780
781 IBinder service = (IBinder) msg.obj;
782 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800783 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
784 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
785 break;
786 } // else must be SERVICE_IBLUETOOTH
787
788 //Remove timeout
789 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
790
fredc0f420372012-04-12 00:02:00 -0700791 mBinding = false;
792 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700793
Matthew Xiecdce0b92012-07-12 19:06:15 -0700794 if (mConnection.isGetNameAddressOnly()) {
795 //Request GET NAME AND ADDRESS
796 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
797 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -0700798 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700799 }
fredc0f420372012-04-12 00:02:00 -0700800
Zhihai Xu40874a02012-10-08 17:57:03 -0700801 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700802 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700803 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700804 mBluetooth.registerCallback(mBluetoothCallback);
805 } catch (RemoteException re) {
806 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700807 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700808 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -0700809 sendBluetoothServiceUpCallback();
810
Matthew Xiecdce0b92012-07-12 19:06:15 -0700811 //Do enable request
812 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700813 if (mQuietEnable == false) {
814 if(!mBluetooth.enable()) {
815 Log.e(TAG,"IBluetooth.enable() returned false");
816 }
817 }
818 else
819 {
820 if(!mBluetooth.enableNoAutoConnect()) {
821 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
822 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700823 }
824 } catch (RemoteException e) {
825 Log.e(TAG,"Unable to call enable()",e);
826 }
Freda8c6df02012-07-11 10:25:23 -0700827 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700828
829 if (!mEnable) {
830 waitForOnOff(true, false);
Zhihai Xu401202b2012-12-03 11:36:21 -0800831 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700832 waitForOnOff(false, false);
833 }
fredc649fe492012-04-19 01:07:18 -0700834 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700835 }
fredc649fe492012-04-19 01:07:18 -0700836 case MESSAGE_TIMEOUT_BIND: {
837 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700838 synchronized(mConnection) {
839 mBinding = false;
840 }
fredc649fe492012-04-19 01:07:18 -0700841 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700842 }
fredcbf072a72012-05-09 16:52:50 -0700843 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700844 {
fredcbf072a72012-05-09 16:52:50 -0700845 int prevState = msg.arg1;
846 int newState = msg.arg2;
847 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -0700848 mState = newState;
849 bluetoothStateChangeHandler(prevState, newState);
fredc649fe492012-04-19 01:07:18 -0700850 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700851 }
fredc0f420372012-04-12 00:02:00 -0700852 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
853 {
Matthew Xieddf7e472013-03-01 18:41:02 -0800854 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530855 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800856 if (msg.arg1 == SERVICE_IBLUETOOTH) {
857 // if service is unbinded already, do nothing and return
858 if (mBluetooth == null) break;
859 mBluetooth = null;
860 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
861 mBluetoothGatt = null;
862 break;
863 } else {
864 Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
865 break;
866 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530867 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700868
869 if (mEnable) {
870 mEnable = false;
871 // Send a Bluetooth Restart message
872 Message restartMsg = mHandler.obtainMessage(
873 MESSAGE_RESTART_BLUETOOTH_SERVICE);
874 mHandler.sendMessageDelayed(restartMsg,
875 SERVICE_RESTART_TIME_MS);
876 }
877
878 if (!mConnection.isGetNameAddressOnly()) {
879 sendBluetoothServiceDownCallback();
880
881 // Send BT state broadcast to update
882 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800883 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
884 (mState == BluetoothAdapter.STATE_ON)) {
885 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
886 BluetoothAdapter.STATE_TURNING_OFF);
887 mState = BluetoothAdapter.STATE_TURNING_OFF;
888 }
889 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
890 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
891 BluetoothAdapter.STATE_OFF);
892 }
893
894 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -0700895 mState = BluetoothAdapter.STATE_OFF;
896 }
fredc649fe492012-04-19 01:07:18 -0700897 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700898 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530899 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
900 {
901 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
902 +" Restart IBluetooth service");
903 /* Enable without persisting the setting as
904 it doesnt change when IBluetooth
905 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -0700906 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800907 handleEnable(mQuietEnable);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530908 break;
909 }
910
fredc0f420372012-04-12 00:02:00 -0700911 case MESSAGE_TIMEOUT_UNBIND:
912 {
fredc649fe492012-04-19 01:07:18 -0700913 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700914 synchronized(mConnection) {
915 mUnbinding = false;
916 }
fredc649fe492012-04-19 01:07:18 -0700917 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700918 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700919
920 case MESSAGE_USER_SWITCHED:
921 {
922 if (DBG) {
923 Log.d(TAG, "MESSAGE_USER_SWITCHED");
924 }
925 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
926 /* disable and enable BT when detect a user switch */
927 if (mEnable && mBluetooth != null) {
928 synchronized (mConnection) {
929 if (mBluetooth != null) {
930 //Unregister callback object
931 try {
932 mBluetooth.unregisterCallback(mBluetoothCallback);
933 } catch (RemoteException re) {
934 Log.e(TAG, "Unable to unregister",re);
935 }
936 }
937 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800938
939 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
940 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
941 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
942 mState = BluetoothAdapter.STATE_OFF;
943 }
944 if (mState == BluetoothAdapter.STATE_OFF) {
945 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
946 mState = BluetoothAdapter.STATE_TURNING_ON;
947 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700948
949 waitForOnOff(true, false);
950
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800951 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
952 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
953 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700954
955 // disable
Zhihai Xu401202b2012-12-03 11:36:21 -0800956 handleDisable();
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800957 // Pbap service need receive STATE_TURNING_OFF intent to close
958 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
959 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700960
961 waitForOnOff(false, true);
962
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800963 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -0700964 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700965 sendBluetoothServiceDownCallback();
966 synchronized (mConnection) {
967 if (mBluetooth != null) {
968 mBluetooth = null;
969 //Unbind
970 mContext.unbindService(mConnection);
971 }
972 }
973 SystemClock.sleep(100);
974
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800975 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
976 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -0700977 // enable
Zhihai Xu401202b2012-12-03 11:36:21 -0800978 handleEnable(mQuietEnable);
Zhihai Xu40874a02012-10-08 17:57:03 -0700979 } else if (mBinding || mBluetooth != null) {
980 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
981 userMsg.arg2 = 1 + msg.arg2;
982 // if user is switched when service is being binding
983 // delay sending MESSAGE_USER_SWITCHED
984 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
985 if (DBG) {
986 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
987 }
988 }
989 break;
990 }
fredc0f420372012-04-12 00:02:00 -0700991 }
992 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700993 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700994
Zhihai Xu401202b2012-12-03 11:36:21 -0800995 private void handleEnable(boolean quietMode) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700996 mQuietEnable = quietMode;
997
Matthew Xiecdce0b92012-07-12 19:06:15 -0700998 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700999 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001000 //Start bind timeout and bind
1001 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1002 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1003 mConnection.setGetNameAddressOnly(false);
1004 Intent i = new Intent(IBluetooth.class.getName());
Amith Yamasani27b89e62013-01-16 12:30:11 -08001005 if (!mContext.bindServiceAsUser(i, mConnection,Context.BIND_AUTO_CREATE,
1006 UserHandle.CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001007 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
1008 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -07001009 } else {
1010 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001011 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001012 } else if (mBluetooth != null) {
1013 if (mConnection.isGetNameAddressOnly()) {
1014 // if GetNameAddressOnly is set, we can clear this flag,
1015 // so the service won't be unbind
1016 // after name and address are saved
1017 mConnection.setGetNameAddressOnly(false);
1018 //Register callback object
1019 try {
1020 mBluetooth.registerCallback(mBluetoothCallback);
1021 } catch (RemoteException re) {
1022 Log.e(TAG, "Unable to register BluetoothCallback",re);
1023 }
1024 //Inform BluetoothAdapter instances that service is up
1025 sendBluetoothServiceUpCallback();
1026 }
1027
Matthew Xiecdce0b92012-07-12 19:06:15 -07001028 //Enable bluetooth
1029 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001030 if (!mQuietEnable) {
1031 if(!mBluetooth.enable()) {
1032 Log.e(TAG,"IBluetooth.enable() returned false");
1033 }
1034 }
1035 else {
1036 if(!mBluetooth.enableNoAutoConnect()) {
1037 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1038 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001039 }
1040 } catch (RemoteException e) {
1041 Log.e(TAG,"Unable to call enable()",e);
1042 }
1043 }
1044 }
1045 }
1046
Zhihai Xu401202b2012-12-03 11:36:21 -08001047 private void handleDisable() {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001048 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001049 // don't need to disable if GetNameAddressOnly is set,
1050 // service will be unbinded after Name and Address are saved
1051 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001052 if (DBG) Log.d(TAG,"Sending off request.");
1053
1054 try {
1055 if(!mBluetooth.disable()) {
1056 Log.e(TAG,"IBluetooth.disable() returned false");
1057 }
1058 } catch (RemoteException e) {
1059 Log.e(TAG,"Unable to call disable()",e);
1060 }
1061 }
1062 }
1063 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001064
1065 private boolean checkIfCallerIsForegroundUser() {
1066 int foregroundUser;
1067 int callingUser = UserHandle.getCallingUserId();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001068 int callingUid = Binder.getCallingUid();
Zhihai Xu40874a02012-10-08 17:57:03 -07001069 long callingIdentity = Binder.clearCallingIdentity();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001070 int callingAppId = UserHandle.getAppId(callingUid);
Zhihai Xu40874a02012-10-08 17:57:03 -07001071 boolean valid = false;
1072 try {
1073 foregroundUser = ActivityManager.getCurrentUser();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001074 valid = (callingUser == foregroundUser) ||
1075 callingAppId == Process.NFC_UID;
Zhihai Xu40874a02012-10-08 17:57:03 -07001076 if (DBG) {
1077 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1078 + " callingUser=" + callingUser
1079 + " foregroundUser=" + foregroundUser);
1080 }
1081 } finally {
1082 Binder.restoreCallingIdentity(callingIdentity);
1083 }
1084 return valid;
1085 }
1086
Zhihai Xu40874a02012-10-08 17:57:03 -07001087 private void bluetoothStateChangeHandler(int prevState, int newState) {
1088 if (prevState != newState) {
1089 //Notify all proxy objects first of adapter state change
1090 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
1091 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1092 sendBluetoothStateCallback(isUp);
1093
Matthew Xieddf7e472013-03-01 18:41:02 -08001094 if (isUp) {
1095 // connect to GattService
Matthew Xie32ab77b2013-05-08 19:26:57 -07001096 if (mContext.getPackageManager().hasSystemFeature(
1097 PackageManager.FEATURE_BLUETOOTH_LE)) {
1098 Intent i = new Intent(IBluetoothGatt.class.getName());
1099 if (!mContext.bindServiceAsUser(i, mConnection, Context.BIND_AUTO_CREATE,
1100 UserHandle.CURRENT)) {
1101 Log.e(TAG, "Fail to bind to: " + IBluetoothGatt.class.getName());
1102 }
Matthew Xieddf7e472013-03-01 18:41:02 -08001103 }
1104 } else {
1105 //If Bluetooth is off, send service down event to proxy objects, and unbind
1106 if (!isUp && canUnbindBluetoothService()) {
1107 sendBluetoothServiceDownCallback();
1108 unbindAndFinish();
1109 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001110 }
1111 }
1112
1113 //Send broadcast message to everyone else
1114 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1115 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1116 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1117 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1118 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
1119 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1120 BLUETOOTH_PERM);
1121 }
1122 }
1123
1124 /**
1125 * if on is true, wait for state become ON
1126 * if off is true, wait for state become OFF
1127 * if both on and off are false, wait for state not ON
1128 */
1129 private boolean waitForOnOff(boolean on, boolean off) {
1130 int i = 0;
1131 while (i < 10) {
1132 synchronized(mConnection) {
1133 try {
1134 if (mBluetooth == null) break;
1135 if (on) {
1136 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1137 } else if (off) {
1138 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001139 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001140 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001141 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001142 } catch (RemoteException e) {
1143 Log.e(TAG, "getState()", e);
1144 break;
1145 }
1146 }
1147 if (on || off) {
1148 SystemClock.sleep(300);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001149 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001150 SystemClock.sleep(50);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001151 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001152 i++;
1153 }
1154 Log.e(TAG,"waitForOnOff time out");
1155 return false;
1156 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001157
Zhihai Xu401202b2012-12-03 11:36:21 -08001158 private void sendDisableMsg() {
1159 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1160 }
1161
1162 private void sendEnableMsg(boolean quietMode) {
1163 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1164 quietMode ? 1 : 0, 0));
1165 }
1166
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001167 private boolean canUnbindBluetoothService() {
1168 synchronized(mConnection) {
1169 //Only unbind with mEnable flag not set
1170 //For race condition: disable and enable back-to-back
1171 //Avoid unbind right after enable due to callback from disable
1172 //Only unbind with Bluetooth at OFF state
1173 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1174 try {
1175 if (mEnable || (mBluetooth == null)) return false;
1176 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1177 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1178 } catch (RemoteException e) {
1179 Log.e(TAG, "getState()", e);
1180 }
1181 }
1182 return false;
1183 }
fredc0f420372012-04-12 00:02:00 -07001184}