blob: 1019faa6d9c947645d947c7abb1b8182030799ca [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;
Wei Wang67d84162015-04-26 17:04:29 -070051import android.provider.Settings.SettingNotFoundException;
fredc0f420372012-04-12 00:02:00 -070052import android.util.Log;
Mike Lockwood726d4de2014-10-28 14:06:28 -070053
54import java.io.FileDescriptor;
55import java.io.PrintWriter;
56
Benjamin Franze8b98922014-11-12 15:57:54 +000057import java.util.HashMap;
58import java.util.Map;
Benjamin Franze8b98922014-11-12 15:57:54 +000059
Nitin Arora6ddbb5e2015-03-02 15:03:51 -080060import java.util.*;
fredc0f420372012-04-12 00:02:00 -070061class BluetoothManagerService extends IBluetoothManager.Stub {
62 private static final String TAG = "BluetoothManagerService";
63 private static final boolean DBG = true;
64
fredc0f420372012-04-12 00:02:00 -070065 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
66 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070067 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
68 private static final String EXTRA_ACTION="action";
Zhihai Xud31c3222012-10-31 16:08:57 -070069 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
fredc0f420372012-04-12 00:02:00 -070070 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
71 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070072 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
73 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053074 //Maximum msec to wait for service restart
75 private static final int SERVICE_RESTART_TIME_MS = 200;
Zhihai Xudd9d17d2013-01-08 17:05:58 -080076 //Maximum msec to wait for restart due to error
77 private static final int ERROR_RESTART_TIME_MS = 3000;
Zhihai Xu40874a02012-10-08 17:57:03 -070078 //Maximum msec to delay MESSAGE_USER_SWITCHED
79 private static final int USER_SWITCHED_TIME_MS = 200;
Benjamin Franze8b98922014-11-12 15:57:54 +000080 // Delay for the addProxy function in msec
81 private static final int ADD_PROXY_DELAY_MS = 100;
fredc0f420372012-04-12 00:02:00 -070082
83 private static final int MESSAGE_ENABLE = 1;
84 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070085 private static final int MESSAGE_REGISTER_ADAPTER = 20;
86 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
87 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
88 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
89 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
90 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053091 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070092 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070093 private static final int MESSAGE_TIMEOUT_BIND =100;
94 private static final int MESSAGE_TIMEOUT_UNBIND =101;
95 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
96 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
Zhihai Xu40874a02012-10-08 17:57:03 -070097 private static final int MESSAGE_USER_SWITCHED = 300;
Benjamin Franze8b98922014-11-12 15:57:54 +000098 private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
99 private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
fredc0f420372012-04-12 00:02:00 -0700100 private static final int MAX_SAVE_RETRIES=3;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800101 private static final int MAX_ERROR_RESTART_RETRIES=6;
102
Zhihai Xu401202b2012-12-03 11:36:21 -0800103 // Bluetooth persisted setting is off
104 private static final int BLUETOOTH_OFF=0;
105 // Bluetooth persisted setting is on
106 // and Airplane mode won't affect Bluetooth state at start up
107 private static final int BLUETOOTH_ON_BLUETOOTH=1;
108 // Bluetooth persisted setting is on
109 // but Airplane mode will affect Bluetooth state at start up
110 // and Airplane mode will have higher priority.
111 private static final int BLUETOOTH_ON_AIRPLANE=2;
fredc0f420372012-04-12 00:02:00 -0700112
Matthew Xieddf7e472013-03-01 18:41:02 -0800113 private static final int SERVICE_IBLUETOOTH = 1;
114 private static final int SERVICE_IBLUETOOTHGATT = 2;
115
fredc0f420372012-04-12 00:02:00 -0700116 private final Context mContext;
Nitin Arorad055adb2015-03-02 15:03:51 -0800117 private static int mBleAppCount = 0;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700118
119 // Locks are not provided for mName and mAddress.
120 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -0700121 private String mAddress;
122 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -0700123 private final ContentResolver mContentResolver;
124 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
125 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -0700126 private IBluetooth mBluetooth;
Matthew Xieddf7e472013-03-01 18:41:02 -0800127 private IBluetoothGatt mBluetoothGatt;
fredc649fe492012-04-19 01:07:18 -0700128 private boolean mBinding;
129 private boolean mUnbinding;
Zhihai Xu401202b2012-12-03 11:36:21 -0800130 // used inside handler thread
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700131 private boolean mQuietEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800132 // configuarion from external IBinder call which is used to
133 // synchronize with broadcast receiver.
134 private boolean mQuietEnableExternal;
135 // configuarion from external IBinder call which is used to
136 // synchronize with broadcast receiver.
137 private boolean mEnableExternal;
138 // used inside handler thread
Zhihai Xu40874a02012-10-08 17:57:03 -0700139 private boolean mEnable;
140 private int mState;
Zhihai Xu40874a02012-10-08 17:57:03 -0700141 private final BluetoothHandler mHandler;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800142 private int mErrorRecoveryRetryCounter;
Adrian Roosbd9a9a52014-08-18 15:31:57 +0200143 private final int mSystemUiUid;
fredc0f420372012-04-12 00:02:00 -0700144
Benjamin Franze8b98922014-11-12 15:57:54 +0000145 // Save a ProfileServiceConnections object for each of the bound
146 // bluetooth profile services
147 private final Map <Integer, ProfileServiceConnections> mProfileServices =
148 new HashMap <Integer, ProfileServiceConnections>();
149
fredc649fe492012-04-19 01:07:18 -0700150 private void registerForAirplaneMode(IntentFilter filter) {
151 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700152 final String airplaneModeRadios = Settings.Global.getString(resolver,
153 Settings.Global.AIRPLANE_MODE_RADIOS);
154 final String toggleableRadios = Settings.Global.getString(resolver,
155 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700156 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700157 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700158 if (mIsAirplaneSensitive) {
159 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
160 }
161 }
162
fredcbf072a72012-05-09 16:52:50 -0700163 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
164 @Override
165 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
166 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
167 mHandler.sendMessage(msg);
168 }
169 };
170
171 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700172 @Override
173 public void onReceive(Context context, Intent intent) {
174 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700175 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700176 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700177 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700178 if (newName != null) {
179 storeNameAndAddress(newName, null);
180 }
fredc649fe492012-04-19 01:07:18 -0700181 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
Zhihai Xu401202b2012-12-03 11:36:21 -0800182 synchronized(mReceiver) {
183 if (isBluetoothPersistedStateOn()) {
184 if (isAirplaneModeOn()) {
185 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
186 } else {
187 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
188 }
189 }
Nitin Arorad055adb2015-03-02 15:03:51 -0800190
191 int st = BluetoothAdapter.STATE_OFF;
192 if (mBluetooth != null) {
193 try {
194 st = mBluetooth.getState();
195 } catch (RemoteException e) {
196 Log.e(TAG,"Unable to call getState", e);
197 }
198 }
199 Log.d(TAG, "state" + st);
200
Zhihai Xu401202b2012-12-03 11:36:21 -0800201 if (isAirplaneModeOn()) {
Nitin Arorad055adb2015-03-02 15:03:51 -0800202 // Clear registered LE apps to force shut-off
203 synchronized (this) {
204 mBleAppCount = 0;
205 }
206 if (st == BluetoothAdapter.STATE_BLE_ON) {
207 //if state is BLE_ON make sure you trigger disableBLE part
208 try {
209 if (mBluetooth != null) {
210 mBluetooth.onBrEdrDown();
211 mEnableExternal = false;
212 }
213 } catch(RemoteException e) {
214 Log.e(TAG,"Unable to call onBrEdrDown", e);
215 }
216 } else if (st == BluetoothAdapter.STATE_ON){
217 // disable without persisting the setting
218 Log.d(TAG, "Calling disable");
219 sendDisableMsg();
220 }
Zhihai Xu401202b2012-12-03 11:36:21 -0800221 } else if (mEnableExternal) {
222 // enable without persisting the setting
Nitin Arorad055adb2015-03-02 15:03:51 -0800223 Log.d(TAG, "Calling enable");
Zhihai Xu401202b2012-12-03 11:36:21 -0800224 sendEnableMsg(mQuietEnableExternal);
225 }
fredc649fe492012-04-19 01:07:18 -0700226 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700227 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
228 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
229 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Zhihai Xu401202b2012-12-03 11:36:21 -0800230 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
231 synchronized(mReceiver) {
232 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
233 //Enable
234 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
235 sendEnableMsg(mQuietEnableExternal);
236 }
237 }
fredc0f420372012-04-12 00:02:00 -0700238 }
239 }
240 };
241
242 BluetoothManagerService(Context context) {
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700243 mHandler = new BluetoothHandler(IoThread.get().getLooper());
Zhihai Xu40874a02012-10-08 17:57:03 -0700244
fredc0f420372012-04-12 00:02:00 -0700245 mContext = context;
246 mBluetooth = null;
Nitin Arorad055adb2015-03-02 15:03:51 -0800247 mBluetoothGatt = null;
fredc0f420372012-04-12 00:02:00 -0700248 mBinding = false;
249 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700250 mEnable = false;
251 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu401202b2012-12-03 11:36:21 -0800252 mQuietEnableExternal = false;
253 mEnableExternal = false;
fredc0f420372012-04-12 00:02:00 -0700254 mAddress = null;
255 mName = null;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800256 mErrorRecoveryRetryCounter = 0;
fredc0f420372012-04-12 00:02:00 -0700257 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700258 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
259 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Zhihai Xu401202b2012-12-03 11:36:21 -0800260 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700261 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700262 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700263 registerForAirplaneMode(filter);
Dianne Hackbornd83a0962014-05-02 16:28:33 -0700264 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Matthew Xie6fde3092012-07-11 17:10:07 -0700265 mContext.registerReceiver(mReceiver, filter);
fredc0f420372012-04-12 00:02:00 -0700266 loadStoredNameAndAddress();
Zhihai Xu401202b2012-12-03 11:36:21 -0800267 if (isBluetoothPersistedStateOn()) {
268 mEnableExternal = true;
fredc0f420372012-04-12 00:02:00 -0700269 }
Adrian Roosbd9a9a52014-08-18 15:31:57 +0200270
271 int sysUiUid = -1;
272 try {
273 sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui",
274 UserHandle.USER_OWNER);
275 } catch (PackageManager.NameNotFoundException e) {
276 Log.wtf(TAG, "Unable to resolve SystemUI's UID.", e);
277 }
278 mSystemUiUid = sysUiUid;
fredc0f420372012-04-12 00:02:00 -0700279 }
280
fredc649fe492012-04-19 01:07:18 -0700281 /**
282 * Returns true if airplane mode is currently on
283 */
284 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700285 return Settings.Global.getInt(mContext.getContentResolver(),
286 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700287 }
288
289 /**
290 * Returns true if the Bluetooth saved state is "on"
291 */
292 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700293 return Settings.Global.getInt(mContentResolver,
Zhihai Xu401202b2012-12-03 11:36:21 -0800294 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
295 }
296
297 /**
298 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
299 */
300 private final boolean isBluetoothPersistedStateOnBluetooth() {
301 return Settings.Global.getInt(mContentResolver,
302 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
fredc649fe492012-04-19 01:07:18 -0700303 }
304
305 /**
306 * Save the Bluetooth on/off state
307 *
308 */
Zhihai Xu401202b2012-12-03 11:36:21 -0800309 private void persistBluetoothSetting(int value) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700310 Settings.Global.putInt(mContext.getContentResolver(),
311 Settings.Global.BLUETOOTH_ON,
Zhihai Xu401202b2012-12-03 11:36:21 -0800312 value);
fredc649fe492012-04-19 01:07:18 -0700313 }
314
315 /**
316 * Returns true if the Bluetooth Adapter's name and address is
317 * locally cached
318 * @return
319 */
fredc0f420372012-04-12 00:02:00 -0700320 private boolean isNameAndAddressSet() {
321 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
322 }
323
fredc649fe492012-04-19 01:07:18 -0700324 /**
325 * Retrieve the Bluetooth Adapter's name and address and save it in
326 * in the local cache
327 */
fredc0f420372012-04-12 00:02:00 -0700328 private void loadStoredNameAndAddress() {
329 if (DBG) Log.d(TAG, "Loading stored name and address");
Zhihai Xud31c3222012-10-31 16:08:57 -0700330 if (mContext.getResources().getBoolean
331 (com.android.internal.R.bool.config_bluetooth_address_validation) &&
332 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
333 // if the valid flag is not set, don't load the address and name
334 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
335 return;
336 }
fredc0f420372012-04-12 00:02:00 -0700337 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
338 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
Zhihai Xud31c3222012-10-31 16:08:57 -0700339 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
fredc0f420372012-04-12 00:02:00 -0700340 }
341
fredc649fe492012-04-19 01:07:18 -0700342 /**
343 * Save the Bluetooth name and address in the persistent store.
344 * Only non-null values will be saved.
345 * @param name
346 * @param address
347 */
fredc0f420372012-04-12 00:02:00 -0700348 private void storeNameAndAddress(String name, String address) {
349 if (name != null) {
350 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700351 mName = name;
fredc649fe492012-04-19 01:07:18 -0700352 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
353 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700354 }
355
356 if (address != null) {
357 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700358 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700359 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
360 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700361 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700362
363 if ((name != null) && (address != null)) {
364 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
365 }
fredc0f420372012-04-12 00:02:00 -0700366 }
367
368 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
Natalie Silvanovich55db6462014-05-01 16:12:23 -0700369 if (callback == null) {
370 Log.w(TAG, "Callback is null in registerAdapter");
371 return null;
372 }
fredc0f420372012-04-12 00:02:00 -0700373 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
374 msg.obj = callback;
375 mHandler.sendMessage(msg);
376 synchronized(mConnection) {
377 return mBluetooth;
378 }
379 }
380
381 public void unregisterAdapter(IBluetoothManagerCallback callback) {
Natalie Silvanovich55db6462014-05-01 16:12:23 -0700382 if (callback == null) {
383 Log.w(TAG, "Callback is null in unregisterAdapter");
384 return;
385 }
fredc0f420372012-04-12 00:02:00 -0700386 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
387 "Need BLUETOOTH permission");
388 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
389 msg.obj = callback;
390 mHandler.sendMessage(msg);
391 }
392
393 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
394 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
395 "Need BLUETOOTH permission");
396 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
397 msg.obj = callback;
398 mHandler.sendMessage(msg);
399 }
400
401 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
402 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
403 "Need BLUETOOTH permission");
404 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
405 msg.obj = callback;
406 mHandler.sendMessage(msg);
407 }
408
409 public boolean isEnabled() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800410 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
411 (!checkIfCallerIsForegroundUser())) {
412 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700413 return false;
414 }
415
fredc0f420372012-04-12 00:02:00 -0700416 synchronized(mConnection) {
417 try {
418 return (mBluetooth != null && mBluetooth.isEnabled());
419 } catch (RemoteException e) {
420 Log.e(TAG, "isEnabled()", e);
421 }
422 }
423 return false;
424 }
425
Nitin Arorad055adb2015-03-02 15:03:51 -0800426 class ClientDeathRecipient implements IBinder.DeathRecipient {
427 public void binderDied() {
428 if (DBG) Log.d(TAG, "Binder is dead - unregister Ble App");
429 if (mBleAppCount > 0) --mBleAppCount;
430
431 if (mBleAppCount == 0) {
432 if (DBG) Log.d(TAG, "Disabling LE only mode after application crash");
433 try {
434 if (mBluetooth != null) {
435 mBluetooth.onBrEdrDown();
436 }
437 } catch(RemoteException e) {
438 Log.e(TAG,"Unable to call onBrEdrDown", e);
439 }
440 }
441 }
442 }
443
444 /** Internal death rec list */
445 Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>();
446
Wei Wang67d84162015-04-26 17:04:29 -0700447 @Override
448 public boolean isBleScanAlwaysAvailable() {
449 try {
450 return (Settings.Global.getInt(mContentResolver,
451 Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0;
452 } catch (SettingNotFoundException e) {
453 }
454 return false;
455 }
456
Nitin Arorad055adb2015-03-02 15:03:51 -0800457 public int updateBleAppCount(IBinder token, boolean enable) {
458 if (enable) {
459 ClientDeathRecipient r = mBleApps.get(token);
460 if (r == null) {
461 ClientDeathRecipient deathRec = new ClientDeathRecipient();
462 try {
463 token.linkToDeath(deathRec, 0);
464 } catch (RemoteException ex) {
465 throw new IllegalArgumentException("Wake lock is already dead.");
466 }
467 mBleApps.put(token, deathRec);
468 synchronized (this) {
469 ++mBleAppCount;
470 }
471 if (DBG) Log.d(TAG, "Registered for death Notification");
472 }
473
474 } else {
475 ClientDeathRecipient r = mBleApps.get(token);
476 if (r != null) {
477 try {
478 token.linkToDeath(r, 0);
479 } catch (RemoteException ex) {
480 throw new IllegalArgumentException("Wake lock is already dead.");
481 }
482 mBleApps.remove(token);
483 synchronized (this) {
484 if (mBleAppCount > 0) --mBleAppCount;
485 }
486 if (DBG) Log.d(TAG, "Unregistered for death Notification");
487 }
488 }
489 if (DBG) Log.d(TAG, "Updated BleAppCount" + mBleAppCount);
490 if (mBleAppCount == 0 && mEnable) {
491 try {
492 if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
493 if (DBG) Log.d(TAG, "Reseting the mEnable flag for clean disable");
494 mEnable = false;
495 }
496 } catch (RemoteException e) {
497 Log.e(TAG, "getState()", e);
498 }
499 }
500 return mBleAppCount;
501 }
502
503 /** @hide*/
504 public boolean isBleAppPresent() {
505 if (DBG) Log.d(TAG, "isBleAppPresent() count: " + mBleAppCount);
506 return (mBleAppCount > 0);
507 }
508
509 /**
510 * Action taken when GattService is turned off
511 */
512 private void onBluetoothGattServiceUp() {
513 if (DBG) Log.d(TAG,"BluetoothGatt Service is Up");
514 try{
515 if (isBleAppPresent() == false && mBluetooth.getState() == BluetoothAdapter.STATE_BLE_ON) {
516 mBluetooth.onLeServiceUp();
517
518 // waive WRITE_SECURE_SETTINGS permission check
519 long callingIdentity = Binder.clearCallingIdentity();
520 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
521 Binder.restoreCallingIdentity(callingIdentity);
522 }
523 } catch(RemoteException e) {
524 Log.e(TAG,"Unable to call onServiceUp", e);
525 }
526 }
527
528 /**
529 * Inform BluetoothAdapter instances that BREDR part is down
530 * and turn off all service and stack if no LE app needs it
531 */
532 private void sendBrEdrDownCallback() {
533 if (DBG) Log.d(TAG,"Calling sendBrEdrDownCallback callbacks");
534 int n = mCallbacks.beginBroadcast();
535
536 if (isBleAppPresent() == false) {
537 try {
538 mBluetooth.onBrEdrDown();
539 } catch(RemoteException e) {
540 Log.e(TAG,"Unable to call onBrEdrDown", e);
541 }
542 }
543 else{//need to stay at BLE ON. disconnect all Gatt connections
544 try{
545 mBluetoothGatt.unregAll();//disconnectAll();
546 } catch(RemoteException e) {
547 Log.e(TAG,"Unable to disconn all", e);
548 }
549 }
550
551 Log.d(TAG,"Broadcasting onBrEdrDown() to " + n + " receivers.");
552 for (int i=0; i <n; i++) {
553 try {
554 mCallbacks.getBroadcastItem(i).onBrEdrDown();
555 } catch (RemoteException e) {
556 Log.e(TAG, "Unable to call sendBrEdrDownCallback() on callback #" + i, e);
557 }
558 }
559 mCallbacks.finishBroadcast();
560 }
561
562 /** @hide*/
fredc0f420372012-04-12 00:02:00 -0700563 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700564 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700565 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
566 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700567 }
fredc0f420372012-04-12 00:02:00 -0700568 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
569 mHandler.sendMessage(msg);
570 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700571 public boolean enableNoAutoConnect()
572 {
573 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
574 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700575
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700576 if (DBG) {
577 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
578 " mBinding = " + mBinding);
579 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800580 int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
581
582 if (callingAppId != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700583 throw new SecurityException("no permission to enable Bluetooth quietly");
584 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800585
Zhihai Xu401202b2012-12-03 11:36:21 -0800586 synchronized(mReceiver) {
587 mQuietEnableExternal = true;
588 mEnableExternal = true;
589 sendEnableMsg(true);
590 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700591 return true;
592
593 }
fredc0f420372012-04-12 00:02:00 -0700594 public boolean enable() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800595 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
596 (!checkIfCallerIsForegroundUser())) {
597 Log.w(TAG,"enable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700598 return false;
fredcf2458862012-04-16 15:18:27 -0700599 }
600
Zhihai Xu401202b2012-12-03 11:36:21 -0800601 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
602 "Need BLUETOOTH ADMIN permission");
603 if (DBG) {
604 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
605 " mBinding = " + mBinding);
606 }
607
608 synchronized(mReceiver) {
609 mQuietEnableExternal = false;
610 mEnableExternal = true;
611 // waive WRITE_SECURE_SETTINGS permission check
Zhihai Xu401202b2012-12-03 11:36:21 -0800612 sendEnableMsg(false);
613 }
Nitin Arorad055adb2015-03-02 15:03:51 -0800614 if (DBG) Log.d(TAG, "enable returning");
Zhihai Xu401202b2012-12-03 11:36:21 -0800615 return true;
fredc0f420372012-04-12 00:02:00 -0700616 }
617
618 public boolean disable(boolean persist) {
619 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
620 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700621
Zhihai Xu6eb76522012-11-29 15:41:04 -0800622 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
623 (!checkIfCallerIsForegroundUser())) {
624 Log.w(TAG,"disable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700625 return false;
626 }
627
fredcf2458862012-04-16 15:18:27 -0700628 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700629 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
630 " mBinding = " + mBinding);
631 }
fredcf2458862012-04-16 15:18:27 -0700632
Zhihai Xu401202b2012-12-03 11:36:21 -0800633 synchronized(mReceiver) {
634 if (persist) {
635 // waive WRITE_SECURE_SETTINGS permission check
636 long callingIdentity = Binder.clearCallingIdentity();
637 persistBluetoothSetting(BLUETOOTH_OFF);
638 Binder.restoreCallingIdentity(callingIdentity);
639 }
640 mEnableExternal = false;
641 sendDisableMsg();
642 }
fredc0f420372012-04-12 00:02:00 -0700643 return true;
644 }
645
fredc649fe492012-04-19 01:07:18 -0700646 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700647 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700648 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
649 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700650 }
651
fredc0f420372012-04-12 00:02:00 -0700652 synchronized (mConnection) {
653 if (mUnbinding) return;
654 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700655 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700656 if (!mConnection.isGetNameAddressOnly()) {
657 //Unregister callback object
658 try {
659 mBluetooth.unregisterCallback(mBluetoothCallback);
660 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700661 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700662 }
663 }
fredc0f420372012-04-12 00:02:00 -0700664 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700665 mBluetooth = null;
666 //Unbind
fredc0f420372012-04-12 00:02:00 -0700667 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700668 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700669 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700670 } else {
671 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700672 }
Nitin Arorad055adb2015-03-02 15:03:51 -0800673 mBluetoothGatt = null;
fredc0f420372012-04-12 00:02:00 -0700674 }
675 }
676
Matthew Xieddf7e472013-03-01 18:41:02 -0800677 public IBluetoothGatt getBluetoothGatt() {
678 // sync protection
679 return mBluetoothGatt;
680 }
681
Benjamin Franze8b98922014-11-12 15:57:54 +0000682 @Override
683 public boolean bindBluetoothProfileService(int bluetoothProfile,
684 IBluetoothProfileServiceConnection proxy) {
685 if (!mEnable) {
686 if (DBG) {
687 Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
688 ", while Bluetooth was disabled");
689 }
690 return false;
691 }
692 synchronized (mProfileServices) {
693 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
694 if (psc == null) {
695 if (DBG) {
696 Log.d(TAG, "Creating new ProfileServiceConnections object for"
697 + " profile: " + bluetoothProfile);
698 }
Benjamin Franz5b614592014-12-09 18:58:45 +0000699
700 if (bluetoothProfile != BluetoothProfile.HEADSET) return false;
701
702 Intent intent = new Intent(IBluetoothHeadset.class.getName());
Benjamin Franze8b98922014-11-12 15:57:54 +0000703 psc = new ProfileServiceConnections(intent);
Benjamin Franz5b614592014-12-09 18:58:45 +0000704 if (!psc.bindService()) return false;
705
Benjamin Franze8b98922014-11-12 15:57:54 +0000706 mProfileServices.put(new Integer(bluetoothProfile), psc);
Benjamin Franze8b98922014-11-12 15:57:54 +0000707 }
708 }
709
710 // Introducing a delay to give the client app time to prepare
711 Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
712 addProxyMsg.arg1 = bluetoothProfile;
713 addProxyMsg.obj = proxy;
714 mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
715 return true;
716 }
717
718 @Override
719 public void unbindBluetoothProfileService(int bluetoothProfile,
720 IBluetoothProfileServiceConnection proxy) {
721 synchronized (mProfileServices) {
722 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
723 if (psc == null) {
724 return;
725 }
726 psc.removeProxy(proxy);
727 }
728 }
729
730 private void unbindAllBluetoothProfileServices() {
731 synchronized (mProfileServices) {
732 for (Integer i : mProfileServices.keySet()) {
733 ProfileServiceConnections psc = mProfileServices.get(i);
Benjamin Franz5b614592014-12-09 18:58:45 +0000734 try {
735 mContext.unbindService(psc);
736 } catch (IllegalArgumentException e) {
737 Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
738 }
Benjamin Franze8b98922014-11-12 15:57:54 +0000739 psc.removeAllProxies();
740 }
741 mProfileServices.clear();
742 }
743 }
744
745 /**
746 * This class manages the clients connected to a given ProfileService
747 * and maintains the connection with that service.
748 */
749 final private class ProfileServiceConnections implements ServiceConnection,
750 IBinder.DeathRecipient {
751 final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
752 new RemoteCallbackList <IBluetoothProfileServiceConnection>();
753 IBinder mService;
754 ComponentName mClassName;
755 Intent mIntent;
756
757 ProfileServiceConnections(Intent intent) {
758 mService = null;
759 mClassName = null;
760 mIntent = intent;
761 }
762
Benjamin Franz5b614592014-12-09 18:58:45 +0000763 private boolean bindService() {
764 if (mIntent != null && mService == null &&
765 doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
Benjamin Franze8b98922014-11-12 15:57:54 +0000766 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
767 msg.obj = this;
768 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
Benjamin Franz5b614592014-12-09 18:58:45 +0000769 return true;
Benjamin Franze8b98922014-11-12 15:57:54 +0000770 }
Benjamin Franz5b614592014-12-09 18:58:45 +0000771 Log.w(TAG, "Unable to bind with intent: " + mIntent);
772 return false;
Benjamin Franze8b98922014-11-12 15:57:54 +0000773 }
774
775 private void addProxy(IBluetoothProfileServiceConnection proxy) {
776 mProxies.register(proxy);
777 if (mService != null) {
778 try{
779 proxy.onServiceConnected(mClassName, mService);
780 } catch (RemoteException e) {
781 Log.e(TAG, "Unable to connect to proxy", e);
782 }
783 } else {
784 if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
785 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
786 msg.obj = this;
787 mHandler.sendMessage(msg);
788 }
789 }
790 }
791
792 private void removeProxy(IBluetoothProfileServiceConnection proxy) {
793 if (proxy != null) {
794 if (mProxies.unregister(proxy)) {
795 try {
796 proxy.onServiceDisconnected(mClassName);
797 } catch (RemoteException e) {
798 Log.e(TAG, "Unable to disconnect proxy", e);
799 }
800 }
801 } else {
802 Log.w(TAG, "Trying to remove a null proxy");
803 }
804 }
805
806 private void removeAllProxies() {
807 onServiceDisconnected(mClassName);
808 mProxies.kill();
809 }
810
811 @Override
812 public void onServiceConnected(ComponentName className, IBinder service) {
813 // remove timeout message
814 mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
815 mService = service;
816 mClassName = className;
817 try {
818 mService.linkToDeath(this, 0);
819 } catch (RemoteException e) {
820 Log.e(TAG, "Unable to linkToDeath", e);
821 }
822 int n = mProxies.beginBroadcast();
823 for (int i = 0; i < n; i++) {
824 try {
825 mProxies.getBroadcastItem(i).onServiceConnected(className, service);
826 } catch (RemoteException e) {
827 Log.e(TAG, "Unable to connect to proxy", e);
828 }
829 }
830 mProxies.finishBroadcast();
831 }
832
833 @Override
834 public void onServiceDisconnected(ComponentName className) {
835 if (mService == null) {
836 return;
837 }
838 mService.unlinkToDeath(this, 0);
839 mService = null;
840 mClassName = null;
841 int n = mProxies.beginBroadcast();
842 for (int i = 0; i < n; i++) {
843 try {
844 mProxies.getBroadcastItem(i).onServiceDisconnected(className);
845 } catch (RemoteException e) {
846 Log.e(TAG, "Unable to disconnect from proxy", e);
847 }
848 }
849 mProxies.finishBroadcast();
850 }
851
852 @Override
853 public void binderDied() {
854 if (DBG) {
855 Log.w(TAG, "Profile service for profile: " + mClassName
856 + " died.");
857 }
858 onServiceDisconnected(mClassName);
859 // Trigger rebind
860 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
861 msg.obj = this;
862 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
863 }
864 }
865
fredcbf072a72012-05-09 16:52:50 -0700866 private void sendBluetoothStateCallback(boolean isUp) {
867 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700868 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700869 for (int i=0; i <n;i++) {
870 try {
871 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
872 } catch (RemoteException e) {
873 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
874 }
875 }
876 mStateChangeCallbacks.finishBroadcast();
877 }
878
879 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700880 * Inform BluetoothAdapter instances that Adapter service is up
881 */
882 private void sendBluetoothServiceUpCallback() {
883 if (!mConnection.isGetNameAddressOnly()) {
884 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
885 int n = mCallbacks.beginBroadcast();
886 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
887 for (int i=0; i <n;i++) {
888 try {
889 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
890 } catch (RemoteException e) {
891 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
892 }
893 }
894 mCallbacks.finishBroadcast();
895 }
896 }
897 /**
fredcbf072a72012-05-09 16:52:50 -0700898 * Inform BluetoothAdapter instances that Adapter service is down
899 */
900 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700901 if (!mConnection.isGetNameAddressOnly()) {
902 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
903 int n = mCallbacks.beginBroadcast();
904 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
905 for (int i=0; i <n;i++) {
906 try {
907 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
908 } catch (RemoteException e) {
909 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
910 }
911 }
912 mCallbacks.finishBroadcast();
913 }
914 }
fredc0f420372012-04-12 00:02:00 -0700915 public String getAddress() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800916 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
917 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700918
Zhihai Xu6eb76522012-11-29 15:41:04 -0800919 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
920 (!checkIfCallerIsForegroundUser())) {
921 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
922 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700923 }
924
fredc116d1d462012-04-20 14:47:08 -0700925 synchronized(mConnection) {
926 if (mBluetooth != null) {
927 try {
928 return mBluetooth.getAddress();
929 } catch (RemoteException e) {
930 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
931 }
932 }
933 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700934 // mAddress is accessed from outside.
935 // It is alright without a lock. Here, bluetooth is off, no other thread is
936 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700937 return mAddress;
938 }
fredc649fe492012-04-19 01:07:18 -0700939
fredc0f420372012-04-12 00:02:00 -0700940 public String getName() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800941 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
942 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700943
Zhihai Xu6eb76522012-11-29 15:41:04 -0800944 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
945 (!checkIfCallerIsForegroundUser())) {
946 Log.w(TAG,"getName(): not allowed for non-active and non system user");
947 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700948 }
949
fredc116d1d462012-04-20 14:47:08 -0700950 synchronized(mConnection) {
951 if (mBluetooth != null) {
952 try {
953 return mBluetooth.getName();
954 } catch (RemoteException e) {
955 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
956 }
957 }
958 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700959 // mName is accessed from outside.
960 // It alright without a lock. Here, bluetooth is off, no other thread is
961 // changing mName
fredc0f420372012-04-12 00:02:00 -0700962 return mName;
963 }
964
fredc0f420372012-04-12 00:02:00 -0700965 private class BluetoothServiceConnection implements ServiceConnection {
966
967 private boolean mGetNameAddressOnly;
968
969 public void setGetNameAddressOnly(boolean getOnly) {
970 mGetNameAddressOnly = getOnly;
971 }
972
973 public boolean isGetNameAddressOnly() {
974 return mGetNameAddressOnly;
975 }
976
977 public void onServiceConnected(ComponentName className, IBinder service) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800978 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700979 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800980 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
981 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
982 msg.arg1 = SERVICE_IBLUETOOTH;
983 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
984 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
985 msg.arg1 = SERVICE_IBLUETOOTHGATT;
986 } else {
987 Log.e(TAG, "Unknown service connected: " + className.getClassName());
988 return;
989 }
fredc0f420372012-04-12 00:02:00 -0700990 msg.obj = service;
991 mHandler.sendMessage(msg);
992 }
993
994 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700995 // Called if we unexpected disconnected.
Matthew Xieddf7e472013-03-01 18:41:02 -0800996 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
997 className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700998 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800999 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
1000 msg.arg1 = SERVICE_IBLUETOOTH;
1001 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
1002 msg.arg1 = SERVICE_IBLUETOOTHGATT;
1003 } else {
1004 Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
1005 return;
1006 }
fredc0f420372012-04-12 00:02:00 -07001007 mHandler.sendMessage(msg);
1008 }
1009 }
1010
1011 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
1012
Zhihai Xu40874a02012-10-08 17:57:03 -07001013 private class BluetoothHandler extends Handler {
1014 public BluetoothHandler(Looper looper) {
1015 super(looper);
1016 }
1017
fredc0f420372012-04-12 00:02:00 -07001018 @Override
1019 public void handleMessage(Message msg) {
1020 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -07001021 switch (msg.what) {
1022 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -07001023 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -07001024 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -07001025 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -07001026 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -07001027 if (DBG) Log.d(TAG, "Binding to service to get name and address");
1028 mConnection.setGetNameAddressOnly(true);
1029 //Start bind timeout and bind
1030 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1031 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1032 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackborn221ea892013-08-04 16:50:16 -07001033 if (!doBind(i, mConnection,
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001034 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1035 UserHandle.CURRENT)) {
fredc0f420372012-04-12 00:02:00 -07001036 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -07001037 } else {
1038 mBinding = true;
fredc0f420372012-04-12 00:02:00 -07001039 }
1040 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001041 else {
1042 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -07001043 saveMsg.arg1 = 0;
1044 if (mBluetooth != null) {
1045 mHandler.sendMessage(saveMsg);
1046 } else {
1047 // if enable is also called to bind the service
1048 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
1049 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
1050 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001051 }
fredc0f420372012-04-12 00:02:00 -07001052 }
fredc649fe492012-04-19 01:07:18 -07001053 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001054 }
fredc0f420372012-04-12 00:02:00 -07001055 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -07001056 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -07001057 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -07001058 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -07001059 if (!mEnable && mBluetooth != null) {
1060 try {
1061 mBluetooth.enable();
1062 } catch (RemoteException e) {
1063 Log.e(TAG,"Unable to call enable()",e);
1064 }
1065 }
1066 }
1067 if (mBluetooth != null) waitForOnOff(true, false);
1068 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001069 if (mBluetooth != null) {
1070 String name = null;
1071 String address = null;
1072 try {
1073 name = mBluetooth.getName();
1074 address = mBluetooth.getAddress();
1075 } catch (RemoteException re) {
1076 Log.e(TAG,"",re);
1077 }
fredc0f420372012-04-12 00:02:00 -07001078
Matthew Xiecdce0b92012-07-12 19:06:15 -07001079 if (name != null && address != null) {
1080 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -07001081 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -07001082 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -07001083 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001084 } else {
1085 if (msg.arg1 < MAX_SAVE_RETRIES) {
1086 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
1087 retryMsg.arg1= 1+msg.arg1;
1088 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
1089 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
1090 } else {
1091 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -07001092 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -07001093 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -07001094 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001095 }
fredc0f420372012-04-12 00:02:00 -07001096 }
Zhihai Xud31c3222012-10-31 16:08:57 -07001097 if (!mEnable) {
1098 try {
1099 mBluetooth.disable();
1100 } catch (RemoteException e) {
1101 Log.e(TAG,"Unable to call disable()",e);
1102 }
1103 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001104 } else {
1105 // rebind service by Request GET NAME AND ADDRESS
1106 // if service is unbinded by disable or
1107 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
1108 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1109 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -07001110 }
1111 }
Zhihai Xud31c3222012-10-31 16:08:57 -07001112 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
1113 if (unbind) {
1114 unbindAndFinish();
1115 }
fredc649fe492012-04-19 01:07:18 -07001116 break;
fredc649fe492012-04-19 01:07:18 -07001117 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001118 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -07001119 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001120 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -07001121 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001122 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1123 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -08001124 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -07001125 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001126
fredc0f420372012-04-12 00:02:00 -07001127 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -07001128 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
1129 if (mEnable && mBluetooth != null) {
1130 waitForOnOff(true, false);
1131 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -08001132 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001133 waitForOnOff(false, false);
1134 } else {
1135 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -08001136 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001137 }
fredc0f420372012-04-12 00:02:00 -07001138 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001139
fredc0f420372012-04-12 00:02:00 -07001140 case MESSAGE_REGISTER_ADAPTER:
1141 {
1142 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -07001143 boolean added = mCallbacks.register(callback);
1144 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -07001145 }
1146 break;
1147 case MESSAGE_UNREGISTER_ADAPTER:
1148 {
1149 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -07001150 boolean removed = mCallbacks.unregister(callback);
1151 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -07001152 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001153 }
fredc0f420372012-04-12 00:02:00 -07001154 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
1155 {
1156 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -07001157 if (callback != null) {
1158 mStateChangeCallbacks.register(callback);
1159 }
fredc0f420372012-04-12 00:02:00 -07001160 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001161 }
fredc0f420372012-04-12 00:02:00 -07001162 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
1163 {
1164 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -07001165 if (callback != null) {
1166 mStateChangeCallbacks.unregister(callback);
1167 }
fredc0f420372012-04-12 00:02:00 -07001168 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001169 }
Benjamin Franze8b98922014-11-12 15:57:54 +00001170 case MESSAGE_ADD_PROXY_DELAYED:
1171 {
1172 ProfileServiceConnections psc = mProfileServices.get(
1173 new Integer(msg.arg1));
1174 if (psc == null) {
1175 break;
1176 }
1177 IBluetoothProfileServiceConnection proxy =
1178 (IBluetoothProfileServiceConnection) msg.obj;
1179 psc.addProxy(proxy);
1180 break;
1181 }
1182 case MESSAGE_BIND_PROFILE_SERVICE:
1183 {
1184 ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
1185 removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
1186 if (psc == null) {
1187 break;
1188 }
1189 psc.bindService();
1190 break;
1191 }
fredc0f420372012-04-12 00:02:00 -07001192 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
1193 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001194 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
fredc0f420372012-04-12 00:02:00 -07001195
1196 IBinder service = (IBinder) msg.obj;
1197 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001198 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1199 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
Nitin Arorad055adb2015-03-02 15:03:51 -08001200 onBluetoothGattServiceUp();
Matthew Xieddf7e472013-03-01 18:41:02 -08001201 break;
1202 } // else must be SERVICE_IBLUETOOTH
1203
1204 //Remove timeout
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001205 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Matthew Xieddf7e472013-03-01 18:41:02 -08001206
fredc0f420372012-04-12 00:02:00 -07001207 mBinding = false;
1208 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -07001209
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001210 try {
1211 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
1212 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
1213 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
1214 Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
1215 }
1216 } catch (RemoteException e) {
1217 Log.e(TAG,"Unable to call configHciSnoopLog", e);
1218 }
1219
Matthew Xiecdce0b92012-07-12 19:06:15 -07001220 if (mConnection.isGetNameAddressOnly()) {
1221 //Request GET NAME AND ADDRESS
1222 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1223 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -07001224 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001225 }
fredc0f420372012-04-12 00:02:00 -07001226
Zhihai Xu40874a02012-10-08 17:57:03 -07001227 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -07001228 //Register callback object
fredcbf072a72012-05-09 16:52:50 -07001229 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001230 mBluetooth.registerCallback(mBluetoothCallback);
1231 } catch (RemoteException re) {
1232 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -07001233 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001234 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -07001235 sendBluetoothServiceUpCallback();
1236
Matthew Xiecdce0b92012-07-12 19:06:15 -07001237 //Do enable request
1238 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001239 if (mQuietEnable == false) {
1240 if(!mBluetooth.enable()) {
1241 Log.e(TAG,"IBluetooth.enable() returned false");
1242 }
1243 }
1244 else
1245 {
1246 if(!mBluetooth.enableNoAutoConnect()) {
1247 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1248 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001249 }
1250 } catch (RemoteException e) {
1251 Log.e(TAG,"Unable to call enable()",e);
1252 }
Freda8c6df02012-07-11 10:25:23 -07001253 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001254
1255 if (!mEnable) {
1256 waitForOnOff(true, false);
Zhihai Xu401202b2012-12-03 11:36:21 -08001257 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001258 waitForOnOff(false, false);
1259 }
fredc649fe492012-04-19 01:07:18 -07001260 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001261 }
fredc649fe492012-04-19 01:07:18 -07001262 case MESSAGE_TIMEOUT_BIND: {
1263 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -07001264 synchronized(mConnection) {
1265 mBinding = false;
1266 }
fredc649fe492012-04-19 01:07:18 -07001267 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001268 }
fredcbf072a72012-05-09 16:52:50 -07001269 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -07001270 {
fredcbf072a72012-05-09 16:52:50 -07001271 int prevState = msg.arg1;
1272 int newState = msg.arg2;
1273 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -07001274 mState = newState;
1275 bluetoothStateChangeHandler(prevState, newState);
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001276 // handle error state transition case from TURNING_ON to OFF
1277 // unbind and rebind bluetooth service and enable bluetooth
Nitin Arorad055adb2015-03-02 15:03:51 -08001278 if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) &&
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001279 (newState == BluetoothAdapter.STATE_OFF) &&
1280 (mBluetooth != null) && mEnable) {
1281 recoverBluetoothServiceFromError();
1282 }
Nitin Arorad055adb2015-03-02 15:03:51 -08001283 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
1284 (newState == BluetoothAdapter.STATE_BLE_ON) &&
1285 (mBluetooth != null) && mEnable) {
1286 recoverBluetoothServiceFromError();
1287 }
1288 if (newState == BluetoothAdapter.STATE_ON ||
1289 newState == BluetoothAdapter.STATE_BLE_ON) {
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001290 // bluetooth is working, reset the counter
1291 if (mErrorRecoveryRetryCounter != 0) {
1292 Log.w(TAG, "bluetooth is recovered from error");
1293 mErrorRecoveryRetryCounter = 0;
1294 }
1295 }
fredc649fe492012-04-19 01:07:18 -07001296 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001297 }
fredc0f420372012-04-12 00:02:00 -07001298 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
1299 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001300 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301301 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001302 if (msg.arg1 == SERVICE_IBLUETOOTH) {
1303 // if service is unbinded already, do nothing and return
1304 if (mBluetooth == null) break;
1305 mBluetooth = null;
1306 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1307 mBluetoothGatt = null;
1308 break;
1309 } else {
1310 Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
1311 break;
1312 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301313 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001314
1315 if (mEnable) {
1316 mEnable = false;
1317 // Send a Bluetooth Restart message
1318 Message restartMsg = mHandler.obtainMessage(
1319 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1320 mHandler.sendMessageDelayed(restartMsg,
1321 SERVICE_RESTART_TIME_MS);
1322 }
1323
1324 if (!mConnection.isGetNameAddressOnly()) {
1325 sendBluetoothServiceDownCallback();
1326
1327 // Send BT state broadcast to update
1328 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001329 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
1330 (mState == BluetoothAdapter.STATE_ON)) {
1331 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1332 BluetoothAdapter.STATE_TURNING_OFF);
1333 mState = BluetoothAdapter.STATE_TURNING_OFF;
1334 }
1335 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1336 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1337 BluetoothAdapter.STATE_OFF);
1338 }
1339
1340 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -07001341 mState = BluetoothAdapter.STATE_OFF;
1342 }
fredc649fe492012-04-19 01:07:18 -07001343 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001344 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301345 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
1346 {
1347 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
1348 +" Restart IBluetooth service");
1349 /* Enable without persisting the setting as
1350 it doesnt change when IBluetooth
1351 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -07001352 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -08001353 handleEnable(mQuietEnable);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301354 break;
1355 }
1356
fredc0f420372012-04-12 00:02:00 -07001357 case MESSAGE_TIMEOUT_UNBIND:
1358 {
fredc649fe492012-04-19 01:07:18 -07001359 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -07001360 synchronized(mConnection) {
1361 mUnbinding = false;
1362 }
fredc649fe492012-04-19 01:07:18 -07001363 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001364 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001365
1366 case MESSAGE_USER_SWITCHED:
1367 {
1368 if (DBG) {
1369 Log.d(TAG, "MESSAGE_USER_SWITCHED");
1370 }
1371 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1372 /* disable and enable BT when detect a user switch */
1373 if (mEnable && mBluetooth != null) {
1374 synchronized (mConnection) {
1375 if (mBluetooth != null) {
1376 //Unregister callback object
1377 try {
1378 mBluetooth.unregisterCallback(mBluetoothCallback);
1379 } catch (RemoteException re) {
1380 Log.e(TAG, "Unable to unregister",re);
1381 }
1382 }
1383 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001384
1385 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1386 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
1387 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
1388 mState = BluetoothAdapter.STATE_OFF;
1389 }
1390 if (mState == BluetoothAdapter.STATE_OFF) {
1391 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
1392 mState = BluetoothAdapter.STATE_TURNING_ON;
1393 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001394
1395 waitForOnOff(true, false);
1396
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001397 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
1398 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
1399 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001400
Benjamin Franze8b98922014-11-12 15:57:54 +00001401 unbindAllBluetoothProfileServices();
Zhihai Xu40874a02012-10-08 17:57:03 -07001402 // disable
Zhihai Xu401202b2012-12-03 11:36:21 -08001403 handleDisable();
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001404 // Pbap service need receive STATE_TURNING_OFF intent to close
1405 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1406 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001407
1408 waitForOnOff(false, true);
1409
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001410 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -07001411 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001412 sendBluetoothServiceDownCallback();
1413 synchronized (mConnection) {
1414 if (mBluetooth != null) {
1415 mBluetooth = null;
1416 //Unbind
1417 mContext.unbindService(mConnection);
1418 }
1419 }
1420 SystemClock.sleep(100);
1421
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001422 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1423 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -07001424 // enable
Zhihai Xu401202b2012-12-03 11:36:21 -08001425 handleEnable(mQuietEnable);
John Spurlock8a985d22014-02-25 09:40:05 -05001426 } else if (mBinding || mBluetooth != null) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001427 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1428 userMsg.arg2 = 1 + msg.arg2;
1429 // if user is switched when service is being binding
1430 // delay sending MESSAGE_USER_SWITCHED
1431 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1432 if (DBG) {
1433 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1434 }
John Spurlock8a985d22014-02-25 09:40:05 -05001435 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001436 break;
1437 }
fredc0f420372012-04-12 00:02:00 -07001438 }
1439 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001440 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001441
Zhihai Xu401202b2012-12-03 11:36:21 -08001442 private void handleEnable(boolean quietMode) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001443 mQuietEnable = quietMode;
1444
Matthew Xiecdce0b92012-07-12 19:06:15 -07001445 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001446 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001447 //Start bind timeout and bind
1448 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1449 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1450 mConnection.setGetNameAddressOnly(false);
1451 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001452 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1453 UserHandle.CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001454 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -07001455 } else {
1456 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001457 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001458 } else if (mBluetooth != null) {
1459 if (mConnection.isGetNameAddressOnly()) {
1460 // if GetNameAddressOnly is set, we can clear this flag,
1461 // so the service won't be unbind
1462 // after name and address are saved
1463 mConnection.setGetNameAddressOnly(false);
1464 //Register callback object
1465 try {
1466 mBluetooth.registerCallback(mBluetoothCallback);
1467 } catch (RemoteException re) {
1468 Log.e(TAG, "Unable to register BluetoothCallback",re);
1469 }
1470 //Inform BluetoothAdapter instances that service is up
1471 sendBluetoothServiceUpCallback();
1472 }
1473
Matthew Xiecdce0b92012-07-12 19:06:15 -07001474 //Enable bluetooth
1475 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001476 if (!mQuietEnable) {
1477 if(!mBluetooth.enable()) {
1478 Log.e(TAG,"IBluetooth.enable() returned false");
1479 }
1480 }
1481 else {
1482 if(!mBluetooth.enableNoAutoConnect()) {
1483 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1484 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001485 }
1486 } catch (RemoteException e) {
1487 Log.e(TAG,"Unable to call enable()",e);
1488 }
1489 }
1490 }
1491 }
1492
Dianne Hackborn221ea892013-08-04 16:50:16 -07001493 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1494 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1495 intent.setComponent(comp);
1496 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1497 Log.e(TAG, "Fail to bind to: " + intent);
1498 return false;
1499 }
1500 return true;
1501 }
1502
Zhihai Xu401202b2012-12-03 11:36:21 -08001503 private void handleDisable() {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001504 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001505 // don't need to disable if GetNameAddressOnly is set,
1506 // service will be unbinded after Name and Address are saved
1507 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001508 if (DBG) Log.d(TAG,"Sending off request.");
1509
1510 try {
1511 if(!mBluetooth.disable()) {
1512 Log.e(TAG,"IBluetooth.disable() returned false");
1513 }
1514 } catch (RemoteException e) {
1515 Log.e(TAG,"Unable to call disable()",e);
1516 }
1517 }
1518 }
1519 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001520
1521 private boolean checkIfCallerIsForegroundUser() {
1522 int foregroundUser;
1523 int callingUser = UserHandle.getCallingUserId();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001524 int callingUid = Binder.getCallingUid();
Zhihai Xu40874a02012-10-08 17:57:03 -07001525 long callingIdentity = Binder.clearCallingIdentity();
Benjamin Franze8b98922014-11-12 15:57:54 +00001526 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1527 UserInfo ui = um.getProfileParent(callingUser);
1528 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001529 int callingAppId = UserHandle.getAppId(callingUid);
Zhihai Xu40874a02012-10-08 17:57:03 -07001530 boolean valid = false;
1531 try {
1532 foregroundUser = ActivityManager.getCurrentUser();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001533 valid = (callingUser == foregroundUser) ||
Benjamin Franze8b98922014-11-12 15:57:54 +00001534 parentUser == foregroundUser ||
Adrian Roosbd9a9a52014-08-18 15:31:57 +02001535 callingAppId == Process.NFC_UID ||
1536 callingAppId == mSystemUiUid;
Zhihai Xu40874a02012-10-08 17:57:03 -07001537 if (DBG) {
1538 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1539 + " callingUser=" + callingUser
Benjamin Franze8b98922014-11-12 15:57:54 +00001540 + " parentUser=" + parentUser
Zhihai Xu40874a02012-10-08 17:57:03 -07001541 + " foregroundUser=" + foregroundUser);
1542 }
1543 } finally {
1544 Binder.restoreCallingIdentity(callingIdentity);
1545 }
1546 return valid;
1547 }
1548
Nitin Arorad055adb2015-03-02 15:03:51 -08001549 private void sendBleStateChanged(int prevState, int newState) {
1550 if (DBG) Log.d(TAG,"BLE State Change Intent: " + prevState + " -> " + newState);
1551 // Send broadcast message to everyone else
1552 Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
1553 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1554 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1555 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1556 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1557 }
1558
Zhihai Xu40874a02012-10-08 17:57:03 -07001559 private void bluetoothStateChangeHandler(int prevState, int newState) {
Nitin Arorad055adb2015-03-02 15:03:51 -08001560 boolean isStandardBroadcast = true;
Zhihai Xu40874a02012-10-08 17:57:03 -07001561 if (prevState != newState) {
1562 //Notify all proxy objects first of adapter state change
Nitin Arorad055adb2015-03-02 15:03:51 -08001563 if (newState == BluetoothAdapter.STATE_BLE_ON
1564 || newState == BluetoothAdapter.STATE_OFF) {
1565 boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
1566 && newState == BluetoothAdapter.STATE_BLE_ON);
Zhihai Xu40874a02012-10-08 17:57:03 -07001567
Nitin Arorad055adb2015-03-02 15:03:51 -08001568 if (newState == BluetoothAdapter.STATE_OFF) {
1569 // If Bluetooth is off, send service down event to proxy objects, and unbind
1570 if (DBG) Log.d(TAG, "Bluetooth is complete turn off");
1571 if (canUnbindBluetoothService()) {
1572 if (DBG) Log.d(TAG, "Good to unbind!");
Matthew Xieddf7e472013-03-01 18:41:02 -08001573 sendBluetoothServiceDownCallback();
1574 unbindAndFinish();
Nitin Arorad055adb2015-03-02 15:03:51 -08001575 sendBleStateChanged(prevState, newState);
1576 // Don't broadcast as it has already been broadcast before
1577 isStandardBroadcast = false;
Matthew Xieddf7e472013-03-01 18:41:02 -08001578 }
Nitin Arorad055adb2015-03-02 15:03:51 -08001579
1580 } else if (!intermediate_off) {
1581 // connect to GattService
1582 if (DBG) Log.d(TAG, "Bluetooth is in LE only mode");
1583 if (mBluetoothGatt != null) {
1584 if (DBG) Log.d(TAG, "Calling BluetoothGattServiceUp");
1585 onBluetoothGattServiceUp();
1586 } else {
1587 if (DBG) Log.d(TAG, "Binding Bluetooth GATT service");
1588 if (mContext.getPackageManager().hasSystemFeature(
1589 PackageManager.FEATURE_BLUETOOTH_LE)) {
1590 Intent i = new Intent(IBluetoothGatt.class.getName());
1591 doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.CURRENT);
1592 }
1593 }
1594 sendBleStateChanged(prevState, newState);
1595 //Don't broadcase this as std intent
1596 isStandardBroadcast = false;
1597
1598 } else if (intermediate_off){
1599 if (DBG) Log.d(TAG, "Intermediate off, back to LE only mode");
1600 // For LE only mode, broadcast as is
1601 sendBleStateChanged(prevState, newState);
1602 sendBluetoothStateCallback(false); // BT is OFF for general users
1603 // Broadcast as STATE_OFF
1604 newState = BluetoothAdapter.STATE_OFF;
1605 sendBrEdrDownCallback();
Zhihai Xu40874a02012-10-08 17:57:03 -07001606 }
Nitin Arorad055adb2015-03-02 15:03:51 -08001607 } else if (newState == BluetoothAdapter.STATE_ON) {
1608 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1609 sendBluetoothStateCallback(isUp);
1610 sendBleStateChanged(prevState, newState);
1611
1612 } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
1613 || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF ) {
1614 sendBleStateChanged(prevState, newState);
1615 isStandardBroadcast = false;
1616
1617 } else if (newState == BluetoothAdapter.STATE_TURNING_ON
1618 || newState == BluetoothAdapter.STATE_TURNING_OFF) {
1619 sendBleStateChanged(prevState, newState);
Zhihai Xu40874a02012-10-08 17:57:03 -07001620 }
1621
Nitin Arorad055adb2015-03-02 15:03:51 -08001622 if (isStandardBroadcast) {
1623 if (prevState == BluetoothAdapter.STATE_BLE_ON) {
1624 // Show prevState of BLE_ON as OFF to standard users
1625 prevState = BluetoothAdapter.STATE_OFF;
1626 }
1627 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1628 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1629 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1630 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1631 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, BLUETOOTH_PERM);
1632 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001633 }
1634 }
1635
1636 /**
1637 * if on is true, wait for state become ON
1638 * if off is true, wait for state become OFF
1639 * if both on and off are false, wait for state not ON
1640 */
1641 private boolean waitForOnOff(boolean on, boolean off) {
1642 int i = 0;
1643 while (i < 10) {
1644 synchronized(mConnection) {
1645 try {
1646 if (mBluetooth == null) break;
1647 if (on) {
1648 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1649 } else if (off) {
1650 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001651 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001652 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001653 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001654 } catch (RemoteException e) {
1655 Log.e(TAG, "getState()", e);
1656 break;
1657 }
1658 }
1659 if (on || off) {
1660 SystemClock.sleep(300);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001661 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001662 SystemClock.sleep(50);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001663 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001664 i++;
1665 }
1666 Log.e(TAG,"waitForOnOff time out");
1667 return false;
1668 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001669
Zhihai Xu401202b2012-12-03 11:36:21 -08001670 private void sendDisableMsg() {
1671 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1672 }
1673
1674 private void sendEnableMsg(boolean quietMode) {
1675 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1676 quietMode ? 1 : 0, 0));
1677 }
1678
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001679 private boolean canUnbindBluetoothService() {
1680 synchronized(mConnection) {
1681 //Only unbind with mEnable flag not set
1682 //For race condition: disable and enable back-to-back
1683 //Avoid unbind right after enable due to callback from disable
1684 //Only unbind with Bluetooth at OFF state
1685 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1686 try {
1687 if (mEnable || (mBluetooth == null)) return false;
1688 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1689 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1690 } catch (RemoteException e) {
1691 Log.e(TAG, "getState()", e);
1692 }
1693 }
1694 return false;
1695 }
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001696
1697 private void recoverBluetoothServiceFromError() {
1698 Log.e(TAG,"recoverBluetoothServiceFromError");
1699 synchronized (mConnection) {
1700 if (mBluetooth != null) {
1701 //Unregister callback object
1702 try {
1703 mBluetooth.unregisterCallback(mBluetoothCallback);
1704 } catch (RemoteException re) {
1705 Log.e(TAG, "Unable to unregister",re);
1706 }
1707 }
1708 }
1709
1710 SystemClock.sleep(500);
1711
1712 // disable
1713 handleDisable();
1714
1715 waitForOnOff(false, true);
1716
1717 sendBluetoothServiceDownCallback();
1718 synchronized (mConnection) {
1719 if (mBluetooth != null) {
1720 mBluetooth = null;
1721 //Unbind
1722 mContext.unbindService(mConnection);
1723 }
1724 }
1725
1726 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1727 mState = BluetoothAdapter.STATE_OFF;
1728
1729 mEnable = false;
1730
1731 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1732 // Send a Bluetooth Restart message to reenable bluetooth
1733 Message restartMsg = mHandler.obtainMessage(
1734 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1735 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1736 } else {
1737 // todo: notify user to power down and power up phone to make bluetooth work.
1738 }
1739 }
Mike Lockwood726d4de2014-10-28 14:06:28 -07001740
1741 @Override
1742 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Mike Lockwood75b52bb2014-12-18 14:16:36 -08001743 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
1744
Mike Lockwood726d4de2014-10-28 14:06:28 -07001745 writer.println("enabled: " + mEnable);
1746 writer.println("state: " + mState);
1747 writer.println("address: " + mAddress);
1748 writer.println("name: " + mName);
1749 if (mBluetooth == null) {
1750 writer.println("Bluetooth Service not connected");
1751 } else {
1752 try {
1753 writer.println(mBluetooth.dump());
1754 } catch (RemoteException re) {
1755 writer.println("RemoteException while calling Bluetooth Service");
1756 }
1757 }
1758 }
fredc0f420372012-04-12 00:02:00 -07001759}