blob: 46a4599dad36252995247df1023c929566ce471f [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;
Zhihai Xu40874a02012-10-08 17:57:03 -070044import android.os.Process;
fredcd6883532012-04-25 17:46:13 -070045import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070046import android.os.RemoteException;
Zhihai Xu40874a02012-10-08 17:57:03 -070047import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070048import android.os.UserHandle;
Benjamin Franze8b98922014-11-12 15:57:54 +000049import android.os.UserManager;
fredc0f420372012-04-12 00:02:00 -070050import android.provider.Settings;
51import android.util.Log;
Mike Lockwood726d4de2014-10-28 14:06:28 -070052
53import java.io.FileDescriptor;
54import java.io.PrintWriter;
55
Benjamin Franze8b98922014-11-12 15:57:54 +000056import java.util.HashMap;
57import java.util.Map;
58import java.util.List;
59import java.util.Vector;
60
Nitin Arora6ddbb5e2015-03-02 15:03:51 -080061import java.util.*;
fredc0f420372012-04-12 00:02:00 -070062class BluetoothManagerService extends IBluetoothManager.Stub {
63 private static final String TAG = "BluetoothManagerService";
64 private static final boolean DBG = true;
65
fredc0f420372012-04-12 00:02:00 -070066 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
67 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070068 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
69 private static final String EXTRA_ACTION="action";
Zhihai Xud31c3222012-10-31 16:08:57 -070070 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
fredc0f420372012-04-12 00:02:00 -070071 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
72 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070073 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
74 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053075 //Maximum msec to wait for service restart
76 private static final int SERVICE_RESTART_TIME_MS = 200;
Zhihai Xudd9d17d2013-01-08 17:05:58 -080077 //Maximum msec to wait for restart due to error
78 private static final int ERROR_RESTART_TIME_MS = 3000;
Zhihai Xu40874a02012-10-08 17:57:03 -070079 //Maximum msec to delay MESSAGE_USER_SWITCHED
80 private static final int USER_SWITCHED_TIME_MS = 200;
Benjamin Franze8b98922014-11-12 15:57:54 +000081 // Delay for the addProxy function in msec
82 private static final int ADD_PROXY_DELAY_MS = 100;
fredc0f420372012-04-12 00:02:00 -070083
84 private static final int MESSAGE_ENABLE = 1;
85 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070086 private static final int MESSAGE_REGISTER_ADAPTER = 20;
87 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
88 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
89 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
90 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
91 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053092 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070093 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070094 private static final int MESSAGE_TIMEOUT_BIND =100;
95 private static final int MESSAGE_TIMEOUT_UNBIND =101;
96 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
97 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
Zhihai Xu40874a02012-10-08 17:57:03 -070098 private static final int MESSAGE_USER_SWITCHED = 300;
Benjamin Franze8b98922014-11-12 15:57:54 +000099 private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
100 private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
fredc0f420372012-04-12 00:02:00 -0700101 private static final int MAX_SAVE_RETRIES=3;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800102 private static final int MAX_ERROR_RESTART_RETRIES=6;
103
Zhihai Xu401202b2012-12-03 11:36:21 -0800104 // Bluetooth persisted setting is off
105 private static final int BLUETOOTH_OFF=0;
106 // Bluetooth persisted setting is on
107 // and Airplane mode won't affect Bluetooth state at start up
108 private static final int BLUETOOTH_ON_BLUETOOTH=1;
109 // Bluetooth persisted setting is on
110 // but Airplane mode will affect Bluetooth state at start up
111 // and Airplane mode will have higher priority.
112 private static final int BLUETOOTH_ON_AIRPLANE=2;
fredc0f420372012-04-12 00:02:00 -0700113
Matthew Xieddf7e472013-03-01 18:41:02 -0800114 private static final int SERVICE_IBLUETOOTH = 1;
115 private static final int SERVICE_IBLUETOOTHGATT = 2;
116
fredc0f420372012-04-12 00:02:00 -0700117 private final Context mContext;
Nitin Arora6ddbb5e2015-03-02 15:03:51 -0800118 private static int mBleAppCount = 0;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700119
120 // Locks are not provided for mName and mAddress.
121 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -0700122 private String mAddress;
123 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -0700124 private final ContentResolver mContentResolver;
125 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
126 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -0700127 private IBluetooth mBluetooth;
Matthew Xieddf7e472013-03-01 18:41:02 -0800128 private IBluetoothGatt mBluetoothGatt;
fredc649fe492012-04-19 01:07:18 -0700129 private boolean mBinding;
130 private boolean mUnbinding;
Zhihai Xu401202b2012-12-03 11:36:21 -0800131 // used inside handler thread
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700132 private boolean mQuietEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800133 // configuarion from external IBinder call which is used to
134 // synchronize with broadcast receiver.
135 private boolean mQuietEnableExternal;
136 // configuarion from external IBinder call which is used to
137 // synchronize with broadcast receiver.
138 private boolean mEnableExternal;
139 // used inside handler thread
Zhihai Xu40874a02012-10-08 17:57:03 -0700140 private boolean mEnable;
141 private int mState;
Zhihai Xu40874a02012-10-08 17:57:03 -0700142 private final BluetoothHandler mHandler;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800143 private int mErrorRecoveryRetryCounter;
Adrian Roosbd9a9a52014-08-18 15:31:57 +0200144 private final int mSystemUiUid;
fredc0f420372012-04-12 00:02:00 -0700145
Benjamin Franze8b98922014-11-12 15:57:54 +0000146 // Save a ProfileServiceConnections object for each of the bound
147 // bluetooth profile services
148 private final Map <Integer, ProfileServiceConnections> mProfileServices =
149 new HashMap <Integer, ProfileServiceConnections>();
150
fredc649fe492012-04-19 01:07:18 -0700151 private void registerForAirplaneMode(IntentFilter filter) {
152 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700153 final String airplaneModeRadios = Settings.Global.getString(resolver,
154 Settings.Global.AIRPLANE_MODE_RADIOS);
155 final String toggleableRadios = Settings.Global.getString(resolver,
156 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700157 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700158 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700159 if (mIsAirplaneSensitive) {
160 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
161 }
162 }
163
fredcbf072a72012-05-09 16:52:50 -0700164 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
165 @Override
166 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
167 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
168 mHandler.sendMessage(msg);
169 }
170 };
171
172 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700173 @Override
174 public void onReceive(Context context, Intent intent) {
175 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700176 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700177 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700178 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700179 if (newName != null) {
180 storeNameAndAddress(newName, null);
181 }
fredc649fe492012-04-19 01:07:18 -0700182 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
Zhihai Xu401202b2012-12-03 11:36:21 -0800183 synchronized(mReceiver) {
184 if (isBluetoothPersistedStateOn()) {
185 if (isAirplaneModeOn()) {
186 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
187 } else {
188 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
189 }
190 }
Nitin Arora6ddbb5e2015-03-02 15:03:51 -0800191
192 int st = BluetoothAdapter.STATE_OFF;
193 if (mBluetooth != null) {
194 try {
195 st = mBluetooth.getState();
196 } catch (RemoteException e) {
197 Log.e(TAG,"Unable to call getState", e);
198 }
199 }
200 Log.d(TAG, "state" + st);
201
Zhihai Xu401202b2012-12-03 11:36:21 -0800202 if (isAirplaneModeOn()) {
Nitin Arora6ddbb5e2015-03-02 15:03:51 -0800203 // Clear registered LE apps to force shut-off
204 synchronized (this) {
205 mBleAppCount = 0;
206 }
207 if (st == BluetoothAdapter.STATE_BLE_ON) {
208 //if state is BLE_ON make sure you trigger disableBLE part
209 try {
210 if (mBluetooth != null) {
211 mBluetooth.onBrEdrDown();
212 mEnableExternal = false;
213 }
214 } catch(RemoteException e) {
215 Log.e(TAG,"Unable to call onBrEdrDown", e);
216 }
217 } else if (st == BluetoothAdapter.STATE_ON){
218 // disable without persisting the setting
219 Log.d(TAG, "Calling disable");
220 sendDisableMsg();
221 }
Zhihai Xu401202b2012-12-03 11:36:21 -0800222 } else if (mEnableExternal) {
223 // enable without persisting the setting
Nitin Arora6ddbb5e2015-03-02 15:03:51 -0800224 Log.d(TAG, "Calling enable");
Zhihai Xu401202b2012-12-03 11:36:21 -0800225 sendEnableMsg(mQuietEnableExternal);
226 }
fredc649fe492012-04-19 01:07:18 -0700227 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700228 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
229 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
230 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Zhihai Xu401202b2012-12-03 11:36:21 -0800231 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
232 synchronized(mReceiver) {
233 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
234 //Enable
235 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
236 sendEnableMsg(mQuietEnableExternal);
237 }
238 }
fredc0f420372012-04-12 00:02:00 -0700239 }
240 }
241 };
242
243 BluetoothManagerService(Context context) {
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700244 mHandler = new BluetoothHandler(IoThread.get().getLooper());
Zhihai Xu40874a02012-10-08 17:57:03 -0700245
fredc0f420372012-04-12 00:02:00 -0700246 mContext = context;
247 mBluetooth = null;
Nitin Arora6ddbb5e2015-03-02 15:03:51 -0800248 mBluetoothGatt = null;
fredc0f420372012-04-12 00:02:00 -0700249 mBinding = false;
250 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700251 mEnable = false;
252 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu401202b2012-12-03 11:36:21 -0800253 mQuietEnableExternal = false;
254 mEnableExternal = false;
fredc0f420372012-04-12 00:02:00 -0700255 mAddress = null;
256 mName = null;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800257 mErrorRecoveryRetryCounter = 0;
fredc0f420372012-04-12 00:02:00 -0700258 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700259 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
260 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Zhihai Xu401202b2012-12-03 11:36:21 -0800261 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700262 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700263 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700264 registerForAirplaneMode(filter);
Dianne Hackbornd83a0962014-05-02 16:28:33 -0700265 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Matthew Xie6fde3092012-07-11 17:10:07 -0700266 mContext.registerReceiver(mReceiver, filter);
fredc0f420372012-04-12 00:02:00 -0700267 loadStoredNameAndAddress();
Zhihai Xu401202b2012-12-03 11:36:21 -0800268 if (isBluetoothPersistedStateOn()) {
269 mEnableExternal = true;
fredc0f420372012-04-12 00:02:00 -0700270 }
Adrian Roosbd9a9a52014-08-18 15:31:57 +0200271
272 int sysUiUid = -1;
273 try {
274 sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui",
275 UserHandle.USER_OWNER);
276 } catch (PackageManager.NameNotFoundException e) {
277 Log.wtf(TAG, "Unable to resolve SystemUI's UID.", e);
278 }
279 mSystemUiUid = sysUiUid;
fredc0f420372012-04-12 00:02:00 -0700280 }
281
fredc649fe492012-04-19 01:07:18 -0700282 /**
283 * Returns true if airplane mode is currently on
284 */
285 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700286 return Settings.Global.getInt(mContext.getContentResolver(),
287 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700288 }
289
290 /**
291 * Returns true if the Bluetooth saved state is "on"
292 */
293 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700294 return Settings.Global.getInt(mContentResolver,
Zhihai Xu401202b2012-12-03 11:36:21 -0800295 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
296 }
297
298 /**
299 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
300 */
301 private final boolean isBluetoothPersistedStateOnBluetooth() {
302 return Settings.Global.getInt(mContentResolver,
303 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
fredc649fe492012-04-19 01:07:18 -0700304 }
305
306 /**
307 * Save the Bluetooth on/off state
308 *
309 */
Zhihai Xu401202b2012-12-03 11:36:21 -0800310 private void persistBluetoothSetting(int value) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700311 Settings.Global.putInt(mContext.getContentResolver(),
312 Settings.Global.BLUETOOTH_ON,
Zhihai Xu401202b2012-12-03 11:36:21 -0800313 value);
fredc649fe492012-04-19 01:07:18 -0700314 }
315
316 /**
317 * Returns true if the Bluetooth Adapter's name and address is
318 * locally cached
319 * @return
320 */
fredc0f420372012-04-12 00:02:00 -0700321 private boolean isNameAndAddressSet() {
322 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
323 }
324
fredc649fe492012-04-19 01:07:18 -0700325 /**
326 * Retrieve the Bluetooth Adapter's name and address and save it in
327 * in the local cache
328 */
fredc0f420372012-04-12 00:02:00 -0700329 private void loadStoredNameAndAddress() {
330 if (DBG) Log.d(TAG, "Loading stored name and address");
Zhihai Xud31c3222012-10-31 16:08:57 -0700331 if (mContext.getResources().getBoolean
332 (com.android.internal.R.bool.config_bluetooth_address_validation) &&
333 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
334 // if the valid flag is not set, don't load the address and name
335 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
336 return;
337 }
fredc0f420372012-04-12 00:02:00 -0700338 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
339 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
Zhihai Xud31c3222012-10-31 16:08:57 -0700340 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
fredc0f420372012-04-12 00:02:00 -0700341 }
342
fredc649fe492012-04-19 01:07:18 -0700343 /**
344 * Save the Bluetooth name and address in the persistent store.
345 * Only non-null values will be saved.
346 * @param name
347 * @param address
348 */
fredc0f420372012-04-12 00:02:00 -0700349 private void storeNameAndAddress(String name, String address) {
350 if (name != null) {
351 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700352 mName = name;
fredc649fe492012-04-19 01:07:18 -0700353 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
354 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700355 }
356
357 if (address != null) {
358 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700359 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700360 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
361 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700362 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700363
364 if ((name != null) && (address != null)) {
365 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
366 }
fredc0f420372012-04-12 00:02:00 -0700367 }
368
369 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
Natalie Silvanovich55db6462014-05-01 16:12:23 -0700370 if (callback == null) {
371 Log.w(TAG, "Callback is null in registerAdapter");
372 return null;
373 }
fredc0f420372012-04-12 00:02:00 -0700374 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
375 msg.obj = callback;
376 mHandler.sendMessage(msg);
377 synchronized(mConnection) {
378 return mBluetooth;
379 }
380 }
381
382 public void unregisterAdapter(IBluetoothManagerCallback callback) {
Natalie Silvanovich55db6462014-05-01 16:12:23 -0700383 if (callback == null) {
384 Log.w(TAG, "Callback is null in unregisterAdapter");
385 return;
386 }
fredc0f420372012-04-12 00:02:00 -0700387 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
388 "Need BLUETOOTH permission");
389 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
390 msg.obj = callback;
391 mHandler.sendMessage(msg);
392 }
393
394 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
395 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
396 "Need BLUETOOTH permission");
397 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
398 msg.obj = callback;
399 mHandler.sendMessage(msg);
400 }
401
402 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
403 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
404 "Need BLUETOOTH permission");
405 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
406 msg.obj = callback;
407 mHandler.sendMessage(msg);
408 }
409
410 public boolean isEnabled() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800411 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
412 (!checkIfCallerIsForegroundUser())) {
413 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700414 return false;
415 }
416
fredc0f420372012-04-12 00:02:00 -0700417 synchronized(mConnection) {
418 try {
419 return (mBluetooth != null && mBluetooth.isEnabled());
420 } catch (RemoteException e) {
421 Log.e(TAG, "isEnabled()", e);
422 }
423 }
424 return false;
425 }
426
Nitin Arora6ddbb5e2015-03-02 15:03:51 -0800427 class ClientDeathRecipient implements IBinder.DeathRecipient {
428 public void binderDied() {
429 if (DBG) Log.d(TAG, "Binder is dead - unregister Ble App");
430 if (mBleAppCount > 0) --mBleAppCount;
431
432 if (mBleAppCount == 0) {
433 if (DBG) Log.d(TAG, "Disabling LE only mode after application crash");
434 try {
435 if (mBluetooth != null) {
436 mBluetooth.onBrEdrDown();
437 }
438 } catch(RemoteException e) {
439 Log.e(TAG,"Unable to call onBrEdrDown", e);
440 }
441 }
442 }
443 }
444
445 /** Internal death rec list */
446 Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>();
447
448 public int updateBleAppCount(IBinder token, boolean enable) {
449 if (enable) {
450 ClientDeathRecipient r = mBleApps.get(token);
451 if (r == null) {
452 ClientDeathRecipient deathRec = new ClientDeathRecipient();
453 try {
454 token.linkToDeath(deathRec, 0);
455 } catch (RemoteException ex) {
456 throw new IllegalArgumentException("Wake lock is already dead.");
457 }
458 mBleApps.put(token, deathRec);
459 synchronized (this) {
460 ++mBleAppCount;
461 }
462 if (DBG) Log.d(TAG, "Registered for death Notification");
463 }
464
465 } else {
466 ClientDeathRecipient r = mBleApps.get(token);
467 if (r != null) {
468 try {
469 token.linkToDeath(r, 0);
470 } catch (RemoteException ex) {
471 throw new IllegalArgumentException("Wake lock is already dead.");
472 }
473 mBleApps.remove(token);
474 synchronized (this) {
475 if (mBleAppCount > 0) --mBleAppCount;
476 }
477 if (DBG) Log.d(TAG, "Unregistered for death Notification");
478 }
479 }
480 if (DBG) Log.d(TAG, "Updated BleAppCount" + mBleAppCount);
481 if (mBleAppCount == 0 && mEnable) {
482 try {
483 if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
484 if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
485 mEnable = false;
486 }
487 } catch (RemoteException e) {
488 Log.e(TAG, "getState()", e);
489 }
490 }
491 return mBleAppCount;
492 }
493
494 /** @hide*/
495 public boolean isBleAppPresent() {
496 if (DBG) Log.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
497 return (mBleAppCount > 0);
498 }
499
500 /**
501 * Action taken when GattService is turned off
502 */
503 private void onBluetoothGattServiceUp() {
504 if (DBG) Log.d(TAG,"BluetoothGatt Service is Up");
505 try{
506 if (isBleAppPresent() == false && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
507 mBluetooth.onLeServiceUp();
508
509 // waive WRITE_SECURE_SETTINGS permission check
510 long callingIdentity = Binder.clearCallingIdentity();
511 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
512 Binder.restoreCallingIdentity(callingIdentity);
513 }
514 } catch(RemoteException e) {
515 Log.e(TAG,"Unable to call onServiceUp", e);
516 }
517 }
518
519 /**
520 * Inform BluetoothAdapter instances that BREDR part is down
521 * and turn off all service and stack if no LE app needs it
522 */
523 private void sendBrEdrDownCallback() {
524 if (DBG) Log.d(TAG,"Calling sendBrEdrDownCallback callbacks");
525 int n = mCallbacks.beginBroadcast();
526
527 if (isBleAppPresent() == false) {
528 try {
529 mBluetooth.onBrEdrDown();
530 } catch(RemoteException e) {
531 Log.e(TAG,"Unable to call onBrEdrDown", e);
532 }
533 }
534 else{//need to stay at BLE ON. disconnect all Gatt connections
535 try{
536 mBluetoothGatt.unregAll();//disconnectAll();
537 } catch(RemoteException e) {
538 Log.e(TAG,"Unable to disconn all", e);
539 }
540 }
541
542 Log.d(TAG,"Broadcasting onBrEdrDown() to " + n + " receivers.");
543 for (int i=0; i <n; i++) {
544 try {
545 mCallbacks.getBroadcastItem(i).onBrEdrDown();
546 } catch (RemoteException e) {
547 Log.e(TAG, "Unable to call sendBrEdrDownCallback() on callback #" + i, e);
548 }
549 }
550 mCallbacks.finishBroadcast();
551 }
552
553 /** @hide*/
fredc0f420372012-04-12 00:02:00 -0700554 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700555 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700556 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
557 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700558 }
fredc0f420372012-04-12 00:02:00 -0700559 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
560 mHandler.sendMessage(msg);
561 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700562 public boolean enableNoAutoConnect()
563 {
564 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
565 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700566
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700567 if (DBG) {
568 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
569 " mBinding = " + mBinding);
570 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800571 int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
572
573 if (callingAppId != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700574 throw new SecurityException("no permission to enable Bluetooth quietly");
575 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800576
Zhihai Xu401202b2012-12-03 11:36:21 -0800577 synchronized(mReceiver) {
578 mQuietEnableExternal = true;
579 mEnableExternal = true;
580 sendEnableMsg(true);
581 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700582 return true;
583
584 }
fredc0f420372012-04-12 00:02:00 -0700585 public boolean enable() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800586 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
587 (!checkIfCallerIsForegroundUser())) {
588 Log.w(TAG,"enable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700589 return false;
fredcf2458862012-04-16 15:18:27 -0700590 }
591
Zhihai Xu401202b2012-12-03 11:36:21 -0800592 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
593 "Need BLUETOOTH ADMIN permission");
594 if (DBG) {
595 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
596 " mBinding = " + mBinding);
597 }
598
599 synchronized(mReceiver) {
600 mQuietEnableExternal = false;
601 mEnableExternal = true;
602 // waive WRITE_SECURE_SETTINGS permission check
Zhihai Xu401202b2012-12-03 11:36:21 -0800603 sendEnableMsg(false);
604 }
Nitin Arora6ddbb5e2015-03-02 15:03:51 -0800605 if (DBG) Log.d(TAG, "enable returning");
Zhihai Xu401202b2012-12-03 11:36:21 -0800606 return true;
fredc0f420372012-04-12 00:02:00 -0700607 }
608
609 public boolean disable(boolean persist) {
610 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
611 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700612
Zhihai Xu6eb76522012-11-29 15:41:04 -0800613 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
614 (!checkIfCallerIsForegroundUser())) {
615 Log.w(TAG,"disable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700616 return false;
617 }
618
fredcf2458862012-04-16 15:18:27 -0700619 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700620 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
621 " mBinding = " + mBinding);
622 }
fredcf2458862012-04-16 15:18:27 -0700623
Zhihai Xu401202b2012-12-03 11:36:21 -0800624 synchronized(mReceiver) {
625 if (persist) {
626 // waive WRITE_SECURE_SETTINGS permission check
627 long callingIdentity = Binder.clearCallingIdentity();
628 persistBluetoothSetting(BLUETOOTH_OFF);
629 Binder.restoreCallingIdentity(callingIdentity);
630 }
631 mEnableExternal = false;
632 sendDisableMsg();
633 }
fredc0f420372012-04-12 00:02:00 -0700634 return true;
635 }
636
fredc649fe492012-04-19 01:07:18 -0700637 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700638 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700639 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
640 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700641 }
642
fredc0f420372012-04-12 00:02:00 -0700643 synchronized (mConnection) {
644 if (mUnbinding) return;
645 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700646 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700647 if (!mConnection.isGetNameAddressOnly()) {
648 //Unregister callback object
649 try {
650 mBluetooth.unregisterCallback(mBluetoothCallback);
651 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700652 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700653 }
654 }
fredc0f420372012-04-12 00:02:00 -0700655 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700656 mBluetooth = null;
657 //Unbind
fredc0f420372012-04-12 00:02:00 -0700658 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700659 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700660 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700661 } else {
662 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700663 }
Nitin Arora6ddbb5e2015-03-02 15:03:51 -0800664 mBluetoothGatt = null;
fredc0f420372012-04-12 00:02:00 -0700665 }
666 }
667
Matthew Xieddf7e472013-03-01 18:41:02 -0800668 public IBluetoothGatt getBluetoothGatt() {
669 // sync protection
670 return mBluetoothGatt;
671 }
672
Benjamin Franze8b98922014-11-12 15:57:54 +0000673 @Override
674 public boolean bindBluetoothProfileService(int bluetoothProfile,
675 IBluetoothProfileServiceConnection proxy) {
676 if (!mEnable) {
677 if (DBG) {
678 Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
679 ", while Bluetooth was disabled");
680 }
681 return false;
682 }
683 synchronized (mProfileServices) {
684 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
685 if (psc == null) {
686 if (DBG) {
687 Log.d(TAG, "Creating new ProfileServiceConnections object for"
688 + " profile: " + bluetoothProfile);
689 }
Benjamin Franz5b614592014-12-09 18:58:45 +0000690
691 if (bluetoothProfile != BluetoothProfile.HEADSET) return false;
692
693 Intent intent = new Intent(IBluetoothHeadset.class.getName());
Benjamin Franze8b98922014-11-12 15:57:54 +0000694 psc = new ProfileServiceConnections(intent);
Benjamin Franz5b614592014-12-09 18:58:45 +0000695 if (!psc.bindService()) return false;
696
Benjamin Franze8b98922014-11-12 15:57:54 +0000697 mProfileServices.put(new Integer(bluetoothProfile), psc);
Benjamin Franze8b98922014-11-12 15:57:54 +0000698 }
699 }
700
701 // Introducing a delay to give the client app time to prepare
702 Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
703 addProxyMsg.arg1 = bluetoothProfile;
704 addProxyMsg.obj = proxy;
705 mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
706 return true;
707 }
708
709 @Override
710 public void unbindBluetoothProfileService(int bluetoothProfile,
711 IBluetoothProfileServiceConnection proxy) {
712 synchronized (mProfileServices) {
713 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
714 if (psc == null) {
715 return;
716 }
717 psc.removeProxy(proxy);
718 }
719 }
720
721 private void unbindAllBluetoothProfileServices() {
722 synchronized (mProfileServices) {
723 for (Integer i : mProfileServices.keySet()) {
724 ProfileServiceConnections psc = mProfileServices.get(i);
Benjamin Franz5b614592014-12-09 18:58:45 +0000725 try {
726 mContext.unbindService(psc);
727 } catch (IllegalArgumentException e) {
728 Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
729 }
Benjamin Franze8b98922014-11-12 15:57:54 +0000730 psc.removeAllProxies();
731 }
732 mProfileServices.clear();
733 }
734 }
735
736 /**
737 * This class manages the clients connected to a given ProfileService
738 * and maintains the connection with that service.
739 */
740 final private class ProfileServiceConnections implements ServiceConnection,
741 IBinder.DeathRecipient {
742 final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
743 new RemoteCallbackList <IBluetoothProfileServiceConnection>();
744 IBinder mService;
745 ComponentName mClassName;
746 Intent mIntent;
747
748 ProfileServiceConnections(Intent intent) {
749 mService = null;
750 mClassName = null;
751 mIntent = intent;
752 }
753
Benjamin Franz5b614592014-12-09 18:58:45 +0000754 private boolean bindService() {
755 if (mIntent != null && mService == null &&
756 doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
Benjamin Franze8b98922014-11-12 15:57:54 +0000757 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
758 msg.obj = this;
759 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
Benjamin Franz5b614592014-12-09 18:58:45 +0000760 return true;
Benjamin Franze8b98922014-11-12 15:57:54 +0000761 }
Benjamin Franz5b614592014-12-09 18:58:45 +0000762 Log.w(TAG, "Unable to bind with intent: " + mIntent);
763 return false;
Benjamin Franze8b98922014-11-12 15:57:54 +0000764 }
765
766 private void addProxy(IBluetoothProfileServiceConnection proxy) {
767 mProxies.register(proxy);
768 if (mService != null) {
769 try{
770 proxy.onServiceConnected(mClassName, mService);
771 } catch (RemoteException e) {
772 Log.e(TAG, "Unable to connect to proxy", e);
773 }
774 } else {
775 if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
776 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
777 msg.obj = this;
778 mHandler.sendMessage(msg);
779 }
780 }
781 }
782
783 private void removeProxy(IBluetoothProfileServiceConnection proxy) {
784 if (proxy != null) {
785 if (mProxies.unregister(proxy)) {
786 try {
787 proxy.onServiceDisconnected(mClassName);
788 } catch (RemoteException e) {
789 Log.e(TAG, "Unable to disconnect proxy", e);
790 }
791 }
792 } else {
793 Log.w(TAG, "Trying to remove a null proxy");
794 }
795 }
796
797 private void removeAllProxies() {
798 onServiceDisconnected(mClassName);
799 mProxies.kill();
800 }
801
802 @Override
803 public void onServiceConnected(ComponentName className, IBinder service) {
804 // remove timeout message
805 mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
806 mService = service;
807 mClassName = className;
808 try {
809 mService.linkToDeath(this, 0);
810 } catch (RemoteException e) {
811 Log.e(TAG, "Unable to linkToDeath", e);
812 }
813 int n = mProxies.beginBroadcast();
814 for (int i = 0; i < n; i++) {
815 try {
816 mProxies.getBroadcastItem(i).onServiceConnected(className, service);
817 } catch (RemoteException e) {
818 Log.e(TAG, "Unable to connect to proxy", e);
819 }
820 }
821 mProxies.finishBroadcast();
822 }
823
824 @Override
825 public void onServiceDisconnected(ComponentName className) {
826 if (mService == null) {
827 return;
828 }
829 mService.unlinkToDeath(this, 0);
830 mService = null;
831 mClassName = null;
832 int n = mProxies.beginBroadcast();
833 for (int i = 0; i < n; i++) {
834 try {
835 mProxies.getBroadcastItem(i).onServiceDisconnected(className);
836 } catch (RemoteException e) {
837 Log.e(TAG, "Unable to disconnect from proxy", e);
838 }
839 }
840 mProxies.finishBroadcast();
841 }
842
843 @Override
844 public void binderDied() {
845 if (DBG) {
846 Log.w(TAG, "Profile service for profile: " + mClassName
847 + " died.");
848 }
849 onServiceDisconnected(mClassName);
850 // Trigger rebind
851 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
852 msg.obj = this;
853 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
854 }
855 }
856
fredcbf072a72012-05-09 16:52:50 -0700857 private void sendBluetoothStateCallback(boolean isUp) {
858 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700859 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700860 for (int i=0; i <n;i++) {
861 try {
862 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
863 } catch (RemoteException e) {
864 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
865 }
866 }
867 mStateChangeCallbacks.finishBroadcast();
868 }
869
870 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700871 * Inform BluetoothAdapter instances that Adapter service is up
872 */
873 private void sendBluetoothServiceUpCallback() {
874 if (!mConnection.isGetNameAddressOnly()) {
875 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
876 int n = mCallbacks.beginBroadcast();
877 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
878 for (int i=0; i <n;i++) {
879 try {
880 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
881 } catch (RemoteException e) {
882 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
883 }
884 }
885 mCallbacks.finishBroadcast();
886 }
887 }
888 /**
fredcbf072a72012-05-09 16:52:50 -0700889 * Inform BluetoothAdapter instances that Adapter service is down
890 */
891 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700892 if (!mConnection.isGetNameAddressOnly()) {
893 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
894 int n = mCallbacks.beginBroadcast();
895 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
896 for (int i=0; i <n;i++) {
897 try {
898 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
899 } catch (RemoteException e) {
900 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
901 }
902 }
903 mCallbacks.finishBroadcast();
904 }
905 }
fredc0f420372012-04-12 00:02:00 -0700906 public String getAddress() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800907 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
908 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700909
Zhihai Xu6eb76522012-11-29 15:41:04 -0800910 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
911 (!checkIfCallerIsForegroundUser())) {
912 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
913 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700914 }
915
fredc116d1d462012-04-20 14:47:08 -0700916 synchronized(mConnection) {
917 if (mBluetooth != null) {
918 try {
919 return mBluetooth.getAddress();
920 } catch (RemoteException e) {
921 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
922 }
923 }
924 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700925 // mAddress is accessed from outside.
926 // It is alright without a lock. Here, bluetooth is off, no other thread is
927 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700928 return mAddress;
929 }
fredc649fe492012-04-19 01:07:18 -0700930
fredc0f420372012-04-12 00:02:00 -0700931 public String getName() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800932 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
933 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700934
Zhihai Xu6eb76522012-11-29 15:41:04 -0800935 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
936 (!checkIfCallerIsForegroundUser())) {
937 Log.w(TAG,"getName(): not allowed for non-active and non system user");
938 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700939 }
940
fredc116d1d462012-04-20 14:47:08 -0700941 synchronized(mConnection) {
942 if (mBluetooth != null) {
943 try {
944 return mBluetooth.getName();
945 } catch (RemoteException e) {
946 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
947 }
948 }
949 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700950 // mName is accessed from outside.
951 // It alright without a lock. Here, bluetooth is off, no other thread is
952 // changing mName
fredc0f420372012-04-12 00:02:00 -0700953 return mName;
954 }
955
fredc0f420372012-04-12 00:02:00 -0700956 private class BluetoothServiceConnection implements ServiceConnection {
957
958 private boolean mGetNameAddressOnly;
959
960 public void setGetNameAddressOnly(boolean getOnly) {
961 mGetNameAddressOnly = getOnly;
962 }
963
964 public boolean isGetNameAddressOnly() {
965 return mGetNameAddressOnly;
966 }
967
968 public void onServiceConnected(ComponentName className, IBinder service) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800969 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700970 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800971 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
972 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
973 msg.arg1 = SERVICE_IBLUETOOTH;
974 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
975 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
976 msg.arg1 = SERVICE_IBLUETOOTHGATT;
977 } else {
978 Log.e(TAG, "Unknown service connected: " + className.getClassName());
979 return;
980 }
fredc0f420372012-04-12 00:02:00 -0700981 msg.obj = service;
982 mHandler.sendMessage(msg);
983 }
984
985 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700986 // Called if we unexpected disconnected.
Matthew Xieddf7e472013-03-01 18:41:02 -0800987 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
988 className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700989 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800990 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
991 msg.arg1 = SERVICE_IBLUETOOTH;
992 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
993 msg.arg1 = SERVICE_IBLUETOOTHGATT;
994 } else {
995 Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
996 return;
997 }
fredc0f420372012-04-12 00:02:00 -0700998 mHandler.sendMessage(msg);
999 }
1000 }
1001
1002 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
1003
Zhihai Xu40874a02012-10-08 17:57:03 -07001004 private class BluetoothHandler extends Handler {
1005 public BluetoothHandler(Looper looper) {
1006 super(looper);
1007 }
1008
fredc0f420372012-04-12 00:02:00 -07001009 @Override
1010 public void handleMessage(Message msg) {
1011 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -07001012 switch (msg.what) {
1013 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -07001014 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -07001015 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -07001016 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -07001017 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -07001018 if (DBG) Log.d(TAG, "Binding to service to get name and address");
1019 mConnection.setGetNameAddressOnly(true);
1020 //Start bind timeout and bind
1021 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1022 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1023 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackborn221ea892013-08-04 16:50:16 -07001024 if (!doBind(i, mConnection,
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001025 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1026 UserHandle.CURRENT)) {
fredc0f420372012-04-12 00:02:00 -07001027 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -07001028 } else {
1029 mBinding = true;
fredc0f420372012-04-12 00:02:00 -07001030 }
1031 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001032 else {
1033 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -07001034 saveMsg.arg1 = 0;
1035 if (mBluetooth != null) {
1036 mHandler.sendMessage(saveMsg);
1037 } else {
1038 // if enable is also called to bind the service
1039 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
1040 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
1041 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001042 }
fredc0f420372012-04-12 00:02:00 -07001043 }
fredc649fe492012-04-19 01:07:18 -07001044 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001045 }
fredc0f420372012-04-12 00:02:00 -07001046 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -07001047 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -07001048 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -07001049 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -07001050 if (!mEnable && mBluetooth != null) {
1051 try {
1052 mBluetooth.enable();
1053 } catch (RemoteException e) {
1054 Log.e(TAG,"Unable to call enable()",e);
1055 }
1056 }
1057 }
1058 if (mBluetooth != null) waitForOnOff(true, false);
1059 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001060 if (mBluetooth != null) {
1061 String name = null;
1062 String address = null;
1063 try {
1064 name = mBluetooth.getName();
1065 address = mBluetooth.getAddress();
1066 } catch (RemoteException re) {
1067 Log.e(TAG,"",re);
1068 }
fredc0f420372012-04-12 00:02:00 -07001069
Matthew Xiecdce0b92012-07-12 19:06:15 -07001070 if (name != null && address != null) {
1071 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -07001072 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -07001073 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -07001074 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001075 } else {
1076 if (msg.arg1 < MAX_SAVE_RETRIES) {
1077 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
1078 retryMsg.arg1= 1+msg.arg1;
1079 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
1080 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
1081 } else {
1082 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -07001083 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -07001084 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -07001085 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001086 }
fredc0f420372012-04-12 00:02:00 -07001087 }
Zhihai Xud31c3222012-10-31 16:08:57 -07001088 if (!mEnable) {
1089 try {
1090 mBluetooth.disable();
1091 } catch (RemoteException e) {
1092 Log.e(TAG,"Unable to call disable()",e);
1093 }
1094 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001095 } else {
1096 // rebind service by Request GET NAME AND ADDRESS
1097 // if service is unbinded by disable or
1098 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
1099 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1100 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -07001101 }
1102 }
Zhihai Xud31c3222012-10-31 16:08:57 -07001103 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
1104 if (unbind) {
1105 unbindAndFinish();
1106 }
fredc649fe492012-04-19 01:07:18 -07001107 break;
fredc649fe492012-04-19 01:07:18 -07001108 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001109 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -07001110 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001111 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -07001112 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001113 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1114 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -08001115 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -07001116 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001117
fredc0f420372012-04-12 00:02:00 -07001118 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -07001119 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1120 if (mEnable && mBluetooth != null) {
1121 waitForOnOff(true, false);
1122 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -08001123 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001124 waitForOnOff(false, false);
1125 } else {
1126 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -08001127 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001128 }
fredc0f420372012-04-12 00:02:00 -07001129 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001130
fredc0f420372012-04-12 00:02:00 -07001131 case MESSAGE_REGISTER_ADAPTER:
1132 {
1133 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -07001134 boolean added = mCallbacks.register(callback);
1135 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -07001136 }
1137 break;
1138 case MESSAGE_UNREGISTER_ADAPTER:
1139 {
1140 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -07001141 boolean removed = mCallbacks.unregister(callback);
1142 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -07001143 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001144 }
fredc0f420372012-04-12 00:02:00 -07001145 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
1146 {
1147 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -07001148 if (callback != null) {
1149 mStateChangeCallbacks.register(callback);
1150 }
fredc0f420372012-04-12 00:02:00 -07001151 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001152 }
fredc0f420372012-04-12 00:02:00 -07001153 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
1154 {
1155 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -07001156 if (callback != null) {
1157 mStateChangeCallbacks.unregister(callback);
1158 }
fredc0f420372012-04-12 00:02:00 -07001159 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001160 }
Benjamin Franze8b98922014-11-12 15:57:54 +00001161 case MESSAGE_ADD_PROXY_DELAYED:
1162 {
1163 ProfileServiceConnections psc = mProfileServices.get(
1164 new Integer(msg.arg1));
1165 if (psc == null) {
1166 break;
1167 }
1168 IBluetoothProfileServiceConnection proxy =
1169 (IBluetoothProfileServiceConnection) msg.obj;
1170 psc.addProxy(proxy);
1171 break;
1172 }
1173 case MESSAGE_BIND_PROFILE_SERVICE:
1174 {
1175 ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
1176 removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
1177 if (psc == null) {
1178 break;
1179 }
1180 psc.bindService();
1181 break;
1182 }
fredc0f420372012-04-12 00:02:00 -07001183 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
1184 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001185 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
fredc0f420372012-04-12 00:02:00 -07001186
1187 IBinder service = (IBinder) msg.obj;
1188 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001189 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1190 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001191 onBluetoothGattServiceUp();
Matthew Xieddf7e472013-03-01 18:41:02 -08001192 break;
1193 } // else must be SERVICE_IBLUETOOTH
1194
1195 //Remove timeout
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001196 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Matthew Xieddf7e472013-03-01 18:41:02 -08001197
fredc0f420372012-04-12 00:02:00 -07001198 mBinding = false;
1199 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -07001200
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001201 try {
1202 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
1203 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
1204 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
1205 Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
1206 }
1207 } catch (RemoteException e) {
1208 Log.e(TAG,"Unable to call configHciSnoopLog", e);
1209 }
1210
Matthew Xiecdce0b92012-07-12 19:06:15 -07001211 if (mConnection.isGetNameAddressOnly()) {
1212 //Request GET NAME AND ADDRESS
1213 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1214 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -07001215 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001216 }
fredc0f420372012-04-12 00:02:00 -07001217
Zhihai Xu40874a02012-10-08 17:57:03 -07001218 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -07001219 //Register callback object
fredcbf072a72012-05-09 16:52:50 -07001220 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001221 mBluetooth.registerCallback(mBluetoothCallback);
1222 } catch (RemoteException re) {
1223 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -07001224 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001225 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -07001226 sendBluetoothServiceUpCallback();
1227
Matthew Xiecdce0b92012-07-12 19:06:15 -07001228 //Do enable request
1229 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001230 if (mQuietEnable == false) {
1231 if(!mBluetooth.enable()) {
1232 Log.e(TAG,"IBluetooth.enable() returned false");
1233 }
1234 }
1235 else
1236 {
1237 if(!mBluetooth.enableNoAutoConnect()) {
1238 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1239 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001240 }
1241 } catch (RemoteException e) {
1242 Log.e(TAG,"Unable to call enable()",e);
1243 }
Freda8c6df02012-07-11 10:25:23 -07001244 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001245
1246 if (!mEnable) {
1247 waitForOnOff(true, false);
Zhihai Xu401202b2012-12-03 11:36:21 -08001248 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001249 waitForOnOff(false, false);
1250 }
fredc649fe492012-04-19 01:07:18 -07001251 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001252 }
fredc649fe492012-04-19 01:07:18 -07001253 case MESSAGE_TIMEOUT_BIND: {
1254 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -07001255 synchronized(mConnection) {
1256 mBinding = false;
1257 }
fredc649fe492012-04-19 01:07:18 -07001258 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001259 }
fredcbf072a72012-05-09 16:52:50 -07001260 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -07001261 {
fredcbf072a72012-05-09 16:52:50 -07001262 int prevState = msg.arg1;
1263 int newState = msg.arg2;
1264 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -07001265 mState = newState;
1266 bluetoothStateChangeHandler(prevState, newState);
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001267 // handle error state transition case from TURNING_ON to OFF
1268 // unbind and rebind bluetooth service and enable bluetooth
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001269 if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001270 (newState == BluetoothAdapter.STATE_OFF) &&
1271 (mBluetooth != null) && mEnable) {
1272 recoverBluetoothServiceFromError();
1273 }
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001274 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
1275 (newState == BluetoothAdapter.STATE_BLE_ON) &&
1276 (mBluetooth != null) && mEnable) {
1277 recoverBluetoothServiceFromError();
1278 }
1279 if (newState == BluetoothAdapter.STATE_ON ||
1280 newState == BluetoothAdapter.STATE_BLE_ON) {
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001281 // bluetooth is working, reset the counter
1282 if (mErrorRecoveryRetryCounter != 0) {
1283 Log.w(TAG, "bluetooth is recovered from error");
1284 mErrorRecoveryRetryCounter = 0;
1285 }
1286 }
fredc649fe492012-04-19 01:07:18 -07001287 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001288 }
fredc0f420372012-04-12 00:02:00 -07001289 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
1290 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001291 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301292 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001293 if (msg.arg1 == SERVICE_IBLUETOOTH) {
1294 // if service is unbinded already, do nothing and return
1295 if (mBluetooth == null) break;
1296 mBluetooth = null;
1297 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1298 mBluetoothGatt = null;
1299 break;
1300 } else {
1301 Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
1302 break;
1303 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301304 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001305
1306 if (mEnable) {
1307 mEnable = false;
1308 // Send a Bluetooth Restart message
1309 Message restartMsg = mHandler.obtainMessage(
1310 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1311 mHandler.sendMessageDelayed(restartMsg,
1312 SERVICE_RESTART_TIME_MS);
1313 }
1314
1315 if (!mConnection.isGetNameAddressOnly()) {
1316 sendBluetoothServiceDownCallback();
1317
1318 // Send BT state broadcast to update
1319 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001320 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
1321 (mState == BluetoothAdapter.STATE_ON)) {
1322 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1323 BluetoothAdapter.STATE_TURNING_OFF);
1324 mState = BluetoothAdapter.STATE_TURNING_OFF;
1325 }
1326 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1327 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1328 BluetoothAdapter.STATE_OFF);
1329 }
1330
1331 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -07001332 mState = BluetoothAdapter.STATE_OFF;
1333 }
fredc649fe492012-04-19 01:07:18 -07001334 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001335 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301336 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
1337 {
1338 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
1339 +" Restart IBluetooth service");
1340 /* Enable without persisting the setting as
1341 it doesnt change when IBluetooth
1342 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -07001343 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -08001344 handleEnable(mQuietEnable);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301345 break;
1346 }
1347
fredc0f420372012-04-12 00:02:00 -07001348 case MESSAGE_TIMEOUT_UNBIND:
1349 {
fredc649fe492012-04-19 01:07:18 -07001350 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -07001351 synchronized(mConnection) {
1352 mUnbinding = false;
1353 }
fredc649fe492012-04-19 01:07:18 -07001354 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001355 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001356
1357 case MESSAGE_USER_SWITCHED:
1358 {
1359 if (DBG) {
1360 Log.d(TAG, "MESSAGE_USER_SWITCHED");
1361 }
1362 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1363 /* disable and enable BT when detect a user switch */
1364 if (mEnable && mBluetooth != null) {
1365 synchronized (mConnection) {
1366 if (mBluetooth != null) {
1367 //Unregister callback object
1368 try {
1369 mBluetooth.unregisterCallback(mBluetoothCallback);
1370 } catch (RemoteException re) {
1371 Log.e(TAG, "Unable to unregister",re);
1372 }
1373 }
1374 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001375
1376 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1377 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
1378 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
1379 mState = BluetoothAdapter.STATE_OFF;
1380 }
1381 if (mState == BluetoothAdapter.STATE_OFF) {
1382 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
1383 mState = BluetoothAdapter.STATE_TURNING_ON;
1384 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001385
1386 waitForOnOff(true, false);
1387
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001388 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
1389 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
1390 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001391
Benjamin Franze8b98922014-11-12 15:57:54 +00001392 unbindAllBluetoothProfileServices();
Zhihai Xu40874a02012-10-08 17:57:03 -07001393 // disable
Zhihai Xu401202b2012-12-03 11:36:21 -08001394 handleDisable();
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001395 // Pbap service need receive STATE_TURNING_OFF intent to close
1396 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1397 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001398
1399 waitForOnOff(false, true);
1400
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001401 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -07001402 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001403 sendBluetoothServiceDownCallback();
1404 synchronized (mConnection) {
1405 if (mBluetooth != null) {
1406 mBluetooth = null;
1407 //Unbind
1408 mContext.unbindService(mConnection);
1409 }
1410 }
1411 SystemClock.sleep(100);
1412
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001413 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1414 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -07001415 // enable
Zhihai Xu401202b2012-12-03 11:36:21 -08001416 handleEnable(mQuietEnable);
John Spurlock8a985d22014-02-25 09:40:05 -05001417 } else if (mBinding || mBluetooth != null) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001418 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1419 userMsg.arg2 = 1 + msg.arg2;
1420 // if user is switched when service is being binding
1421 // delay sending MESSAGE_USER_SWITCHED
1422 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1423 if (DBG) {
1424 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1425 }
John Spurlock8a985d22014-02-25 09:40:05 -05001426 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001427 break;
1428 }
fredc0f420372012-04-12 00:02:00 -07001429 }
1430 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001431 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001432
Zhihai Xu401202b2012-12-03 11:36:21 -08001433 private void handleEnable(boolean quietMode) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001434 mQuietEnable = quietMode;
1435
Matthew Xiecdce0b92012-07-12 19:06:15 -07001436 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001437 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001438 //Start bind timeout and bind
1439 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1440 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1441 mConnection.setGetNameAddressOnly(false);
1442 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001443 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1444 UserHandle.CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001445 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -07001446 } else {
1447 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001448 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001449 } else if (mBluetooth != null) {
1450 if (mConnection.isGetNameAddressOnly()) {
1451 // if GetNameAddressOnly is set, we can clear this flag,
1452 // so the service won't be unbind
1453 // after name and address are saved
1454 mConnection.setGetNameAddressOnly(false);
1455 //Register callback object
1456 try {
1457 mBluetooth.registerCallback(mBluetoothCallback);
1458 } catch (RemoteException re) {
1459 Log.e(TAG, "Unable to register BluetoothCallback",re);
1460 }
1461 //Inform BluetoothAdapter instances that service is up
1462 sendBluetoothServiceUpCallback();
1463 }
1464
Matthew Xiecdce0b92012-07-12 19:06:15 -07001465 //Enable bluetooth
1466 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001467 if (!mQuietEnable) {
1468 if(!mBluetooth.enable()) {
1469 Log.e(TAG,"IBluetooth.enable() returned false");
1470 }
1471 }
1472 else {
1473 if(!mBluetooth.enableNoAutoConnect()) {
1474 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1475 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001476 }
1477 } catch (RemoteException e) {
1478 Log.e(TAG,"Unable to call enable()",e);
1479 }
1480 }
1481 }
1482 }
1483
Dianne Hackborn221ea892013-08-04 16:50:16 -07001484 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1485 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1486 intent.setComponent(comp);
1487 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1488 Log.e(TAG, "Fail to bind to: " + intent);
1489 return false;
1490 }
1491 return true;
1492 }
1493
Zhihai Xu401202b2012-12-03 11:36:21 -08001494 private void handleDisable() {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001495 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001496 // don't need to disable if GetNameAddressOnly is set,
1497 // service will be unbinded after Name and Address are saved
1498 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001499 if (DBG) Log.d(TAG,"Sending off request.");
1500
1501 try {
1502 if(!mBluetooth.disable()) {
1503 Log.e(TAG,"IBluetooth.disable() returned false");
1504 }
1505 } catch (RemoteException e) {
1506 Log.e(TAG,"Unable to call disable()",e);
1507 }
1508 }
1509 }
1510 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001511
1512 private boolean checkIfCallerIsForegroundUser() {
1513 int foregroundUser;
1514 int callingUser = UserHandle.getCallingUserId();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001515 int callingUid = Binder.getCallingUid();
Zhihai Xu40874a02012-10-08 17:57:03 -07001516 long callingIdentity = Binder.clearCallingIdentity();
Benjamin Franze8b98922014-11-12 15:57:54 +00001517 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1518 UserInfo ui = um.getProfileParent(callingUser);
1519 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001520 int callingAppId = UserHandle.getAppId(callingUid);
Zhihai Xu40874a02012-10-08 17:57:03 -07001521 boolean valid = false;
1522 try {
1523 foregroundUser = ActivityManager.getCurrentUser();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001524 valid = (callingUser == foregroundUser) ||
Benjamin Franze8b98922014-11-12 15:57:54 +00001525 parentUser == foregroundUser ||
Adrian Roosbd9a9a52014-08-18 15:31:57 +02001526 callingAppId == Process.NFC_UID ||
1527 callingAppId == mSystemUiUid;
Zhihai Xu40874a02012-10-08 17:57:03 -07001528 if (DBG) {
1529 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1530 + " callingUser=" + callingUser
Benjamin Franze8b98922014-11-12 15:57:54 +00001531 + " parentUser=" + parentUser
Zhihai Xu40874a02012-10-08 17:57:03 -07001532 + " foregroundUser=" + foregroundUser);
1533 }
1534 } finally {
1535 Binder.restoreCallingIdentity(callingIdentity);
1536 }
1537 return valid;
1538 }
1539
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001540 private void sendBleStateChanged(int prevState, int newState) {
1541 if (DBG) Log.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
1542 // Send broadcast message to everyone else
1543 Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
1544 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1545 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1546 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1547 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1548 }
1549
Zhihai Xu40874a02012-10-08 17:57:03 -07001550 private void bluetoothStateChangeHandler(int prevState, int newState) {
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001551 boolean isStandardBroadcast = true;
Zhihai Xu40874a02012-10-08 17:57:03 -07001552 if (prevState != newState) {
1553 //Notify all proxy objects first of adapter state change
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001554 if (newState == BluetoothAdapter.STATE_BLE_ON
1555 || newState == BluetoothAdapter.STATE_OFF) {
1556 boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
1557 && newState == BluetoothAdapter.STATE_BLE_ON);
Zhihai Xu40874a02012-10-08 17:57:03 -07001558
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001559 if (newState == BluetoothAdapter.STATE_OFF) {
1560 // If Bluetooth is off, send service down event to proxy objects, and unbind
1561 if (DBG) Log.d(TAG, "Bluetooth is complete turn off");
1562 if (canUnbindBluetoothService()) {
1563 if (DBG) Log.d(TAG, "Good to unbind!");
Matthew Xieddf7e472013-03-01 18:41:02 -08001564 sendBluetoothServiceDownCallback();
1565 unbindAndFinish();
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001566 sendBleStateChanged(prevState, newState);
1567 // Don't broadcast as it has already been broadcast before
1568 isStandardBroadcast = false;
Matthew Xieddf7e472013-03-01 18:41:02 -08001569 }
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001570
1571 } else if (!intermediate_off) {
1572 // connect to GattService
1573 if (DBG) Log.d(TAG, "Bluetooth is in LE only mode");
1574 if (mBluetoothGatt != null) {
1575 if (DBG) Log.d(TAG, "Calling BluetoothGattServiceUp");
1576 onBluetoothGattServiceUp();
1577 } else {
1578 if (DBG) Log.d(TAG, "Binding Bluetooth GATT service");
1579 if (mContext.getPackageManager().hasSystemFeature(
1580 PackageManager.FEATURE_BLUETOOTH_LE)) {
1581 Intent i = new Intent(IBluetoothGatt.class.getName());
1582 doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
1583 }
1584 }
1585 sendBleStateChanged(prevState, newState);
1586 //Don't broadcase this as std intent
1587 isStandardBroadcast = false;
1588
1589 } else if (intermediate_off){
1590 if (DBG) Log.d(TAG, "Intermediate off, back to LE only mode");
1591 // For LE only mode, broadcast as is
1592 sendBleStateChanged(prevState, newState);
1593 sendBluetoothStateCallback(false); // BT is OFF for general users
1594 // Broadcast as STATE_OFF
1595 newState = BluetoothAdapter.STATE_OFF;
1596 sendBrEdrDownCallback();
Zhihai Xu40874a02012-10-08 17:57:03 -07001597 }
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001598 } else if (newState == BluetoothAdapter.STATE_ON) {
1599 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1600 sendBluetoothStateCallback(isUp);
1601 sendBleStateChanged(prevState, newState);
1602
1603 } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
1604 || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
1605 sendBleStateChanged(prevState, newState);
1606 isStandardBroadcast = false;
1607
1608 } else if (newState == BluetoothAdapter.STATE_TURNING_ON
1609 || newState == BluetoothAdapter.STATE_TURNING_OFF) {
1610 sendBleStateChanged(prevState, newState);
Zhihai Xu40874a02012-10-08 17:57:03 -07001611 }
1612
Nitin Arora6ddbb5e2015-03-02 15:03:51 -08001613 if (isStandardBroadcast) {
1614 if (prevState == BluetoothAdapter.STATE_BLE_ON) {
1615 // Show prevState of BLE_ON as OFF to standard users
1616 prevState = BluetoothAdapter.STATE_OFF;
1617 }
1618 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1619 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1620 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1621 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1622 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1623 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001624 }
1625 }
1626
1627 /**
1628 * if on is true, wait for state become ON
1629 * if off is true, wait for state become OFF
1630 * if both on and off are false, wait for state not ON
1631 */
1632 private boolean waitForOnOff(boolean on, boolean off) {
1633 int i = 0;
1634 while (i < 10) {
1635 synchronized(mConnection) {
1636 try {
1637 if (mBluetooth == null) break;
1638 if (on) {
1639 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1640 } else if (off) {
1641 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001642 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001643 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001644 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001645 } catch (RemoteException e) {
1646 Log.e(TAG, "getState()", e);
1647 break;
1648 }
1649 }
1650 if (on || off) {
1651 SystemClock.sleep(300);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001652 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001653 SystemClock.sleep(50);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001654 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001655 i++;
1656 }
1657 Log.e(TAG,"waitForOnOff time out");
1658 return false;
1659 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001660
Zhihai Xu401202b2012-12-03 11:36:21 -08001661 private void sendDisableMsg() {
1662 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1663 }
1664
1665 private void sendEnableMsg(boolean quietMode) {
1666 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1667 quietMode ? 1 : 0, 0));
1668 }
1669
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001670 private boolean canUnbindBluetoothService() {
1671 synchronized(mConnection) {
1672 //Only unbind with mEnable flag not set
1673 //For race condition: disable and enable back-to-back
1674 //Avoid unbind right after enable due to callback from disable
1675 //Only unbind with Bluetooth at OFF state
1676 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1677 try {
1678 if (mEnable || (mBluetooth == null)) return false;
1679 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1680 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1681 } catch (RemoteException e) {
1682 Log.e(TAG, "getState()", e);
1683 }
1684 }
1685 return false;
1686 }
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001687
1688 private void recoverBluetoothServiceFromError() {
1689 Log.e(TAG,"recoverBluetoothServiceFromError");
1690 synchronized (mConnection) {
1691 if (mBluetooth != null) {
1692 //Unregister callback object
1693 try {
1694 mBluetooth.unregisterCallback(mBluetoothCallback);
1695 } catch (RemoteException re) {
1696 Log.e(TAG, "Unable to unregister",re);
1697 }
1698 }
1699 }
1700
1701 SystemClock.sleep(500);
1702
1703 // disable
1704 handleDisable();
1705
1706 waitForOnOff(false, true);
1707
1708 sendBluetoothServiceDownCallback();
1709 synchronized (mConnection) {
1710 if (mBluetooth != null) {
1711 mBluetooth = null;
1712 //Unbind
1713 mContext.unbindService(mConnection);
1714 }
1715 }
1716
1717 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1718 mState = BluetoothAdapter.STATE_OFF;
1719
1720 mEnable = false;
1721
1722 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1723 // Send a Bluetooth Restart message to reenable bluetooth
1724 Message restartMsg = mHandler.obtainMessage(
1725 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1726 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1727 } else {
1728 // todo: notify user to power down and power up phone to make bluetooth work.
1729 }
1730 }
Mike Lockwood726d4de2014-10-28 14:06:28 -07001731
1732 @Override
1733 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Mike Lockwood75b52bb2014-12-18 14:16:36 -08001734 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
1735
Mike Lockwood726d4de2014-10-28 14:06:28 -07001736 writer.println("enabled: " + mEnable);
1737 writer.println("state: " + mState);
1738 writer.println("address: " + mAddress);
1739 writer.println("name: " + mName);
1740 if (mBluetooth == null) {
1741 writer.println("Bluetooth Service not connected");
1742 } else {
1743 try {
1744 writer.println(mBluetooth.dump());
1745 } catch (RemoteException re) {
1746 writer.println("RemoteException while calling Bluetooth Service");
1747 }
1748 }
1749 }
fredc0f420372012-04-12 00:02:00 -07001750}