blob: f5d27f952be1a248c708bd11fa63fda1c069052b [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;
Benjamin Franze8b98922014-11-12 15:57:54 +000021import android.bluetooth.BluetoothProfile;
fredc0f420372012-04-12 00:02:00 -070022import android.bluetooth.IBluetooth;
Matthew Xieddf7e472013-03-01 18:41:02 -080023import android.bluetooth.IBluetoothGatt;
fredcbf072a72012-05-09 16:52:50 -070024import android.bluetooth.IBluetoothCallback;
Benjamin Franze8b98922014-11-12 15:57:54 +000025import android.bluetooth.IBluetoothHeadset;
fredc0f420372012-04-12 00:02:00 -070026import android.bluetooth.IBluetoothManager;
27import android.bluetooth.IBluetoothManagerCallback;
Benjamin Franze8b98922014-11-12 15:57:54 +000028import android.bluetooth.IBluetoothProfileServiceConnection;
fredc0f420372012-04-12 00:02:00 -070029import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070030import android.content.BroadcastReceiver;
31import android.content.ComponentName;
32import android.content.ContentResolver;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.ServiceConnection;
Matthew Xie32ab77b2013-05-08 19:26:57 -070037import android.content.pm.PackageManager;
Benjamin Franze8b98922014-11-12 15:57:54 +000038import android.content.pm.UserInfo;
Zhihai Xu40874a02012-10-08 17:57:03 -070039import android.os.Binder;
fredc0f420372012-04-12 00:02:00 -070040import android.os.Handler;
fredc0f420372012-04-12 00:02:00 -070041import android.os.IBinder;
Zhihai Xu40874a02012-10-08 17:57:03 -070042import android.os.Looper;
fredc0f420372012-04-12 00:02:00 -070043import android.os.Message;
Andre Eisenbach14dcb5f2014-12-05 09:31:30 -080044import android.os.ParcelFileDescriptor;
Zhihai Xu40874a02012-10-08 17:57:03 -070045import android.os.Process;
fredcd6883532012-04-25 17:46:13 -070046import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070047import android.os.RemoteException;
Zhihai Xu40874a02012-10-08 17:57:03 -070048import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070049import android.os.UserHandle;
Benjamin Franze8b98922014-11-12 15:57:54 +000050import android.os.UserManager;
fredc0f420372012-04-12 00:02:00 -070051import android.provider.Settings;
Wei Wang67d84162015-04-26 17:04:29 -070052import android.provider.Settings.SettingNotFoundException;
fredc0f420372012-04-12 00:02:00 -070053import android.util.Log;
Mike Lockwood726d4de2014-10-28 14:06:28 -070054
55import java.io.FileDescriptor;
Andre Eisenbach14dcb5f2014-12-05 09:31:30 -080056import java.io.IOException;
Mike Lockwood726d4de2014-10-28 14:06:28 -070057import java.io.PrintWriter;
58
Benjamin Franze8b98922014-11-12 15:57:54 +000059import java.util.HashMap;
60import java.util.Map;
Benjamin Franze8b98922014-11-12 15:57:54 +000061
Nitin Arora6ddbb5e2015-03-02 15:03:51 -080062import java.util.*;
fredc0f420372012-04-12 00:02:00 -070063class BluetoothManagerService extends IBluetoothManager.Stub {
64 private static final String TAG = "BluetoothManagerService";
65 private static final boolean DBG = true;
66
fredc0f420372012-04-12 00:02:00 -070067 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
68 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070069 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
70 private static final String EXTRA_ACTION="action";
Zhihai Xud31c3222012-10-31 16:08:57 -070071 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
fredc0f420372012-04-12 00:02:00 -070072 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
73 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070074 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
75 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053076 //Maximum msec to wait for service restart
77 private static final int SERVICE_RESTART_TIME_MS = 200;
Zhihai Xudd9d17d2013-01-08 17:05:58 -080078 //Maximum msec to wait for restart due to error
79 private static final int ERROR_RESTART_TIME_MS = 3000;
Zhihai Xu40874a02012-10-08 17:57:03 -070080 //Maximum msec to delay MESSAGE_USER_SWITCHED
81 private static final int USER_SWITCHED_TIME_MS = 200;
Benjamin Franze8b98922014-11-12 15:57:54 +000082 // Delay for the addProxy function in msec
83 private static final int ADD_PROXY_DELAY_MS = 100;
fredc0f420372012-04-12 00:02:00 -070084
85 private static final int MESSAGE_ENABLE = 1;
86 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070087 private static final int MESSAGE_REGISTER_ADAPTER = 20;
88 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
89 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
90 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
91 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
92 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053093 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070094 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070095 private static final int MESSAGE_TIMEOUT_BIND =100;
96 private static final int MESSAGE_TIMEOUT_UNBIND =101;
97 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
98 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
Zhihai Xu40874a02012-10-08 17:57:03 -070099 private static final int MESSAGE_USER_SWITCHED = 300;
Benjamin Franze8b98922014-11-12 15:57:54 +0000100 private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
101 private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
fredc0f420372012-04-12 00:02:00 -0700102 private static final int MAX_SAVE_RETRIES=3;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800103 private static final int MAX_ERROR_RESTART_RETRIES=6;
104
Zhihai Xu401202b2012-12-03 11:36:21 -0800105 // Bluetooth persisted setting is off
106 private static final int BLUETOOTH_OFF=0;
107 // Bluetooth persisted setting is on
108 // and Airplane mode won't affect Bluetooth state at start up
109 private static final int BLUETOOTH_ON_BLUETOOTH=1;
110 // Bluetooth persisted setting is on
111 // but Airplane mode will affect Bluetooth state at start up
112 // and Airplane mode will have higher priority.
113 private static final int BLUETOOTH_ON_AIRPLANE=2;
fredc0f420372012-04-12 00:02:00 -0700114
Matthew Xieddf7e472013-03-01 18:41:02 -0800115 private static final int SERVICE_IBLUETOOTH = 1;
116 private static final int SERVICE_IBLUETOOTHGATT = 2;
117
fredc0f420372012-04-12 00:02:00 -0700118 private final Context mContext;
Nitin Arorad055adb2015-03-02 15:03:51 -0800119 private static int mBleAppCount = 0;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700120
121 // Locks are not provided for mName and mAddress.
122 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -0700123 private String mAddress;
124 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -0700125 private final ContentResolver mContentResolver;
126 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
127 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -0700128 private IBluetooth mBluetooth;
Matthew Xieddf7e472013-03-01 18:41:02 -0800129 private IBluetoothGatt mBluetoothGatt;
fredc649fe492012-04-19 01:07:18 -0700130 private boolean mBinding;
131 private boolean mUnbinding;
Zhihai Xu401202b2012-12-03 11:36:21 -0800132 // used inside handler thread
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700133 private boolean mQuietEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800134 // configuarion from external IBinder call which is used to
135 // synchronize with broadcast receiver.
136 private boolean mQuietEnableExternal;
137 // configuarion from external IBinder call which is used to
138 // synchronize with broadcast receiver.
139 private boolean mEnableExternal;
140 // used inside handler thread
Zhihai Xu40874a02012-10-08 17:57:03 -0700141 private boolean mEnable;
142 private int mState;
Zhihai Xu40874a02012-10-08 17:57:03 -0700143 private final BluetoothHandler mHandler;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800144 private int mErrorRecoveryRetryCounter;
Adrian Roosbd9a9a52014-08-18 15:31:57 +0200145 private final int mSystemUiUid;
fredc0f420372012-04-12 00:02:00 -0700146
Benjamin Franze8b98922014-11-12 15:57:54 +0000147 // Save a ProfileServiceConnections object for each of the bound
148 // bluetooth profile services
149 private final Map <Integer, ProfileServiceConnections> mProfileServices =
150 new HashMap <Integer, ProfileServiceConnections>();
151
fredc649fe492012-04-19 01:07:18 -0700152 private void registerForAirplaneMode(IntentFilter filter) {
153 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700154 final String airplaneModeRadios = Settings.Global.getString(resolver,
155 Settings.Global.AIRPLANE_MODE_RADIOS);
156 final String toggleableRadios = Settings.Global.getString(resolver,
157 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700158 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700159 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700160 if (mIsAirplaneSensitive) {
161 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
162 }
163 }
164
fredcbf072a72012-05-09 16:52:50 -0700165 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
166 @Override
167 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
168 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
169 mHandler.sendMessage(msg);
170 }
171 };
172
173 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700174 @Override
175 public void onReceive(Context context, Intent intent) {
176 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700177 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700178 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700179 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700180 if (newName != null) {
181 storeNameAndAddress(newName, null);
182 }
fredc649fe492012-04-19 01:07:18 -0700183 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
Zhihai Xu401202b2012-12-03 11:36:21 -0800184 synchronized(mReceiver) {
185 if (isBluetoothPersistedStateOn()) {
186 if (isAirplaneModeOn()) {
187 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
188 } else {
189 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
190 }
191 }
Nitin Arorad055adb2015-03-02 15:03:51 -0800192
193 int st = BluetoothAdapter.STATE_OFF;
194 if (mBluetooth != null) {
195 try {
196 st = mBluetooth.getState();
197 } catch (RemoteException e) {
198 Log.e(TAG,"Unable to call getState", e);
199 }
200 }
201 Log.d(TAG, "state" + st);
202
Zhihai Xu401202b2012-12-03 11:36:21 -0800203 if (isAirplaneModeOn()) {
Nitin Arorad055adb2015-03-02 15:03:51 -0800204 // Clear registered LE apps to force shut-off
205 synchronized (this) {
206 mBleAppCount = 0;
207 }
208 if (st == BluetoothAdapter.STATE_BLE_ON) {
209 //if state is BLE_ON make sure you trigger disableBLE part
210 try {
211 if (mBluetooth != null) {
212 mBluetooth.onBrEdrDown();
213 mEnableExternal = false;
214 }
215 } catch(RemoteException e) {
216 Log.e(TAG,"Unable to call onBrEdrDown", e);
217 }
218 } else if (st == BluetoothAdapter.STATE_ON){
219 // disable without persisting the setting
220 Log.d(TAG, "Calling disable");
221 sendDisableMsg();
222 }
Zhihai Xu401202b2012-12-03 11:36:21 -0800223 } else if (mEnableExternal) {
224 // enable without persisting the setting
Nitin Arorad055adb2015-03-02 15:03:51 -0800225 Log.d(TAG, "Calling enable");
Zhihai Xu401202b2012-12-03 11:36:21 -0800226 sendEnableMsg(mQuietEnableExternal);
227 }
fredc649fe492012-04-19 01:07:18 -0700228 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700229 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
230 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
231 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Zhihai Xu401202b2012-12-03 11:36:21 -0800232 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
233 synchronized(mReceiver) {
234 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
235 //Enable
236 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
237 sendEnableMsg(mQuietEnableExternal);
238 }
239 }
fredc0f420372012-04-12 00:02:00 -0700240 }
241 }
242 };
243
244 BluetoothManagerService(Context context) {
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700245 mHandler = new BluetoothHandler(IoThread.get().getLooper());
Zhihai Xu40874a02012-10-08 17:57:03 -0700246
fredc0f420372012-04-12 00:02:00 -0700247 mContext = context;
248 mBluetooth = null;
Nitin Arorad055adb2015-03-02 15:03:51 -0800249 mBluetoothGatt = null;
fredc0f420372012-04-12 00:02:00 -0700250 mBinding = false;
251 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700252 mEnable = false;
253 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu401202b2012-12-03 11:36:21 -0800254 mQuietEnableExternal = false;
255 mEnableExternal = false;
fredc0f420372012-04-12 00:02:00 -0700256 mAddress = null;
257 mName = null;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800258 mErrorRecoveryRetryCounter = 0;
fredc0f420372012-04-12 00:02:00 -0700259 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700260 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
261 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Zhihai Xu401202b2012-12-03 11:36:21 -0800262 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700263 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700264 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700265 registerForAirplaneMode(filter);
Dianne Hackbornd83a0962014-05-02 16:28:33 -0700266 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Matthew Xie6fde3092012-07-11 17:10:07 -0700267 mContext.registerReceiver(mReceiver, filter);
fredc0f420372012-04-12 00:02:00 -0700268 loadStoredNameAndAddress();
Zhihai Xu401202b2012-12-03 11:36:21 -0800269 if (isBluetoothPersistedStateOn()) {
270 mEnableExternal = true;
fredc0f420372012-04-12 00:02:00 -0700271 }
Adrian Roosbd9a9a52014-08-18 15:31:57 +0200272
273 int sysUiUid = -1;
274 try {
275 sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui",
276 UserHandle.USER_OWNER);
277 } catch (PackageManager.NameNotFoundException e) {
278 Log.wtf(TAG, "Unable to resolve SystemUI's UID.", e);
279 }
280 mSystemUiUid = sysUiUid;
fredc0f420372012-04-12 00:02:00 -0700281 }
282
fredc649fe492012-04-19 01:07:18 -0700283 /**
284 * Returns true if airplane mode is currently on
285 */
286 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700287 return Settings.Global.getInt(mContext.getContentResolver(),
288 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700289 }
290
291 /**
292 * Returns true if the Bluetooth saved state is "on"
293 */
294 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700295 return Settings.Global.getInt(mContentResolver,
Zhihai Xu401202b2012-12-03 11:36:21 -0800296 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
297 }
298
299 /**
300 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
301 */
302 private final boolean isBluetoothPersistedStateOnBluetooth() {
303 return Settings.Global.getInt(mContentResolver,
304 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
fredc649fe492012-04-19 01:07:18 -0700305 }
306
307 /**
308 * Save the Bluetooth on/off state
309 *
310 */
Zhihai Xu401202b2012-12-03 11:36:21 -0800311 private void persistBluetoothSetting(int value) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700312 Settings.Global.putInt(mContext.getContentResolver(),
313 Settings.Global.BLUETOOTH_ON,
Zhihai Xu401202b2012-12-03 11:36:21 -0800314 value);
fredc649fe492012-04-19 01:07:18 -0700315 }
316
317 /**
318 * Returns true if the Bluetooth Adapter's name and address is
319 * locally cached
320 * @return
321 */
fredc0f420372012-04-12 00:02:00 -0700322 private boolean isNameAndAddressSet() {
323 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
324 }
325
fredc649fe492012-04-19 01:07:18 -0700326 /**
327 * Retrieve the Bluetooth Adapter's name and address and save it in
328 * in the local cache
329 */
fredc0f420372012-04-12 00:02:00 -0700330 private void loadStoredNameAndAddress() {
331 if (DBG) Log.d(TAG, "Loading stored name and address");
Zhihai Xud31c3222012-10-31 16:08:57 -0700332 if (mContext.getResources().getBoolean
333 (com.android.internal.R.bool.config_bluetooth_address_validation) &&
334 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
335 // if the valid flag is not set, don't load the address and name
336 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
337 return;
338 }
fredc0f420372012-04-12 00:02:00 -0700339 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
340 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
Zhihai Xud31c3222012-10-31 16:08:57 -0700341 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
fredc0f420372012-04-12 00:02:00 -0700342 }
343
fredc649fe492012-04-19 01:07:18 -0700344 /**
345 * Save the Bluetooth name and address in the persistent store.
346 * Only non-null values will be saved.
347 * @param name
348 * @param address
349 */
fredc0f420372012-04-12 00:02:00 -0700350 private void storeNameAndAddress(String name, String address) {
351 if (name != null) {
352 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700353 mName = name;
fredc649fe492012-04-19 01:07:18 -0700354 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
355 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700356 }
357
358 if (address != null) {
359 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700360 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700361 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
362 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700363 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700364
365 if ((name != null) && (address != null)) {
366 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
367 }
fredc0f420372012-04-12 00:02:00 -0700368 }
369
370 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
Natalie Silvanovich55db6462014-05-01 16:12:23 -0700371 if (callback == null) {
372 Log.w(TAG, "Callback is null in registerAdapter");
373 return null;
374 }
fredc0f420372012-04-12 00:02:00 -0700375 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
376 msg.obj = callback;
377 mHandler.sendMessage(msg);
378 synchronized(mConnection) {
379 return mBluetooth;
380 }
381 }
382
383 public void unregisterAdapter(IBluetoothManagerCallback callback) {
Natalie Silvanovich55db6462014-05-01 16:12:23 -0700384 if (callback == null) {
385 Log.w(TAG, "Callback is null in unregisterAdapter");
386 return;
387 }
fredc0f420372012-04-12 00:02:00 -0700388 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
389 "Need BLUETOOTH permission");
390 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
391 msg.obj = callback;
392 mHandler.sendMessage(msg);
393 }
394
395 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
396 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
397 "Need BLUETOOTH permission");
398 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
399 msg.obj = callback;
400 mHandler.sendMessage(msg);
401 }
402
403 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
404 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
405 "Need BLUETOOTH permission");
406 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
407 msg.obj = callback;
408 mHandler.sendMessage(msg);
409 }
410
411 public boolean isEnabled() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800412 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
413 (!checkIfCallerIsForegroundUser())) {
414 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700415 return false;
416 }
417
fredc0f420372012-04-12 00:02:00 -0700418 synchronized(mConnection) {
419 try {
420 return (mBluetooth != null && mBluetooth.isEnabled());
421 } catch (RemoteException e) {
422 Log.e(TAG, "isEnabled()", e);
423 }
424 }
425 return false;
426 }
427
Nitin Arorad055adb2015-03-02 15:03:51 -0800428 class ClientDeathRecipient implements IBinder.DeathRecipient {
429 public void binderDied() {
430 if (DBG) Log.d(TAG, "Binder is dead - unregister Ble App");
431 if (mBleAppCount > 0) --mBleAppCount;
432
433 if (mBleAppCount == 0) {
434 if (DBG) Log.d(TAG, "Disabling LE only mode after application crash");
435 try {
436 if (mBluetooth != null) {
437 mBluetooth.onBrEdrDown();
438 }
439 } catch(RemoteException e) {
440 Log.e(TAG,"Unable to call onBrEdrDown", e);
441 }
442 }
443 }
444 }
445
446 /** Internal death rec list */
447 Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>();
448
Wei Wang67d84162015-04-26 17:04:29 -0700449 @Override
450 public boolean isBleScanAlwaysAvailable() {
451 try {
452 return (Settings.Global.getInt(mContentResolver,
453 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0;
454 } catch (SettingNotFoundException e) {
455 }
456 return false;
457 }
458
Nitin Arorad055adb2015-03-02 15:03:51 -0800459 public int updateBleAppCount(IBinder token, boolean enable) {
460 if (enable) {
461 ClientDeathRecipient r = mBleApps.get(token);
462 if (r == null) {
463 ClientDeathRecipient deathRec = new ClientDeathRecipient();
464 try {
465 token.linkToDeath(deathRec, 0);
466 } catch (RemoteException ex) {
467 throw new IllegalArgumentException("Wake lock is already dead.");
468 }
469 mBleApps.put(token, deathRec);
470 synchronized (this) {
471 ++mBleAppCount;
472 }
473 if (DBG) Log.d(TAG, "Registered for death Notification");
474 }
475
476 } else {
477 ClientDeathRecipient r = mBleApps.get(token);
478 if (r != null) {
479 try {
480 token.linkToDeath(r, 0);
481 } catch (RemoteException ex) {
482 throw new IllegalArgumentException("Wake lock is already dead.");
483 }
484 mBleApps.remove(token);
485 synchronized (this) {
486 if (mBleAppCount > 0) --mBleAppCount;
487 }
488 if (DBG) Log.d(TAG, "Unregistered for death Notification");
489 }
490 }
491 if (DBG) Log.d(TAG, "Updated BleAppCount" + mBleAppCount);
492 if (mBleAppCount == 0 && mEnable) {
493 try {
494 if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
495 if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
496 mEnable = false;
497 }
498 } catch (RemoteException e) {
499 Log.e(TAG, "getState()", e);
500 }
501 }
502 return mBleAppCount;
503 }
504
505 /** @hide*/
506 public boolean isBleAppPresent() {
507 if (DBG) Log.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
508 return (mBleAppCount > 0);
509 }
510
511 /**
512 * Action taken when GattService is turned off
513 */
514 private void onBluetoothGattServiceUp() {
515 if (DBG) Log.d(TAG,"BluetoothGatt Service is Up");
516 try{
Nitin Arorabdfaa7f2015-04-29 12:35:03 -0700517 if (isBleAppPresent() == false && mBluetooth != null
518 && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
Nitin Arorad055adb2015-03-02 15:03:51 -0800519 mBluetooth.onLeServiceUp();
520
521 // waive WRITE_SECURE_SETTINGS permission check
522 long callingIdentity = Binder.clearCallingIdentity();
523 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
524 Binder.restoreCallingIdentity(callingIdentity);
525 }
526 } catch(RemoteException e) {
527 Log.e(TAG,"Unable to call onServiceUp", e);
528 }
529 }
530
531 /**
532 * Inform BluetoothAdapter instances that BREDR part is down
533 * and turn off all service and stack if no LE app needs it
534 */
535 private void sendBrEdrDownCallback() {
536 if (DBG) Log.d(TAG,"Calling sendBrEdrDownCallback callbacks");
Nitin Arorabdfaa7f2015-04-29 12:35:03 -0700537
538 if(mBluetooth == null) {
539 Log.w(TAG, "Bluetooth handle is null");
540 return;
541 }
Nitin Arorad055adb2015-03-02 15:03:51 -0800542
543 if (isBleAppPresent() == false) {
544 try {
545 mBluetooth.onBrEdrDown();
546 } catch(RemoteException e) {
Nitin Arorabdfaa7f2015-04-29 12:35:03 -0700547 Log.e(TAG, "Call to onBrEdrDown() failed.", e);
Nitin Arorad055adb2015-03-02 15:03:51 -0800548 }
Nitin Arorabdfaa7f2015-04-29 12:35:03 -0700549 } else {
550 // Need to stay at BLE ON. Disconnect all Gatt connections
Nitin Arorad055adb2015-03-02 15:03:51 -0800551 try{
Nitin Arorabdfaa7f2015-04-29 12:35:03 -0700552 mBluetoothGatt.unregAll();
Nitin Arorad055adb2015-03-02 15:03:51 -0800553 } catch(RemoteException e) {
Nitin Arorabdfaa7f2015-04-29 12:35:03 -0700554 Log.e(TAG, "Unable to disconnect all apps.", e);
Nitin Arorad055adb2015-03-02 15:03:51 -0800555 }
556 }
Nitin Arorad055adb2015-03-02 15:03:51 -0800557 }
558
559 /** @hide*/
fredc0f420372012-04-12 00:02:00 -0700560 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700561 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700562 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
563 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700564 }
fredc0f420372012-04-12 00:02:00 -0700565 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
566 mHandler.sendMessage(msg);
567 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700568 public boolean enableNoAutoConnect()
569 {
570 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
571 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700572
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700573 if (DBG) {
574 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
575 " mBinding = " + mBinding);
576 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800577 int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
578
579 if (callingAppId != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700580 throw new SecurityException("no permission to enable Bluetooth quietly");
581 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800582
Zhihai Xu401202b2012-12-03 11:36:21 -0800583 synchronized(mReceiver) {
584 mQuietEnableExternal = true;
585 mEnableExternal = true;
586 sendEnableMsg(true);
587 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700588 return true;
589
590 }
fredc0f420372012-04-12 00:02:00 -0700591 public boolean enable() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800592 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
593 (!checkIfCallerIsForegroundUser())) {
594 Log.w(TAG,"enable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700595 return false;
fredcf2458862012-04-16 15:18:27 -0700596 }
597
Zhihai Xu401202b2012-12-03 11:36:21 -0800598 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
599 "Need BLUETOOTH ADMIN permission");
600 if (DBG) {
601 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
602 " mBinding = " + mBinding);
603 }
604
605 synchronized(mReceiver) {
606 mQuietEnableExternal = false;
607 mEnableExternal = true;
608 // waive WRITE_SECURE_SETTINGS permission check
Zhihai Xu401202b2012-12-03 11:36:21 -0800609 sendEnableMsg(false);
610 }
Nitin Arorad055adb2015-03-02 15:03:51 -0800611 if (DBG) Log.d(TAG, "enable returning");
Zhihai Xu401202b2012-12-03 11:36:21 -0800612 return true;
fredc0f420372012-04-12 00:02:00 -0700613 }
614
615 public boolean disable(boolean persist) {
616 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
617 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700618
Zhihai Xu6eb76522012-11-29 15:41:04 -0800619 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
620 (!checkIfCallerIsForegroundUser())) {
621 Log.w(TAG,"disable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700622 return false;
623 }
624
fredcf2458862012-04-16 15:18:27 -0700625 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700626 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
627 " mBinding = " + mBinding);
628 }
fredcf2458862012-04-16 15:18:27 -0700629
Zhihai Xu401202b2012-12-03 11:36:21 -0800630 synchronized(mReceiver) {
631 if (persist) {
632 // waive WRITE_SECURE_SETTINGS permission check
633 long callingIdentity = Binder.clearCallingIdentity();
634 persistBluetoothSetting(BLUETOOTH_OFF);
635 Binder.restoreCallingIdentity(callingIdentity);
636 }
637 mEnableExternal = false;
638 sendDisableMsg();
639 }
fredc0f420372012-04-12 00:02:00 -0700640 return true;
641 }
642
fredc649fe492012-04-19 01:07:18 -0700643 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700644 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700645 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
646 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700647 }
648
fredc0f420372012-04-12 00:02:00 -0700649 synchronized (mConnection) {
650 if (mUnbinding) return;
651 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700652 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700653 if (!mConnection.isGetNameAddressOnly()) {
654 //Unregister callback object
655 try {
656 mBluetooth.unregisterCallback(mBluetoothCallback);
657 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700658 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700659 }
660 }
fredc0f420372012-04-12 00:02:00 -0700661 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700662 mBluetooth = null;
663 //Unbind
fredc0f420372012-04-12 00:02:00 -0700664 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700665 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700666 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700667 } else {
668 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700669 }
Nitin Arorad055adb2015-03-02 15:03:51 -0800670 mBluetoothGatt = null;
fredc0f420372012-04-12 00:02:00 -0700671 }
672 }
673
Matthew Xieddf7e472013-03-01 18:41:02 -0800674 public IBluetoothGatt getBluetoothGatt() {
675 // sync protection
676 return mBluetoothGatt;
677 }
678
Benjamin Franze8b98922014-11-12 15:57:54 +0000679 @Override
680 public boolean bindBluetoothProfileService(int bluetoothProfile,
681 IBluetoothProfileServiceConnection proxy) {
682 if (!mEnable) {
683 if (DBG) {
684 Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
685 ", while Bluetooth was disabled");
686 }
687 return false;
688 }
689 synchronized (mProfileServices) {
690 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
691 if (psc == null) {
692 if (DBG) {
693 Log.d(TAG, "Creating new ProfileServiceConnections object for"
694 + " profile: " + bluetoothProfile);
695 }
Benjamin Franz5b614592014-12-09 18:58:45 +0000696
697 if (bluetoothProfile != BluetoothProfile.HEADSET) return false;
698
699 Intent intent = new Intent(IBluetoothHeadset.class.getName());
Benjamin Franze8b98922014-11-12 15:57:54 +0000700 psc = new ProfileServiceConnections(intent);
Benjamin Franz5b614592014-12-09 18:58:45 +0000701 if (!psc.bindService()) return false;
702
Benjamin Franze8b98922014-11-12 15:57:54 +0000703 mProfileServices.put(new Integer(bluetoothProfile), psc);
Benjamin Franze8b98922014-11-12 15:57:54 +0000704 }
705 }
706
707 // Introducing a delay to give the client app time to prepare
708 Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
709 addProxyMsg.arg1 = bluetoothProfile;
710 addProxyMsg.obj = proxy;
711 mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
712 return true;
713 }
714
715 @Override
716 public void unbindBluetoothProfileService(int bluetoothProfile,
717 IBluetoothProfileServiceConnection proxy) {
718 synchronized (mProfileServices) {
719 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
720 if (psc == null) {
721 return;
722 }
723 psc.removeProxy(proxy);
724 }
725 }
726
727 private void unbindAllBluetoothProfileServices() {
728 synchronized (mProfileServices) {
729 for (Integer i : mProfileServices.keySet()) {
730 ProfileServiceConnections psc = mProfileServices.get(i);
Benjamin Franz5b614592014-12-09 18:58:45 +0000731 try {
732 mContext.unbindService(psc);
733 } catch (IllegalArgumentException e) {
734 Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
735 }
Benjamin Franze8b98922014-11-12 15:57:54 +0000736 psc.removeAllProxies();
737 }
738 mProfileServices.clear();
739 }
740 }
741
742 /**
743 * This class manages the clients connected to a given ProfileService
744 * and maintains the connection with that service.
745 */
746 final private class ProfileServiceConnections implements ServiceConnection,
747 IBinder.DeathRecipient {
748 final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
749 new RemoteCallbackList <IBluetoothProfileServiceConnection>();
750 IBinder mService;
751 ComponentName mClassName;
752 Intent mIntent;
753
754 ProfileServiceConnections(Intent intent) {
755 mService = null;
756 mClassName = null;
757 mIntent = intent;
758 }
759
Benjamin Franz5b614592014-12-09 18:58:45 +0000760 private boolean bindService() {
761 if (mIntent != null && mService == null &&
762 doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
Benjamin Franze8b98922014-11-12 15:57:54 +0000763 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
764 msg.obj = this;
765 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
Benjamin Franz5b614592014-12-09 18:58:45 +0000766 return true;
Benjamin Franze8b98922014-11-12 15:57:54 +0000767 }
Benjamin Franz5b614592014-12-09 18:58:45 +0000768 Log.w(TAG, "Unable to bind with intent: " + mIntent);
769 return false;
Benjamin Franze8b98922014-11-12 15:57:54 +0000770 }
771
772 private void addProxy(IBluetoothProfileServiceConnection proxy) {
773 mProxies.register(proxy);
774 if (mService != null) {
775 try{
776 proxy.onServiceConnected(mClassName, mService);
777 } catch (RemoteException e) {
778 Log.e(TAG, "Unable to connect to proxy", e);
779 }
780 } else {
781 if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
782 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
783 msg.obj = this;
784 mHandler.sendMessage(msg);
785 }
786 }
787 }
788
789 private void removeProxy(IBluetoothProfileServiceConnection proxy) {
790 if (proxy != null) {
791 if (mProxies.unregister(proxy)) {
792 try {
793 proxy.onServiceDisconnected(mClassName);
794 } catch (RemoteException e) {
795 Log.e(TAG, "Unable to disconnect proxy", e);
796 }
797 }
798 } else {
799 Log.w(TAG, "Trying to remove a null proxy");
800 }
801 }
802
803 private void removeAllProxies() {
804 onServiceDisconnected(mClassName);
805 mProxies.kill();
806 }
807
808 @Override
809 public void onServiceConnected(ComponentName className, IBinder service) {
810 // remove timeout message
811 mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
812 mService = service;
813 mClassName = className;
814 try {
815 mService.linkToDeath(this, 0);
816 } catch (RemoteException e) {
817 Log.e(TAG, "Unable to linkToDeath", e);
818 }
819 int n = mProxies.beginBroadcast();
820 for (int i = 0; i < n; i++) {
821 try {
822 mProxies.getBroadcastItem(i).onServiceConnected(className, service);
823 } catch (RemoteException e) {
824 Log.e(TAG, "Unable to connect to proxy", e);
825 }
826 }
827 mProxies.finishBroadcast();
828 }
829
830 @Override
831 public void onServiceDisconnected(ComponentName className) {
832 if (mService == null) {
833 return;
834 }
835 mService.unlinkToDeath(this, 0);
836 mService = null;
837 mClassName = null;
838 int n = mProxies.beginBroadcast();
839 for (int i = 0; i < n; i++) {
840 try {
841 mProxies.getBroadcastItem(i).onServiceDisconnected(className);
842 } catch (RemoteException e) {
843 Log.e(TAG, "Unable to disconnect from proxy", e);
844 }
845 }
846 mProxies.finishBroadcast();
847 }
848
849 @Override
850 public void binderDied() {
851 if (DBG) {
852 Log.w(TAG, "Profile service for profile: " + mClassName
853 + " died.");
854 }
855 onServiceDisconnected(mClassName);
856 // Trigger rebind
857 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
858 msg.obj = this;
859 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
860 }
861 }
862
fredcbf072a72012-05-09 16:52:50 -0700863 private void sendBluetoothStateCallback(boolean isUp) {
864 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700865 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700866 for (int i=0; i <n;i++) {
867 try {
868 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
869 } catch (RemoteException e) {
870 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
871 }
872 }
873 mStateChangeCallbacks.finishBroadcast();
874 }
875
876 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700877 * Inform BluetoothAdapter instances that Adapter service is up
878 */
879 private void sendBluetoothServiceUpCallback() {
880 if (!mConnection.isGetNameAddressOnly()) {
881 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
882 int n = mCallbacks.beginBroadcast();
883 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
884 for (int i=0; i <n;i++) {
885 try {
886 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
887 } catch (RemoteException e) {
888 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
889 }
890 }
891 mCallbacks.finishBroadcast();
892 }
893 }
894 /**
fredcbf072a72012-05-09 16:52:50 -0700895 * Inform BluetoothAdapter instances that Adapter service is down
896 */
897 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700898 if (!mConnection.isGetNameAddressOnly()) {
899 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
900 int n = mCallbacks.beginBroadcast();
901 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
902 for (int i=0; i <n;i++) {
903 try {
904 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
905 } catch (RemoteException e) {
906 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
907 }
908 }
909 mCallbacks.finishBroadcast();
910 }
911 }
fredc0f420372012-04-12 00:02:00 -0700912 public String getAddress() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800913 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
914 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700915
Zhihai Xu6eb76522012-11-29 15:41:04 -0800916 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
917 (!checkIfCallerIsForegroundUser())) {
918 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
919 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700920 }
921
fredc116d1d462012-04-20 14:47:08 -0700922 synchronized(mConnection) {
923 if (mBluetooth != null) {
924 try {
925 return mBluetooth.getAddress();
926 } catch (RemoteException e) {
927 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
928 }
929 }
930 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700931 // mAddress is accessed from outside.
932 // It is alright without a lock. Here, bluetooth is off, no other thread is
933 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700934 return mAddress;
935 }
fredc649fe492012-04-19 01:07:18 -0700936
fredc0f420372012-04-12 00:02:00 -0700937 public String getName() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800938 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
939 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700940
Zhihai Xu6eb76522012-11-29 15:41:04 -0800941 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
942 (!checkIfCallerIsForegroundUser())) {
943 Log.w(TAG,"getName(): not allowed for non-active and non system user");
944 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700945 }
946
fredc116d1d462012-04-20 14:47:08 -0700947 synchronized(mConnection) {
948 if (mBluetooth != null) {
949 try {
950 return mBluetooth.getName();
951 } catch (RemoteException e) {
952 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
953 }
954 }
955 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700956 // mName is accessed from outside.
957 // It alright without a lock. Here, bluetooth is off, no other thread is
958 // changing mName
fredc0f420372012-04-12 00:02:00 -0700959 return mName;
960 }
961
fredc0f420372012-04-12 00:02:00 -0700962 private class BluetoothServiceConnection implements ServiceConnection {
963
964 private boolean mGetNameAddressOnly;
965
966 public void setGetNameAddressOnly(boolean getOnly) {
967 mGetNameAddressOnly = getOnly;
968 }
969
970 public boolean isGetNameAddressOnly() {
971 return mGetNameAddressOnly;
972 }
973
974 public void onServiceConnected(ComponentName className, IBinder service) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800975 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700976 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800977 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
978 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
979 msg.arg1 = SERVICE_IBLUETOOTH;
980 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
981 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
982 msg.arg1 = SERVICE_IBLUETOOTHGATT;
983 } else {
984 Log.e(TAG, "Unknown service connected: " + className.getClassName());
985 return;
986 }
fredc0f420372012-04-12 00:02:00 -0700987 msg.obj = service;
988 mHandler.sendMessage(msg);
989 }
990
991 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700992 // Called if we unexpected disconnected.
Matthew Xieddf7e472013-03-01 18:41:02 -0800993 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
994 className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700995 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800996 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
997 msg.arg1 = SERVICE_IBLUETOOTH;
998 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
999 msg.arg1 = SERVICE_IBLUETOOTHGATT;
1000 } else {
1001 Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
1002 return;
1003 }
fredc0f420372012-04-12 00:02:00 -07001004 mHandler.sendMessage(msg);
1005 }
1006 }
1007
1008 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
1009
Zhihai Xu40874a02012-10-08 17:57:03 -07001010 private class BluetoothHandler extends Handler {
1011 public BluetoothHandler(Looper looper) {
1012 super(looper);
1013 }
1014
fredc0f420372012-04-12 00:02:00 -07001015 @Override
1016 public void handleMessage(Message msg) {
1017 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -07001018 switch (msg.what) {
1019 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -07001020 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -07001021 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -07001022 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -07001023 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -07001024 if (DBG) Log.d(TAG, "Binding to service to get name and address");
1025 mConnection.setGetNameAddressOnly(true);
1026 //Start bind timeout and bind
1027 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1028 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1029 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackborn221ea892013-08-04 16:50:16 -07001030 if (!doBind(i, mConnection,
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001031 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1032 UserHandle.CURRENT)) {
fredc0f420372012-04-12 00:02:00 -07001033 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -07001034 } else {
1035 mBinding = true;
fredc0f420372012-04-12 00:02:00 -07001036 }
1037 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001038 else {
1039 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -07001040 saveMsg.arg1 = 0;
1041 if (mBluetooth != null) {
1042 mHandler.sendMessage(saveMsg);
1043 } else {
1044 // if enable is also called to bind the service
1045 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
1046 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
1047 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001048 }
fredc0f420372012-04-12 00:02:00 -07001049 }
fredc649fe492012-04-19 01:07:18 -07001050 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001051 }
fredc0f420372012-04-12 00:02:00 -07001052 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -07001053 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -07001054 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -07001055 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -07001056 if (!mEnable && mBluetooth != null) {
1057 try {
1058 mBluetooth.enable();
1059 } catch (RemoteException e) {
1060 Log.e(TAG,"Unable to call enable()",e);
1061 }
1062 }
1063 }
1064 if (mBluetooth != null) waitForOnOff(true, false);
1065 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001066 if (mBluetooth != null) {
1067 String name = null;
1068 String address = null;
1069 try {
1070 name = mBluetooth.getName();
1071 address = mBluetooth.getAddress();
1072 } catch (RemoteException re) {
1073 Log.e(TAG,"",re);
1074 }
fredc0f420372012-04-12 00:02:00 -07001075
Matthew Xiecdce0b92012-07-12 19:06:15 -07001076 if (name != null && address != null) {
1077 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -07001078 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -07001079 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -07001080 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001081 } else {
1082 if (msg.arg1 < MAX_SAVE_RETRIES) {
1083 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
1084 retryMsg.arg1= 1+msg.arg1;
1085 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
1086 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
1087 } else {
1088 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -07001089 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -07001090 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -07001091 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001092 }
fredc0f420372012-04-12 00:02:00 -07001093 }
Zhihai Xud31c3222012-10-31 16:08:57 -07001094 if (!mEnable) {
1095 try {
1096 mBluetooth.disable();
1097 } catch (RemoteException e) {
1098 Log.e(TAG,"Unable to call disable()",e);
1099 }
1100 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001101 } else {
1102 // rebind service by Request GET NAME AND ADDRESS
1103 // if service is unbinded by disable or
1104 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
1105 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1106 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -07001107 }
1108 }
Zhihai Xud31c3222012-10-31 16:08:57 -07001109 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
1110 if (unbind) {
1111 unbindAndFinish();
1112 }
fredc649fe492012-04-19 01:07:18 -07001113 break;
fredc649fe492012-04-19 01:07:18 -07001114 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001115 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -07001116 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001117 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -07001118 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001119 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1120 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -08001121 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -07001122 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001123
fredc0f420372012-04-12 00:02:00 -07001124 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -07001125 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1126 if (mEnable && mBluetooth != null) {
1127 waitForOnOff(true, false);
1128 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -08001129 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001130 waitForOnOff(false, false);
1131 } else {
1132 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -08001133 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001134 }
fredc0f420372012-04-12 00:02:00 -07001135 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001136
fredc0f420372012-04-12 00:02:00 -07001137 case MESSAGE_REGISTER_ADAPTER:
1138 {
1139 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -07001140 boolean added = mCallbacks.register(callback);
1141 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -07001142 }
1143 break;
1144 case MESSAGE_UNREGISTER_ADAPTER:
1145 {
1146 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -07001147 boolean removed = mCallbacks.unregister(callback);
1148 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -07001149 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001150 }
fredc0f420372012-04-12 00:02:00 -07001151 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
1152 {
1153 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -07001154 if (callback != null) {
1155 mStateChangeCallbacks.register(callback);
1156 }
fredc0f420372012-04-12 00:02:00 -07001157 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001158 }
fredc0f420372012-04-12 00:02:00 -07001159 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
1160 {
1161 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -07001162 if (callback != null) {
1163 mStateChangeCallbacks.unregister(callback);
1164 }
fredc0f420372012-04-12 00:02:00 -07001165 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001166 }
Benjamin Franze8b98922014-11-12 15:57:54 +00001167 case MESSAGE_ADD_PROXY_DELAYED:
1168 {
1169 ProfileServiceConnections psc = mProfileServices.get(
1170 new Integer(msg.arg1));
1171 if (psc == null) {
1172 break;
1173 }
1174 IBluetoothProfileServiceConnection proxy =
1175 (IBluetoothProfileServiceConnection) msg.obj;
1176 psc.addProxy(proxy);
1177 break;
1178 }
1179 case MESSAGE_BIND_PROFILE_SERVICE:
1180 {
1181 ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
1182 removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
1183 if (psc == null) {
1184 break;
1185 }
1186 psc.bindService();
1187 break;
1188 }
fredc0f420372012-04-12 00:02:00 -07001189 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
1190 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001191 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
fredc0f420372012-04-12 00:02:00 -07001192
1193 IBinder service = (IBinder) msg.obj;
1194 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001195 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1196 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
Nitin Arorad055adb2015-03-02 15:03:51 -08001197 onBluetoothGattServiceUp();
Matthew Xieddf7e472013-03-01 18:41:02 -08001198 break;
1199 } // else must be SERVICE_IBLUETOOTH
1200
1201 //Remove timeout
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001202 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Matthew Xieddf7e472013-03-01 18:41:02 -08001203
fredc0f420372012-04-12 00:02:00 -07001204 mBinding = false;
1205 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -07001206
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001207 try {
1208 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
1209 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
1210 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
1211 Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
1212 }
1213 } catch (RemoteException e) {
1214 Log.e(TAG,"Unable to call configHciSnoopLog", e);
1215 }
1216
Matthew Xiecdce0b92012-07-12 19:06:15 -07001217 if (mConnection.isGetNameAddressOnly()) {
1218 //Request GET NAME AND ADDRESS
1219 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1220 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -07001221 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001222 }
fredc0f420372012-04-12 00:02:00 -07001223
Zhihai Xu40874a02012-10-08 17:57:03 -07001224 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -07001225 //Register callback object
fredcbf072a72012-05-09 16:52:50 -07001226 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001227 mBluetooth.registerCallback(mBluetoothCallback);
1228 } catch (RemoteException re) {
1229 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -07001230 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001231 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -07001232 sendBluetoothServiceUpCallback();
1233
Matthew Xiecdce0b92012-07-12 19:06:15 -07001234 //Do enable request
1235 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001236 if (mQuietEnable == false) {
1237 if(!mBluetooth.enable()) {
1238 Log.e(TAG,"IBluetooth.enable() returned false");
1239 }
1240 }
1241 else
1242 {
1243 if(!mBluetooth.enableNoAutoConnect()) {
1244 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1245 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001246 }
1247 } catch (RemoteException e) {
1248 Log.e(TAG,"Unable to call enable()",e);
1249 }
Freda8c6df02012-07-11 10:25:23 -07001250 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001251
1252 if (!mEnable) {
1253 waitForOnOff(true, false);
Zhihai Xu401202b2012-12-03 11:36:21 -08001254 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001255 waitForOnOff(false, false);
1256 }
fredc649fe492012-04-19 01:07:18 -07001257 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001258 }
fredc649fe492012-04-19 01:07:18 -07001259 case MESSAGE_TIMEOUT_BIND: {
1260 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -07001261 synchronized(mConnection) {
1262 mBinding = false;
1263 }
fredc649fe492012-04-19 01:07:18 -07001264 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001265 }
fredcbf072a72012-05-09 16:52:50 -07001266 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -07001267 {
fredcbf072a72012-05-09 16:52:50 -07001268 int prevState = msg.arg1;
1269 int newState = msg.arg2;
1270 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -07001271 mState = newState;
1272 bluetoothStateChangeHandler(prevState, newState);
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001273 // handle error state transition case from TURNING_ON to OFF
1274 // unbind and rebind bluetooth service and enable bluetooth
Nitin Arorad055adb2015-03-02 15:03:51 -08001275 if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001276 (newState == BluetoothAdapter.STATE_OFF) &&
1277 (mBluetooth != null) && mEnable) {
1278 recoverBluetoothServiceFromError();
1279 }
Nitin Arorad055adb2015-03-02 15:03:51 -08001280 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
1281 (newState == BluetoothAdapter.STATE_BLE_ON) &&
1282 (mBluetooth != null) && mEnable) {
1283 recoverBluetoothServiceFromError();
1284 }
1285 if (newState == BluetoothAdapter.STATE_ON ||
1286 newState == BluetoothAdapter.STATE_BLE_ON) {
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001287 // bluetooth is working, reset the counter
1288 if (mErrorRecoveryRetryCounter != 0) {
1289 Log.w(TAG, "bluetooth is recovered from error");
1290 mErrorRecoveryRetryCounter = 0;
1291 }
1292 }
fredc649fe492012-04-19 01:07:18 -07001293 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001294 }
fredc0f420372012-04-12 00:02:00 -07001295 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
1296 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001297 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301298 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001299 if (msg.arg1 == SERVICE_IBLUETOOTH) {
1300 // if service is unbinded already, do nothing and return
1301 if (mBluetooth == null) break;
1302 mBluetooth = null;
1303 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1304 mBluetoothGatt = null;
1305 break;
1306 } else {
1307 Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
1308 break;
1309 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301310 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001311
1312 if (mEnable) {
1313 mEnable = false;
1314 // Send a Bluetooth Restart message
1315 Message restartMsg = mHandler.obtainMessage(
1316 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1317 mHandler.sendMessageDelayed(restartMsg,
1318 SERVICE_RESTART_TIME_MS);
1319 }
1320
1321 if (!mConnection.isGetNameAddressOnly()) {
1322 sendBluetoothServiceDownCallback();
1323
1324 // Send BT state broadcast to update
1325 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001326 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
1327 (mState == BluetoothAdapter.STATE_ON)) {
1328 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1329 BluetoothAdapter.STATE_TURNING_OFF);
1330 mState = BluetoothAdapter.STATE_TURNING_OFF;
1331 }
1332 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1333 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1334 BluetoothAdapter.STATE_OFF);
1335 }
1336
1337 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -07001338 mState = BluetoothAdapter.STATE_OFF;
1339 }
fredc649fe492012-04-19 01:07:18 -07001340 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001341 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301342 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
1343 {
1344 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
1345 +" Restart IBluetooth service");
1346 /* Enable without persisting the setting as
1347 it doesnt change when IBluetooth
1348 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -07001349 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -08001350 handleEnable(mQuietEnable);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301351 break;
1352 }
1353
fredc0f420372012-04-12 00:02:00 -07001354 case MESSAGE_TIMEOUT_UNBIND:
1355 {
fredc649fe492012-04-19 01:07:18 -07001356 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -07001357 synchronized(mConnection) {
1358 mUnbinding = false;
1359 }
fredc649fe492012-04-19 01:07:18 -07001360 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001361 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001362
1363 case MESSAGE_USER_SWITCHED:
1364 {
1365 if (DBG) {
1366 Log.d(TAG, "MESSAGE_USER_SWITCHED");
1367 }
1368 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1369 /* disable and enable BT when detect a user switch */
1370 if (mEnable && mBluetooth != null) {
1371 synchronized (mConnection) {
1372 if (mBluetooth != null) {
1373 //Unregister callback object
1374 try {
1375 mBluetooth.unregisterCallback(mBluetoothCallback);
1376 } catch (RemoteException re) {
1377 Log.e(TAG, "Unable to unregister",re);
1378 }
1379 }
1380 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001381
1382 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1383 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
1384 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
1385 mState = BluetoothAdapter.STATE_OFF;
1386 }
1387 if (mState == BluetoothAdapter.STATE_OFF) {
1388 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
1389 mState = BluetoothAdapter.STATE_TURNING_ON;
1390 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001391
1392 waitForOnOff(true, false);
1393
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001394 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
1395 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
1396 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001397
Benjamin Franze8b98922014-11-12 15:57:54 +00001398 unbindAllBluetoothProfileServices();
Zhihai Xu40874a02012-10-08 17:57:03 -07001399 // disable
Zhihai Xu401202b2012-12-03 11:36:21 -08001400 handleDisable();
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001401 // Pbap service need receive STATE_TURNING_OFF intent to close
1402 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1403 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001404
1405 waitForOnOff(false, true);
1406
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001407 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -07001408 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001409 sendBluetoothServiceDownCallback();
1410 synchronized (mConnection) {
1411 if (mBluetooth != null) {
1412 mBluetooth = null;
1413 //Unbind
1414 mContext.unbindService(mConnection);
1415 }
1416 }
1417 SystemClock.sleep(100);
1418
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001419 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1420 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -07001421 // enable
Zhihai Xu401202b2012-12-03 11:36:21 -08001422 handleEnable(mQuietEnable);
John Spurlock8a985d22014-02-25 09:40:05 -05001423 } else if (mBinding || mBluetooth != null) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001424 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1425 userMsg.arg2 = 1 + msg.arg2;
1426 // if user is switched when service is being binding
1427 // delay sending MESSAGE_USER_SWITCHED
1428 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1429 if (DBG) {
1430 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1431 }
John Spurlock8a985d22014-02-25 09:40:05 -05001432 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001433 break;
1434 }
fredc0f420372012-04-12 00:02:00 -07001435 }
1436 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001437 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001438
Zhihai Xu401202b2012-12-03 11:36:21 -08001439 private void handleEnable(boolean quietMode) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001440 mQuietEnable = quietMode;
1441
Matthew Xiecdce0b92012-07-12 19:06:15 -07001442 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001443 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001444 //Start bind timeout and bind
1445 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1446 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1447 mConnection.setGetNameAddressOnly(false);
1448 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001449 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1450 UserHandle.CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001451 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -07001452 } else {
1453 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001454 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001455 } else if (mBluetooth != null) {
1456 if (mConnection.isGetNameAddressOnly()) {
1457 // if GetNameAddressOnly is set, we can clear this flag,
1458 // so the service won't be unbind
1459 // after name and address are saved
1460 mConnection.setGetNameAddressOnly(false);
1461 //Register callback object
1462 try {
1463 mBluetooth.registerCallback(mBluetoothCallback);
1464 } catch (RemoteException re) {
1465 Log.e(TAG, "Unable to register BluetoothCallback",re);
1466 }
1467 //Inform BluetoothAdapter instances that service is up
1468 sendBluetoothServiceUpCallback();
1469 }
1470
Matthew Xiecdce0b92012-07-12 19:06:15 -07001471 //Enable bluetooth
1472 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001473 if (!mQuietEnable) {
1474 if(!mBluetooth.enable()) {
1475 Log.e(TAG,"IBluetooth.enable() returned false");
1476 }
1477 }
1478 else {
1479 if(!mBluetooth.enableNoAutoConnect()) {
1480 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1481 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001482 }
1483 } catch (RemoteException e) {
1484 Log.e(TAG,"Unable to call enable()",e);
1485 }
1486 }
1487 }
1488 }
1489
Dianne Hackborn221ea892013-08-04 16:50:16 -07001490 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1491 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1492 intent.setComponent(comp);
1493 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1494 Log.e(TAG, "Fail to bind to: " + intent);
1495 return false;
1496 }
1497 return true;
1498 }
1499
Zhihai Xu401202b2012-12-03 11:36:21 -08001500 private void handleDisable() {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001501 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001502 // don't need to disable if GetNameAddressOnly is set,
1503 // service will be unbinded after Name and Address are saved
1504 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001505 if (DBG) Log.d(TAG,"Sending off request.");
1506
1507 try {
1508 if(!mBluetooth.disable()) {
1509 Log.e(TAG,"IBluetooth.disable() returned false");
1510 }
1511 } catch (RemoteException e) {
1512 Log.e(TAG,"Unable to call disable()",e);
1513 }
1514 }
1515 }
1516 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001517
1518 private boolean checkIfCallerIsForegroundUser() {
1519 int foregroundUser;
1520 int callingUser = UserHandle.getCallingUserId();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001521 int callingUid = Binder.getCallingUid();
Zhihai Xu40874a02012-10-08 17:57:03 -07001522 long callingIdentity = Binder.clearCallingIdentity();
Benjamin Franze8b98922014-11-12 15:57:54 +00001523 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1524 UserInfo ui = um.getProfileParent(callingUser);
1525 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001526 int callingAppId = UserHandle.getAppId(callingUid);
Zhihai Xu40874a02012-10-08 17:57:03 -07001527 boolean valid = false;
1528 try {
1529 foregroundUser = ActivityManager.getCurrentUser();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001530 valid = (callingUser == foregroundUser) ||
Benjamin Franze8b98922014-11-12 15:57:54 +00001531 parentUser == foregroundUser ||
Adrian Roosbd9a9a52014-08-18 15:31:57 +02001532 callingAppId == Process.NFC_UID ||
1533 callingAppId == mSystemUiUid;
Zhihai Xu40874a02012-10-08 17:57:03 -07001534 if (DBG) {
1535 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1536 + " callingUser=" + callingUser
Benjamin Franze8b98922014-11-12 15:57:54 +00001537 + " parentUser=" + parentUser
Zhihai Xu40874a02012-10-08 17:57:03 -07001538 + " foregroundUser=" + foregroundUser);
1539 }
1540 } finally {
1541 Binder.restoreCallingIdentity(callingIdentity);
1542 }
1543 return valid;
1544 }
1545
Nitin Arorad055adb2015-03-02 15:03:51 -08001546 private void sendBleStateChanged(int prevState, int newState) {
1547 if (DBG) Log.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
1548 // Send broadcast message to everyone else
1549 Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
1550 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1551 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1552 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1553 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1554 }
1555
Zhihai Xu40874a02012-10-08 17:57:03 -07001556 private void bluetoothStateChangeHandler(int prevState, int newState) {
Nitin Arorad055adb2015-03-02 15:03:51 -08001557 boolean isStandardBroadcast = true;
Zhihai Xu40874a02012-10-08 17:57:03 -07001558 if (prevState != newState) {
1559 //Notify all proxy objects first of adapter state change
Nitin Arorad055adb2015-03-02 15:03:51 -08001560 if (newState == BluetoothAdapter.STATE_BLE_ON
1561 || newState == BluetoothAdapter.STATE_OFF) {
1562 boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
1563 && newState == BluetoothAdapter.STATE_BLE_ON);
Zhihai Xu40874a02012-10-08 17:57:03 -07001564
Nitin Arorad055adb2015-03-02 15:03:51 -08001565 if (newState == BluetoothAdapter.STATE_OFF) {
1566 // If Bluetooth is off, send service down event to proxy objects, and unbind
1567 if (DBG) Log.d(TAG, "Bluetooth is complete turn off");
1568 if (canUnbindBluetoothService()) {
1569 if (DBG) Log.d(TAG, "Good to unbind!");
Matthew Xieddf7e472013-03-01 18:41:02 -08001570 sendBluetoothServiceDownCallback();
1571 unbindAndFinish();
Nitin Arorad055adb2015-03-02 15:03:51 -08001572 sendBleStateChanged(prevState, newState);
1573 // Don't broadcast as it has already been broadcast before
1574 isStandardBroadcast = false;
Matthew Xieddf7e472013-03-01 18:41:02 -08001575 }
Nitin Arorad055adb2015-03-02 15:03:51 -08001576
1577 } else if (!intermediate_off) {
1578 // connect to GattService
1579 if (DBG) Log.d(TAG, "Bluetooth is in LE only mode");
1580 if (mBluetoothGatt != null) {
1581 if (DBG) Log.d(TAG, "Calling BluetoothGattServiceUp");
1582 onBluetoothGattServiceUp();
1583 } else {
1584 if (DBG) Log.d(TAG, "Binding Bluetooth GATT service");
1585 if (mContext.getPackageManager().hasSystemFeature(
1586 PackageManager.FEATURE_BLUETOOTH_LE)) {
1587 Intent i = new Intent(IBluetoothGatt.class.getName());
1588 doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
1589 }
1590 }
1591 sendBleStateChanged(prevState, newState);
1592 //Don't broadcase this as std intent
1593 isStandardBroadcast = false;
1594
1595 } else if (intermediate_off){
1596 if (DBG) Log.d(TAG, "Intermediate off, back to LE only mode");
1597 // For LE only mode, broadcast as is
1598 sendBleStateChanged(prevState, newState);
1599 sendBluetoothStateCallback(false); // BT is OFF for general users
1600 // Broadcast as STATE_OFF
1601 newState = BluetoothAdapter.STATE_OFF;
1602 sendBrEdrDownCallback();
Zhihai Xu40874a02012-10-08 17:57:03 -07001603 }
Nitin Arorad055adb2015-03-02 15:03:51 -08001604 } else if (newState == BluetoothAdapter.STATE_ON) {
1605 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1606 sendBluetoothStateCallback(isUp);
1607 sendBleStateChanged(prevState, newState);
1608
1609 } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
1610 || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
1611 sendBleStateChanged(prevState, newState);
1612 isStandardBroadcast = false;
1613
1614 } else if (newState == BluetoothAdapter.STATE_TURNING_ON
1615 || newState == BluetoothAdapter.STATE_TURNING_OFF) {
1616 sendBleStateChanged(prevState, newState);
Zhihai Xu40874a02012-10-08 17:57:03 -07001617 }
1618
Nitin Arorad055adb2015-03-02 15:03:51 -08001619 if (isStandardBroadcast) {
1620 if (prevState == BluetoothAdapter.STATE_BLE_ON) {
1621 // Show prevState of BLE_ON as OFF to standard users
1622 prevState = BluetoothAdapter.STATE_OFF;
1623 }
1624 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1625 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1626 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1627 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1628 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1629 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001630 }
1631 }
1632
1633 /**
1634 * if on is true, wait for state become ON
1635 * if off is true, wait for state become OFF
1636 * if both on and off are false, wait for state not ON
1637 */
1638 private boolean waitForOnOff(boolean on, boolean off) {
1639 int i = 0;
1640 while (i < 10) {
1641 synchronized(mConnection) {
1642 try {
1643 if (mBluetooth == null) break;
1644 if (on) {
1645 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1646 } else if (off) {
1647 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001648 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001649 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001650 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001651 } catch (RemoteException e) {
1652 Log.e(TAG, "getState()", e);
1653 break;
1654 }
1655 }
1656 if (on || off) {
1657 SystemClock.sleep(300);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001658 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001659 SystemClock.sleep(50);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001660 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001661 i++;
1662 }
1663 Log.e(TAG,"waitForOnOff time out");
1664 return false;
1665 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001666
Zhihai Xu401202b2012-12-03 11:36:21 -08001667 private void sendDisableMsg() {
1668 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1669 }
1670
1671 private void sendEnableMsg(boolean quietMode) {
1672 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1673 quietMode ? 1 : 0, 0));
1674 }
1675
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001676 private boolean canUnbindBluetoothService() {
1677 synchronized(mConnection) {
1678 //Only unbind with mEnable flag not set
1679 //For race condition: disable and enable back-to-back
1680 //Avoid unbind right after enable due to callback from disable
1681 //Only unbind with Bluetooth at OFF state
1682 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1683 try {
1684 if (mEnable || (mBluetooth == null)) return false;
1685 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1686 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1687 } catch (RemoteException e) {
1688 Log.e(TAG, "getState()", e);
1689 }
1690 }
1691 return false;
1692 }
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001693
1694 private void recoverBluetoothServiceFromError() {
1695 Log.e(TAG,"recoverBluetoothServiceFromError");
1696 synchronized (mConnection) {
1697 if (mBluetooth != null) {
1698 //Unregister callback object
1699 try {
1700 mBluetooth.unregisterCallback(mBluetoothCallback);
1701 } catch (RemoteException re) {
1702 Log.e(TAG, "Unable to unregister",re);
1703 }
1704 }
1705 }
1706
1707 SystemClock.sleep(500);
1708
1709 // disable
1710 handleDisable();
1711
1712 waitForOnOff(false, true);
1713
1714 sendBluetoothServiceDownCallback();
1715 synchronized (mConnection) {
1716 if (mBluetooth != null) {
1717 mBluetooth = null;
1718 //Unbind
1719 mContext.unbindService(mConnection);
1720 }
1721 }
1722
1723 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1724 mState = BluetoothAdapter.STATE_OFF;
1725
1726 mEnable = false;
1727
1728 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1729 // Send a Bluetooth Restart message to reenable bluetooth
1730 Message restartMsg = mHandler.obtainMessage(
1731 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1732 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1733 } else {
1734 // todo: notify user to power down and power up phone to make bluetooth work.
1735 }
1736 }
Mike Lockwood726d4de2014-10-28 14:06:28 -07001737
1738 @Override
1739 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Mike Lockwood75b52bb2014-12-18 14:16:36 -08001740 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
1741
Andre Eisenbach14dcb5f2014-12-05 09:31:30 -08001742 writer.println("Bluetooth Status");
1743 writer.println(" enabled: " + mEnable);
1744 writer.println(" state: " + mState);
1745 writer.println(" address: " + mAddress);
1746 writer.println(" name: " + mName + "\n");
1747 writer.flush();
1748
Mike Lockwood726d4de2014-10-28 14:06:28 -07001749 if (mBluetooth == null) {
1750 writer.println("Bluetooth Service not connected");
1751 } else {
Andre Eisenbach14dcb5f2014-12-05 09:31:30 -08001752 ParcelFileDescriptor pfd = null;
Mike Lockwood726d4de2014-10-28 14:06:28 -07001753 try {
Andre Eisenbach14dcb5f2014-12-05 09:31:30 -08001754 pfd = ParcelFileDescriptor.dup(fd);
1755 mBluetooth.dump(pfd);
Mike Lockwood726d4de2014-10-28 14:06:28 -07001756 } catch (RemoteException re) {
1757 writer.println("RemoteException while calling Bluetooth Service");
Andre Eisenbach14dcb5f2014-12-05 09:31:30 -08001758 } catch (IOException ioe) {
1759 writer.println("IOException attempting to dup() fd");
1760 } finally {
1761 if (pfd != null) {
1762 try {
1763 pfd.close();
1764 } catch (IOException ioe) {
1765 writer.println("IOException attempting to close() fd");
1766 }
1767 }
Mike Lockwood726d4de2014-10-28 14:06:28 -07001768 }
1769 }
1770 }
fredc0f420372012-04-12 00:02:00 -07001771}