blob: 32a6a2faad7551232389b504a406c50038bac715 [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
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;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700117
118 // Locks are not provided for mName and mAddress.
119 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -0700120 private String mAddress;
121 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -0700122 private final ContentResolver mContentResolver;
123 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
124 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -0700125 private IBluetooth mBluetooth;
Matthew Xieddf7e472013-03-01 18:41:02 -0800126 private IBluetoothGatt mBluetoothGatt;
fredc649fe492012-04-19 01:07:18 -0700127 private boolean mBinding;
128 private boolean mUnbinding;
Zhihai Xu401202b2012-12-03 11:36:21 -0800129 // used inside handler thread
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700130 private boolean mQuietEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800131 // configuarion from external IBinder call which is used to
132 // synchronize with broadcast receiver.
133 private boolean mQuietEnableExternal;
134 // configuarion from external IBinder call which is used to
135 // synchronize with broadcast receiver.
136 private boolean mEnableExternal;
137 // used inside handler thread
Zhihai Xu40874a02012-10-08 17:57:03 -0700138 private boolean mEnable;
139 private int mState;
Zhihai Xu40874a02012-10-08 17:57:03 -0700140 private final BluetoothHandler mHandler;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800141 private int mErrorRecoveryRetryCounter;
Adrian Roosbd9a9a52014-08-18 15:31:57 +0200142 private final int mSystemUiUid;
fredc0f420372012-04-12 00:02:00 -0700143
Benjamin Franze8b98922014-11-12 15:57:54 +0000144 // Save a ProfileServiceConnections object for each of the bound
145 // bluetooth profile services
146 private final Map <Integer, ProfileServiceConnections> mProfileServices =
147 new HashMap <Integer, ProfileServiceConnections>();
148
fredc649fe492012-04-19 01:07:18 -0700149 private void registerForAirplaneMode(IntentFilter filter) {
150 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700151 final String airplaneModeRadios = Settings.Global.getString(resolver,
152 Settings.Global.AIRPLANE_MODE_RADIOS);
153 final String toggleableRadios = Settings.Global.getString(resolver,
154 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700155 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700156 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700157 if (mIsAirplaneSensitive) {
158 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
159 }
160 }
161
fredcbf072a72012-05-09 16:52:50 -0700162 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
163 @Override
164 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
165 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
166 mHandler.sendMessage(msg);
167 }
168 };
169
170 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700171 @Override
172 public void onReceive(Context context, Intent intent) {
173 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700174 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700175 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700176 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700177 if (newName != null) {
178 storeNameAndAddress(newName, null);
179 }
fredc649fe492012-04-19 01:07:18 -0700180 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
Zhihai Xu401202b2012-12-03 11:36:21 -0800181 synchronized(mReceiver) {
182 if (isBluetoothPersistedStateOn()) {
183 if (isAirplaneModeOn()) {
184 persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
185 } else {
186 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
187 }
188 }
189 if (isAirplaneModeOn()) {
190 // disable without persisting the setting
191 sendDisableMsg();
192 } else if (mEnableExternal) {
193 // enable without persisting the setting
194 sendEnableMsg(mQuietEnableExternal);
195 }
fredc649fe492012-04-19 01:07:18 -0700196 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700197 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
198 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
199 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
Zhihai Xu401202b2012-12-03 11:36:21 -0800200 } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
201 synchronized(mReceiver) {
202 if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
203 //Enable
204 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
205 sendEnableMsg(mQuietEnableExternal);
206 }
207 }
208
209 if (!isNameAndAddressSet()) {
210 //Sync the Bluetooth name and address from the Bluetooth Adapter
211 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
212 getNameAndAddress();
213 }
fredc0f420372012-04-12 00:02:00 -0700214 }
215 }
216 };
217
218 BluetoothManagerService(Context context) {
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700219 mHandler = new BluetoothHandler(IoThread.get().getLooper());
Zhihai Xu40874a02012-10-08 17:57:03 -0700220
fredc0f420372012-04-12 00:02:00 -0700221 mContext = context;
222 mBluetooth = null;
223 mBinding = false;
224 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700225 mEnable = false;
226 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu401202b2012-12-03 11:36:21 -0800227 mQuietEnableExternal = false;
228 mEnableExternal = false;
fredc0f420372012-04-12 00:02:00 -0700229 mAddress = null;
230 mName = null;
Zhihai Xudd9d17d2013-01-08 17:05:58 -0800231 mErrorRecoveryRetryCounter = 0;
fredc0f420372012-04-12 00:02:00 -0700232 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700233 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
234 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Zhihai Xu401202b2012-12-03 11:36:21 -0800235 IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700236 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700237 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700238 registerForAirplaneMode(filter);
Dianne Hackbornd83a0962014-05-02 16:28:33 -0700239 filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
Matthew Xie6fde3092012-07-11 17:10:07 -0700240 mContext.registerReceiver(mReceiver, filter);
fredc0f420372012-04-12 00:02:00 -0700241 loadStoredNameAndAddress();
Zhihai Xu401202b2012-12-03 11:36:21 -0800242 if (isBluetoothPersistedStateOn()) {
243 mEnableExternal = true;
fredc0f420372012-04-12 00:02:00 -0700244 }
Adrian Roosbd9a9a52014-08-18 15:31:57 +0200245
246 int sysUiUid = -1;
247 try {
248 sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui",
249 UserHandle.USER_OWNER);
250 } catch (PackageManager.NameNotFoundException e) {
251 Log.wtf(TAG, "Unable to resolve SystemUI's UID.", e);
252 }
253 mSystemUiUid = sysUiUid;
fredc0f420372012-04-12 00:02:00 -0700254 }
255
fredc649fe492012-04-19 01:07:18 -0700256 /**
257 * Returns true if airplane mode is currently on
258 */
259 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700260 return Settings.Global.getInt(mContext.getContentResolver(),
261 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700262 }
263
264 /**
265 * Returns true if the Bluetooth saved state is "on"
266 */
267 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700268 return Settings.Global.getInt(mContentResolver,
Zhihai Xu401202b2012-12-03 11:36:21 -0800269 Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
270 }
271
272 /**
273 * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
274 */
275 private final boolean isBluetoothPersistedStateOnBluetooth() {
276 return Settings.Global.getInt(mContentResolver,
277 Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
fredc649fe492012-04-19 01:07:18 -0700278 }
279
280 /**
281 * Save the Bluetooth on/off state
282 *
283 */
Zhihai Xu401202b2012-12-03 11:36:21 -0800284 private void persistBluetoothSetting(int value) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700285 Settings.Global.putInt(mContext.getContentResolver(),
286 Settings.Global.BLUETOOTH_ON,
Zhihai Xu401202b2012-12-03 11:36:21 -0800287 value);
fredc649fe492012-04-19 01:07:18 -0700288 }
289
290 /**
291 * Returns true if the Bluetooth Adapter's name and address is
292 * locally cached
293 * @return
294 */
fredc0f420372012-04-12 00:02:00 -0700295 private boolean isNameAndAddressSet() {
296 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
297 }
298
fredc649fe492012-04-19 01:07:18 -0700299 /**
300 * Retrieve the Bluetooth Adapter's name and address and save it in
301 * in the local cache
302 */
fredc0f420372012-04-12 00:02:00 -0700303 private void loadStoredNameAndAddress() {
304 if (DBG) Log.d(TAG, "Loading stored name and address");
Zhihai Xud31c3222012-10-31 16:08:57 -0700305 if (mContext.getResources().getBoolean
306 (com.android.internal.R.bool.config_bluetooth_address_validation) &&
307 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
308 // if the valid flag is not set, don't load the address and name
309 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
310 return;
311 }
fredc0f420372012-04-12 00:02:00 -0700312 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
313 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
Zhihai Xud31c3222012-10-31 16:08:57 -0700314 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
fredc0f420372012-04-12 00:02:00 -0700315 }
316
fredc649fe492012-04-19 01:07:18 -0700317 /**
318 * Save the Bluetooth name and address in the persistent store.
319 * Only non-null values will be saved.
320 * @param name
321 * @param address
322 */
fredc0f420372012-04-12 00:02:00 -0700323 private void storeNameAndAddress(String name, String address) {
324 if (name != null) {
325 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700326 mName = name;
fredc649fe492012-04-19 01:07:18 -0700327 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
328 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700329 }
330
331 if (address != null) {
332 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700333 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700334 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
335 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700336 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700337
338 if ((name != null) && (address != null)) {
339 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
340 }
fredc0f420372012-04-12 00:02:00 -0700341 }
342
343 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
Natalie Silvanovich55db6462014-05-01 16:12:23 -0700344 if (callback == null) {
345 Log.w(TAG, "Callback is null in registerAdapter");
346 return null;
347 }
fredc0f420372012-04-12 00:02:00 -0700348 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
349 msg.obj = callback;
350 mHandler.sendMessage(msg);
351 synchronized(mConnection) {
352 return mBluetooth;
353 }
354 }
355
356 public void unregisterAdapter(IBluetoothManagerCallback callback) {
Natalie Silvanovich55db6462014-05-01 16:12:23 -0700357 if (callback == null) {
358 Log.w(TAG, "Callback is null in unregisterAdapter");
359 return;
360 }
fredc0f420372012-04-12 00:02:00 -0700361 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
362 "Need BLUETOOTH permission");
363 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
364 msg.obj = callback;
365 mHandler.sendMessage(msg);
366 }
367
368 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
369 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
370 "Need BLUETOOTH permission");
371 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
372 msg.obj = callback;
373 mHandler.sendMessage(msg);
374 }
375
376 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
377 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
378 "Need BLUETOOTH permission");
379 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
380 msg.obj = callback;
381 mHandler.sendMessage(msg);
382 }
383
384 public boolean isEnabled() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800385 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
386 (!checkIfCallerIsForegroundUser())) {
387 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700388 return false;
389 }
390
fredc0f420372012-04-12 00:02:00 -0700391 synchronized(mConnection) {
392 try {
393 return (mBluetooth != null && mBluetooth.isEnabled());
394 } catch (RemoteException e) {
395 Log.e(TAG, "isEnabled()", e);
396 }
397 }
398 return false;
399 }
400
401 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700402 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700403 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
404 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700405 }
fredc0f420372012-04-12 00:02:00 -0700406 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
407 mHandler.sendMessage(msg);
408 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700409 public boolean enableNoAutoConnect()
410 {
411 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
412 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700413
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700414 if (DBG) {
415 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
416 " mBinding = " + mBinding);
417 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800418 int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
419
420 if (callingAppId != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700421 throw new SecurityException("no permission to enable Bluetooth quietly");
422 }
Martijn Coenen8385c5a2012-11-29 10:14:16 -0800423
Zhihai Xu401202b2012-12-03 11:36:21 -0800424 synchronized(mReceiver) {
425 mQuietEnableExternal = true;
426 mEnableExternal = true;
427 sendEnableMsg(true);
428 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700429 return true;
430
431 }
fredc0f420372012-04-12 00:02:00 -0700432 public boolean enable() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800433 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
434 (!checkIfCallerIsForegroundUser())) {
435 Log.w(TAG,"enable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700436 return false;
fredcf2458862012-04-16 15:18:27 -0700437 }
438
Zhihai Xu401202b2012-12-03 11:36:21 -0800439 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
440 "Need BLUETOOTH ADMIN permission");
441 if (DBG) {
442 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
443 " mBinding = " + mBinding);
444 }
445
446 synchronized(mReceiver) {
447 mQuietEnableExternal = false;
448 mEnableExternal = true;
449 // waive WRITE_SECURE_SETTINGS permission check
450 long callingIdentity = Binder.clearCallingIdentity();
451 persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
452 Binder.restoreCallingIdentity(callingIdentity);
453 sendEnableMsg(false);
454 }
455 return true;
fredc0f420372012-04-12 00:02:00 -0700456 }
457
458 public boolean disable(boolean persist) {
459 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
460 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700461
Zhihai Xu6eb76522012-11-29 15:41:04 -0800462 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
463 (!checkIfCallerIsForegroundUser())) {
464 Log.w(TAG,"disable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700465 return false;
466 }
467
fredcf2458862012-04-16 15:18:27 -0700468 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700469 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
470 " mBinding = " + mBinding);
471 }
fredcf2458862012-04-16 15:18:27 -0700472
Zhihai Xu401202b2012-12-03 11:36:21 -0800473 synchronized(mReceiver) {
474 if (persist) {
475 // waive WRITE_SECURE_SETTINGS permission check
476 long callingIdentity = Binder.clearCallingIdentity();
477 persistBluetoothSetting(BLUETOOTH_OFF);
478 Binder.restoreCallingIdentity(callingIdentity);
479 }
480 mEnableExternal = false;
481 sendDisableMsg();
482 }
fredc0f420372012-04-12 00:02:00 -0700483 return true;
484 }
485
fredc649fe492012-04-19 01:07:18 -0700486 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700487 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700488 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
489 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700490 }
491
fredc0f420372012-04-12 00:02:00 -0700492 synchronized (mConnection) {
493 if (mUnbinding) return;
494 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700495 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700496 if (!mConnection.isGetNameAddressOnly()) {
497 //Unregister callback object
498 try {
499 mBluetooth.unregisterCallback(mBluetoothCallback);
500 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700501 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700502 }
503 }
fredc0f420372012-04-12 00:02:00 -0700504 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700505 mBluetooth = null;
506 //Unbind
fredc0f420372012-04-12 00:02:00 -0700507 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700508 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700509 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700510 } else {
511 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700512 }
513 }
514 }
515
Matthew Xieddf7e472013-03-01 18:41:02 -0800516 public IBluetoothGatt getBluetoothGatt() {
517 // sync protection
518 return mBluetoothGatt;
519 }
520
Benjamin Franze8b98922014-11-12 15:57:54 +0000521 @Override
522 public boolean bindBluetoothProfileService(int bluetoothProfile,
523 IBluetoothProfileServiceConnection proxy) {
524 if (!mEnable) {
525 if (DBG) {
526 Log.d(TAG, "Trying to bind to profile: " + bluetoothProfile +
527 ", while Bluetooth was disabled");
528 }
529 return false;
530 }
531 synchronized (mProfileServices) {
532 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
533 if (psc == null) {
534 if (DBG) {
535 Log.d(TAG, "Creating new ProfileServiceConnections object for"
536 + " profile: " + bluetoothProfile);
537 }
Benjamin Franz5b614592014-12-09 18:58:45 +0000538
539 if (bluetoothProfile != BluetoothProfile.HEADSET) return false;
540
541 Intent intent = new Intent(IBluetoothHeadset.class.getName());
Benjamin Franze8b98922014-11-12 15:57:54 +0000542 psc = new ProfileServiceConnections(intent);
Benjamin Franz5b614592014-12-09 18:58:45 +0000543 if (!psc.bindService()) return false;
544
Benjamin Franze8b98922014-11-12 15:57:54 +0000545 mProfileServices.put(new Integer(bluetoothProfile), psc);
Benjamin Franze8b98922014-11-12 15:57:54 +0000546 }
547 }
548
549 // Introducing a delay to give the client app time to prepare
550 Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
551 addProxyMsg.arg1 = bluetoothProfile;
552 addProxyMsg.obj = proxy;
553 mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
554 return true;
555 }
556
557 @Override
558 public void unbindBluetoothProfileService(int bluetoothProfile,
559 IBluetoothProfileServiceConnection proxy) {
560 synchronized (mProfileServices) {
561 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
562 if (psc == null) {
563 return;
564 }
565 psc.removeProxy(proxy);
566 }
567 }
568
569 private void unbindAllBluetoothProfileServices() {
570 synchronized (mProfileServices) {
571 for (Integer i : mProfileServices.keySet()) {
572 ProfileServiceConnections psc = mProfileServices.get(i);
Benjamin Franz5b614592014-12-09 18:58:45 +0000573 try {
574 mContext.unbindService(psc);
575 } catch (IllegalArgumentException e) {
576 Log.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
577 }
Benjamin Franze8b98922014-11-12 15:57:54 +0000578 psc.removeAllProxies();
579 }
580 mProfileServices.clear();
581 }
582 }
583
584 /**
585 * This class manages the clients connected to a given ProfileService
586 * and maintains the connection with that service.
587 */
588 final private class ProfileServiceConnections implements ServiceConnection,
589 IBinder.DeathRecipient {
590 final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
591 new RemoteCallbackList <IBluetoothProfileServiceConnection>();
592 IBinder mService;
593 ComponentName mClassName;
594 Intent mIntent;
595
596 ProfileServiceConnections(Intent intent) {
597 mService = null;
598 mClassName = null;
599 mIntent = intent;
600 }
601
Benjamin Franz5b614592014-12-09 18:58:45 +0000602 private boolean bindService() {
603 if (mIntent != null && mService == null &&
604 doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
Benjamin Franze8b98922014-11-12 15:57:54 +0000605 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
606 msg.obj = this;
607 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
Benjamin Franz5b614592014-12-09 18:58:45 +0000608 return true;
Benjamin Franze8b98922014-11-12 15:57:54 +0000609 }
Benjamin Franz5b614592014-12-09 18:58:45 +0000610 Log.w(TAG, "Unable to bind with intent: " + mIntent);
611 return false;
Benjamin Franze8b98922014-11-12 15:57:54 +0000612 }
613
614 private void addProxy(IBluetoothProfileServiceConnection proxy) {
615 mProxies.register(proxy);
616 if (mService != null) {
617 try{
618 proxy.onServiceConnected(mClassName, mService);
619 } catch (RemoteException e) {
620 Log.e(TAG, "Unable to connect to proxy", e);
621 }
622 } else {
623 if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
624 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
625 msg.obj = this;
626 mHandler.sendMessage(msg);
627 }
628 }
629 }
630
631 private void removeProxy(IBluetoothProfileServiceConnection proxy) {
632 if (proxy != null) {
633 if (mProxies.unregister(proxy)) {
634 try {
635 proxy.onServiceDisconnected(mClassName);
636 } catch (RemoteException e) {
637 Log.e(TAG, "Unable to disconnect proxy", e);
638 }
639 }
640 } else {
641 Log.w(TAG, "Trying to remove a null proxy");
642 }
643 }
644
645 private void removeAllProxies() {
646 onServiceDisconnected(mClassName);
647 mProxies.kill();
648 }
649
650 @Override
651 public void onServiceConnected(ComponentName className, IBinder service) {
652 // remove timeout message
653 mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
654 mService = service;
655 mClassName = className;
656 try {
657 mService.linkToDeath(this, 0);
658 } catch (RemoteException e) {
659 Log.e(TAG, "Unable to linkToDeath", e);
660 }
661 int n = mProxies.beginBroadcast();
662 for (int i = 0; i < n; i++) {
663 try {
664 mProxies.getBroadcastItem(i).onServiceConnected(className, service);
665 } catch (RemoteException e) {
666 Log.e(TAG, "Unable to connect to proxy", e);
667 }
668 }
669 mProxies.finishBroadcast();
670 }
671
672 @Override
673 public void onServiceDisconnected(ComponentName className) {
674 if (mService == null) {
675 return;
676 }
677 mService.unlinkToDeath(this, 0);
678 mService = null;
679 mClassName = null;
680 int n = mProxies.beginBroadcast();
681 for (int i = 0; i < n; i++) {
682 try {
683 mProxies.getBroadcastItem(i).onServiceDisconnected(className);
684 } catch (RemoteException e) {
685 Log.e(TAG, "Unable to disconnect from proxy", e);
686 }
687 }
688 mProxies.finishBroadcast();
689 }
690
691 @Override
692 public void binderDied() {
693 if (DBG) {
694 Log.w(TAG, "Profile service for profile: " + mClassName
695 + " died.");
696 }
697 onServiceDisconnected(mClassName);
698 // Trigger rebind
699 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
700 msg.obj = this;
701 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
702 }
703 }
704
fredcbf072a72012-05-09 16:52:50 -0700705 private void sendBluetoothStateCallback(boolean isUp) {
706 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700707 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700708 for (int i=0; i <n;i++) {
709 try {
710 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
711 } catch (RemoteException e) {
712 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
713 }
714 }
715 mStateChangeCallbacks.finishBroadcast();
716 }
717
718 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700719 * Inform BluetoothAdapter instances that Adapter service is up
720 */
721 private void sendBluetoothServiceUpCallback() {
722 if (!mConnection.isGetNameAddressOnly()) {
723 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
724 int n = mCallbacks.beginBroadcast();
725 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
726 for (int i=0; i <n;i++) {
727 try {
728 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
729 } catch (RemoteException e) {
730 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
731 }
732 }
733 mCallbacks.finishBroadcast();
734 }
735 }
736 /**
fredcbf072a72012-05-09 16:52:50 -0700737 * Inform BluetoothAdapter instances that Adapter service is down
738 */
739 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700740 if (!mConnection.isGetNameAddressOnly()) {
741 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
742 int n = mCallbacks.beginBroadcast();
743 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
744 for (int i=0; i <n;i++) {
745 try {
746 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
747 } catch (RemoteException e) {
748 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
749 }
750 }
751 mCallbacks.finishBroadcast();
752 }
753 }
fredc0f420372012-04-12 00:02:00 -0700754 public String getAddress() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800755 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
756 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700757
Zhihai Xu6eb76522012-11-29 15:41:04 -0800758 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
759 (!checkIfCallerIsForegroundUser())) {
760 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
761 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700762 }
763
fredc116d1d462012-04-20 14:47:08 -0700764 synchronized(mConnection) {
765 if (mBluetooth != null) {
766 try {
767 return mBluetooth.getAddress();
768 } catch (RemoteException e) {
769 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
770 }
771 }
772 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700773 // mAddress is accessed from outside.
774 // It is alright without a lock. Here, bluetooth is off, no other thread is
775 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700776 return mAddress;
777 }
fredc649fe492012-04-19 01:07:18 -0700778
fredc0f420372012-04-12 00:02:00 -0700779 public String getName() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800780 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
781 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700782
Zhihai Xu6eb76522012-11-29 15:41:04 -0800783 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
784 (!checkIfCallerIsForegroundUser())) {
785 Log.w(TAG,"getName(): not allowed for non-active and non system user");
786 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700787 }
788
fredc116d1d462012-04-20 14:47:08 -0700789 synchronized(mConnection) {
790 if (mBluetooth != null) {
791 try {
792 return mBluetooth.getName();
793 } catch (RemoteException e) {
794 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
795 }
796 }
797 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700798 // mName is accessed from outside.
799 // It alright without a lock. Here, bluetooth is off, no other thread is
800 // changing mName
fredc0f420372012-04-12 00:02:00 -0700801 return mName;
802 }
803
fredc0f420372012-04-12 00:02:00 -0700804 private class BluetoothServiceConnection implements ServiceConnection {
805
806 private boolean mGetNameAddressOnly;
807
808 public void setGetNameAddressOnly(boolean getOnly) {
809 mGetNameAddressOnly = getOnly;
810 }
811
812 public boolean isGetNameAddressOnly() {
813 return mGetNameAddressOnly;
814 }
815
816 public void onServiceConnected(ComponentName className, IBinder service) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800817 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700818 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800819 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
820 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
821 msg.arg1 = SERVICE_IBLUETOOTH;
822 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
823 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
824 msg.arg1 = SERVICE_IBLUETOOTHGATT;
825 } else {
826 Log.e(TAG, "Unknown service connected: " + className.getClassName());
827 return;
828 }
fredc0f420372012-04-12 00:02:00 -0700829 msg.obj = service;
830 mHandler.sendMessage(msg);
831 }
832
833 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700834 // Called if we unexpected disconnected.
Matthew Xieddf7e472013-03-01 18:41:02 -0800835 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
836 className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700837 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800838 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
839 msg.arg1 = SERVICE_IBLUETOOTH;
840 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
841 msg.arg1 = SERVICE_IBLUETOOTHGATT;
842 } else {
843 Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
844 return;
845 }
fredc0f420372012-04-12 00:02:00 -0700846 mHandler.sendMessage(msg);
847 }
848 }
849
850 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
851
Zhihai Xu40874a02012-10-08 17:57:03 -0700852 private class BluetoothHandler extends Handler {
853 public BluetoothHandler(Looper looper) {
854 super(looper);
855 }
856
fredc0f420372012-04-12 00:02:00 -0700857 @Override
858 public void handleMessage(Message msg) {
859 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700860 switch (msg.what) {
861 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700862 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700863 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700864 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -0700865 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -0700866 if (DBG) Log.d(TAG, "Binding to service to get name and address");
867 mConnection.setGetNameAddressOnly(true);
868 //Start bind timeout and bind
869 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
870 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
871 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackborn221ea892013-08-04 16:50:16 -0700872 if (!doBind(i, mConnection,
Dianne Hackbornce09f5a2014-10-10 15:03:13 -0700873 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
874 UserHandle.CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700875 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -0700876 } else {
877 mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700878 }
879 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700880 else {
881 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -0700882 saveMsg.arg1 = 0;
883 if (mBluetooth != null) {
884 mHandler.sendMessage(saveMsg);
885 } else {
886 // if enable is also called to bind the service
887 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
888 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
889 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700890 }
fredc0f420372012-04-12 00:02:00 -0700891 }
fredc649fe492012-04-19 01:07:18 -0700892 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700893 }
fredc0f420372012-04-12 00:02:00 -0700894 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -0700895 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -0700896 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700897 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700898 if (!mEnable && mBluetooth != null) {
899 try {
900 mBluetooth.enable();
901 } catch (RemoteException e) {
902 Log.e(TAG,"Unable to call enable()",e);
903 }
904 }
905 }
906 if (mBluetooth != null) waitForOnOff(true, false);
907 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700908 if (mBluetooth != null) {
909 String name = null;
910 String address = null;
911 try {
912 name = mBluetooth.getName();
913 address = mBluetooth.getAddress();
914 } catch (RemoteException re) {
915 Log.e(TAG,"",re);
916 }
fredc0f420372012-04-12 00:02:00 -0700917
Matthew Xiecdce0b92012-07-12 19:06:15 -0700918 if (name != null && address != null) {
919 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -0700920 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700921 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700922 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700923 } else {
924 if (msg.arg1 < MAX_SAVE_RETRIES) {
925 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
926 retryMsg.arg1= 1+msg.arg1;
927 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
928 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
929 } else {
930 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -0700931 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700932 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700933 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700934 }
fredc0f420372012-04-12 00:02:00 -0700935 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700936 if (!mEnable) {
937 try {
938 mBluetooth.disable();
939 } catch (RemoteException e) {
940 Log.e(TAG,"Unable to call disable()",e);
941 }
942 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700943 } else {
944 // rebind service by Request GET NAME AND ADDRESS
945 // if service is unbinded by disable or
946 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
947 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
948 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -0700949 }
950 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700951 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
952 if (unbind) {
953 unbindAndFinish();
954 }
fredc649fe492012-04-19 01:07:18 -0700955 break;
fredc649fe492012-04-19 01:07:18 -0700956 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700957 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700958 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700959 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700960 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700961 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
962 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800963 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -0700964 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700965
fredc0f420372012-04-12 00:02:00 -0700966 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -0700967 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
968 if (mEnable && mBluetooth != null) {
969 waitForOnOff(true, false);
970 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800971 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700972 waitForOnOff(false, false);
973 } else {
974 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800975 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700976 }
fredc0f420372012-04-12 00:02:00 -0700977 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700978
fredc0f420372012-04-12 00:02:00 -0700979 case MESSAGE_REGISTER_ADAPTER:
980 {
981 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700982 boolean added = mCallbacks.register(callback);
983 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700984 }
985 break;
986 case MESSAGE_UNREGISTER_ADAPTER:
987 {
988 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700989 boolean removed = mCallbacks.unregister(callback);
990 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700991 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700992 }
fredc0f420372012-04-12 00:02:00 -0700993 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
994 {
995 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -0700996 if (callback != null) {
997 mStateChangeCallbacks.register(callback);
998 }
fredc0f420372012-04-12 00:02:00 -0700999 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001000 }
fredc0f420372012-04-12 00:02:00 -07001001 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
1002 {
1003 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -07001004 if (callback != null) {
1005 mStateChangeCallbacks.unregister(callback);
1006 }
fredc0f420372012-04-12 00:02:00 -07001007 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001008 }
Benjamin Franze8b98922014-11-12 15:57:54 +00001009 case MESSAGE_ADD_PROXY_DELAYED:
1010 {
1011 ProfileServiceConnections psc = mProfileServices.get(
1012 new Integer(msg.arg1));
1013 if (psc == null) {
1014 break;
1015 }
1016 IBluetoothProfileServiceConnection proxy =
1017 (IBluetoothProfileServiceConnection) msg.obj;
1018 psc.addProxy(proxy);
1019 break;
1020 }
1021 case MESSAGE_BIND_PROFILE_SERVICE:
1022 {
1023 ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
1024 removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
1025 if (psc == null) {
1026 break;
1027 }
1028 psc.bindService();
1029 break;
1030 }
fredc0f420372012-04-12 00:02:00 -07001031 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
1032 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001033 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
fredc0f420372012-04-12 00:02:00 -07001034
1035 IBinder service = (IBinder) msg.obj;
1036 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001037 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1038 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
1039 break;
1040 } // else must be SERVICE_IBLUETOOTH
1041
1042 //Remove timeout
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001043 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Matthew Xieddf7e472013-03-01 18:41:02 -08001044
fredc0f420372012-04-12 00:02:00 -07001045 mBinding = false;
1046 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -07001047
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001048 try {
1049 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
1050 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
1051 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
1052 Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
1053 }
1054 } catch (RemoteException e) {
1055 Log.e(TAG,"Unable to call configHciSnoopLog", e);
1056 }
1057
Matthew Xiecdce0b92012-07-12 19:06:15 -07001058 if (mConnection.isGetNameAddressOnly()) {
1059 //Request GET NAME AND ADDRESS
1060 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1061 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -07001062 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001063 }
fredc0f420372012-04-12 00:02:00 -07001064
Zhihai Xu40874a02012-10-08 17:57:03 -07001065 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -07001066 //Register callback object
fredcbf072a72012-05-09 16:52:50 -07001067 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001068 mBluetooth.registerCallback(mBluetoothCallback);
1069 } catch (RemoteException re) {
1070 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -07001071 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001072 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -07001073 sendBluetoothServiceUpCallback();
1074
Matthew Xiecdce0b92012-07-12 19:06:15 -07001075 //Do enable request
1076 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001077 if (mQuietEnable == false) {
1078 if(!mBluetooth.enable()) {
1079 Log.e(TAG,"IBluetooth.enable() returned false");
1080 }
1081 }
1082 else
1083 {
1084 if(!mBluetooth.enableNoAutoConnect()) {
1085 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1086 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001087 }
1088 } catch (RemoteException e) {
1089 Log.e(TAG,"Unable to call enable()",e);
1090 }
Freda8c6df02012-07-11 10:25:23 -07001091 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001092
1093 if (!mEnable) {
1094 waitForOnOff(true, false);
Zhihai Xu401202b2012-12-03 11:36:21 -08001095 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001096 waitForOnOff(false, false);
1097 }
fredc649fe492012-04-19 01:07:18 -07001098 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001099 }
fredc649fe492012-04-19 01:07:18 -07001100 case MESSAGE_TIMEOUT_BIND: {
1101 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -07001102 synchronized(mConnection) {
1103 mBinding = false;
1104 }
fredc649fe492012-04-19 01:07:18 -07001105 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001106 }
fredcbf072a72012-05-09 16:52:50 -07001107 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -07001108 {
fredcbf072a72012-05-09 16:52:50 -07001109 int prevState = msg.arg1;
1110 int newState = msg.arg2;
1111 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -07001112 mState = newState;
1113 bluetoothStateChangeHandler(prevState, newState);
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001114 // handle error state transition case from TURNING_ON to OFF
1115 // unbind and rebind bluetooth service and enable bluetooth
1116 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
1117 (newState == BluetoothAdapter.STATE_OFF) &&
1118 (mBluetooth != null) && mEnable) {
1119 recoverBluetoothServiceFromError();
1120 }
1121 if (newState == BluetoothAdapter.STATE_ON) {
1122 // bluetooth is working, reset the counter
1123 if (mErrorRecoveryRetryCounter != 0) {
1124 Log.w(TAG, "bluetooth is recovered from error");
1125 mErrorRecoveryRetryCounter = 0;
1126 }
1127 }
fredc649fe492012-04-19 01:07:18 -07001128 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001129 }
fredc0f420372012-04-12 00:02:00 -07001130 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
1131 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001132 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301133 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001134 if (msg.arg1 == SERVICE_IBLUETOOTH) {
1135 // if service is unbinded already, do nothing and return
1136 if (mBluetooth == null) break;
1137 mBluetooth = null;
1138 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1139 mBluetoothGatt = null;
1140 break;
1141 } else {
1142 Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
1143 break;
1144 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301145 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001146
1147 if (mEnable) {
1148 mEnable = false;
1149 // Send a Bluetooth Restart message
1150 Message restartMsg = mHandler.obtainMessage(
1151 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1152 mHandler.sendMessageDelayed(restartMsg,
1153 SERVICE_RESTART_TIME_MS);
1154 }
1155
1156 if (!mConnection.isGetNameAddressOnly()) {
1157 sendBluetoothServiceDownCallback();
1158
1159 // Send BT state broadcast to update
1160 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001161 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
1162 (mState == BluetoothAdapter.STATE_ON)) {
1163 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1164 BluetoothAdapter.STATE_TURNING_OFF);
1165 mState = BluetoothAdapter.STATE_TURNING_OFF;
1166 }
1167 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1168 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1169 BluetoothAdapter.STATE_OFF);
1170 }
1171
1172 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -07001173 mState = BluetoothAdapter.STATE_OFF;
1174 }
fredc649fe492012-04-19 01:07:18 -07001175 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001176 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301177 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
1178 {
1179 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
1180 +" Restart IBluetooth service");
1181 /* Enable without persisting the setting as
1182 it doesnt change when IBluetooth
1183 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -07001184 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -08001185 handleEnable(mQuietEnable);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301186 break;
1187 }
1188
fredc0f420372012-04-12 00:02:00 -07001189 case MESSAGE_TIMEOUT_UNBIND:
1190 {
fredc649fe492012-04-19 01:07:18 -07001191 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -07001192 synchronized(mConnection) {
1193 mUnbinding = false;
1194 }
fredc649fe492012-04-19 01:07:18 -07001195 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001196 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001197
1198 case MESSAGE_USER_SWITCHED:
1199 {
1200 if (DBG) {
1201 Log.d(TAG, "MESSAGE_USER_SWITCHED");
1202 }
1203 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1204 /* disable and enable BT when detect a user switch */
1205 if (mEnable && mBluetooth != null) {
1206 synchronized (mConnection) {
1207 if (mBluetooth != null) {
1208 //Unregister callback object
1209 try {
1210 mBluetooth.unregisterCallback(mBluetoothCallback);
1211 } catch (RemoteException re) {
1212 Log.e(TAG, "Unable to unregister",re);
1213 }
1214 }
1215 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001216
1217 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1218 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
1219 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
1220 mState = BluetoothAdapter.STATE_OFF;
1221 }
1222 if (mState == BluetoothAdapter.STATE_OFF) {
1223 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
1224 mState = BluetoothAdapter.STATE_TURNING_ON;
1225 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001226
1227 waitForOnOff(true, false);
1228
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001229 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
1230 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
1231 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001232
Benjamin Franze8b98922014-11-12 15:57:54 +00001233 unbindAllBluetoothProfileServices();
Zhihai Xu40874a02012-10-08 17:57:03 -07001234 // disable
Zhihai Xu401202b2012-12-03 11:36:21 -08001235 handleDisable();
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001236 // Pbap service need receive STATE_TURNING_OFF intent to close
1237 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1238 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001239
1240 waitForOnOff(false, true);
1241
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001242 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -07001243 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001244 sendBluetoothServiceDownCallback();
1245 synchronized (mConnection) {
1246 if (mBluetooth != null) {
1247 mBluetooth = null;
1248 //Unbind
1249 mContext.unbindService(mConnection);
1250 }
1251 }
1252 SystemClock.sleep(100);
1253
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001254 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1255 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -07001256 // enable
Zhihai Xu401202b2012-12-03 11:36:21 -08001257 handleEnable(mQuietEnable);
John Spurlock8a985d22014-02-25 09:40:05 -05001258 } else if (mBinding || mBluetooth != null) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001259 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1260 userMsg.arg2 = 1 + msg.arg2;
1261 // if user is switched when service is being binding
1262 // delay sending MESSAGE_USER_SWITCHED
1263 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1264 if (DBG) {
1265 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1266 }
John Spurlock8a985d22014-02-25 09:40:05 -05001267 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001268 break;
1269 }
fredc0f420372012-04-12 00:02:00 -07001270 }
1271 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001272 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001273
Zhihai Xu401202b2012-12-03 11:36:21 -08001274 private void handleEnable(boolean quietMode) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001275 mQuietEnable = quietMode;
1276
Matthew Xiecdce0b92012-07-12 19:06:15 -07001277 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001278 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001279 //Start bind timeout and bind
1280 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1281 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1282 mConnection.setGetNameAddressOnly(false);
1283 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001284 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1285 UserHandle.CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001286 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -07001287 } else {
1288 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001289 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001290 } else if (mBluetooth != null) {
1291 if (mConnection.isGetNameAddressOnly()) {
1292 // if GetNameAddressOnly is set, we can clear this flag,
1293 // so the service won't be unbind
1294 // after name and address are saved
1295 mConnection.setGetNameAddressOnly(false);
1296 //Register callback object
1297 try {
1298 mBluetooth.registerCallback(mBluetoothCallback);
1299 } catch (RemoteException re) {
1300 Log.e(TAG, "Unable to register BluetoothCallback",re);
1301 }
1302 //Inform BluetoothAdapter instances that service is up
1303 sendBluetoothServiceUpCallback();
1304 }
1305
Matthew Xiecdce0b92012-07-12 19:06:15 -07001306 //Enable bluetooth
1307 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001308 if (!mQuietEnable) {
1309 if(!mBluetooth.enable()) {
1310 Log.e(TAG,"IBluetooth.enable() returned false");
1311 }
1312 }
1313 else {
1314 if(!mBluetooth.enableNoAutoConnect()) {
1315 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1316 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001317 }
1318 } catch (RemoteException e) {
1319 Log.e(TAG,"Unable to call enable()",e);
1320 }
1321 }
1322 }
1323 }
1324
Dianne Hackborn221ea892013-08-04 16:50:16 -07001325 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1326 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1327 intent.setComponent(comp);
1328 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1329 Log.e(TAG, "Fail to bind to: " + intent);
1330 return false;
1331 }
1332 return true;
1333 }
1334
Zhihai Xu401202b2012-12-03 11:36:21 -08001335 private void handleDisable() {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001336 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001337 // don't need to disable if GetNameAddressOnly is set,
1338 // service will be unbinded after Name and Address are saved
1339 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001340 if (DBG) Log.d(TAG,"Sending off request.");
1341
1342 try {
1343 if(!mBluetooth.disable()) {
1344 Log.e(TAG,"IBluetooth.disable() returned false");
1345 }
1346 } catch (RemoteException e) {
1347 Log.e(TAG,"Unable to call disable()",e);
1348 }
1349 }
1350 }
1351 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001352
1353 private boolean checkIfCallerIsForegroundUser() {
1354 int foregroundUser;
1355 int callingUser = UserHandle.getCallingUserId();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001356 int callingUid = Binder.getCallingUid();
Zhihai Xu40874a02012-10-08 17:57:03 -07001357 long callingIdentity = Binder.clearCallingIdentity();
Benjamin Franze8b98922014-11-12 15:57:54 +00001358 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1359 UserInfo ui = um.getProfileParent(callingUser);
1360 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001361 int callingAppId = UserHandle.getAppId(callingUid);
Zhihai Xu40874a02012-10-08 17:57:03 -07001362 boolean valid = false;
1363 try {
1364 foregroundUser = ActivityManager.getCurrentUser();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001365 valid = (callingUser == foregroundUser) ||
Benjamin Franze8b98922014-11-12 15:57:54 +00001366 parentUser == foregroundUser ||
Adrian Roosbd9a9a52014-08-18 15:31:57 +02001367 callingAppId == Process.NFC_UID ||
1368 callingAppId == mSystemUiUid;
Zhihai Xu40874a02012-10-08 17:57:03 -07001369 if (DBG) {
1370 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1371 + " callingUser=" + callingUser
Benjamin Franze8b98922014-11-12 15:57:54 +00001372 + " parentUser=" + parentUser
Zhihai Xu40874a02012-10-08 17:57:03 -07001373 + " foregroundUser=" + foregroundUser);
1374 }
1375 } finally {
1376 Binder.restoreCallingIdentity(callingIdentity);
1377 }
1378 return valid;
1379 }
1380
Zhihai Xu40874a02012-10-08 17:57:03 -07001381 private void bluetoothStateChangeHandler(int prevState, int newState) {
1382 if (prevState != newState) {
1383 //Notify all proxy objects first of adapter state change
1384 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
1385 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1386 sendBluetoothStateCallback(isUp);
1387
Matthew Xieddf7e472013-03-01 18:41:02 -08001388 if (isUp) {
1389 // connect to GattService
Matthew Xie32ab77b2013-05-08 19:26:57 -07001390 if (mContext.getPackageManager().hasSystemFeature(
1391 PackageManager.FEATURE_BLUETOOTH_LE)) {
1392 Intent i = new Intent(IBluetoothGatt.class.getName());
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001393 doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1394 UserHandle.CURRENT);
Matthew Xieddf7e472013-03-01 18:41:02 -08001395 }
1396 } else {
1397 //If Bluetooth is off, send service down event to proxy objects, and unbind
1398 if (!isUp && canUnbindBluetoothService()) {
Benjamin Franze8b98922014-11-12 15:57:54 +00001399 unbindAllBluetoothProfileServices();
Matthew Xieddf7e472013-03-01 18:41:02 -08001400 sendBluetoothServiceDownCallback();
1401 unbindAndFinish();
1402 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001403 }
1404 }
1405
1406 //Send broadcast message to everyone else
1407 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1408 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1409 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1410 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1411 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
1412 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1413 BLUETOOTH_PERM);
1414 }
1415 }
1416
1417 /**
1418 * if on is true, wait for state become ON
1419 * if off is true, wait for state become OFF
1420 * if both on and off are false, wait for state not ON
1421 */
1422 private boolean waitForOnOff(boolean on, boolean off) {
1423 int i = 0;
1424 while (i < 10) {
1425 synchronized(mConnection) {
1426 try {
1427 if (mBluetooth == null) break;
1428 if (on) {
1429 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1430 } else if (off) {
1431 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001432 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001433 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001434 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001435 } catch (RemoteException e) {
1436 Log.e(TAG, "getState()", e);
1437 break;
1438 }
1439 }
1440 if (on || off) {
1441 SystemClock.sleep(300);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001442 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001443 SystemClock.sleep(50);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001444 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001445 i++;
1446 }
1447 Log.e(TAG,"waitForOnOff time out");
1448 return false;
1449 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001450
Zhihai Xu401202b2012-12-03 11:36:21 -08001451 private void sendDisableMsg() {
1452 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1453 }
1454
1455 private void sendEnableMsg(boolean quietMode) {
1456 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1457 quietMode ? 1 : 0, 0));
1458 }
1459
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001460 private boolean canUnbindBluetoothService() {
1461 synchronized(mConnection) {
1462 //Only unbind with mEnable flag not set
1463 //For race condition: disable and enable back-to-back
1464 //Avoid unbind right after enable due to callback from disable
1465 //Only unbind with Bluetooth at OFF state
1466 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1467 try {
1468 if (mEnable || (mBluetooth == null)) return false;
1469 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1470 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1471 } catch (RemoteException e) {
1472 Log.e(TAG, "getState()", e);
1473 }
1474 }
1475 return false;
1476 }
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001477
1478 private void recoverBluetoothServiceFromError() {
1479 Log.e(TAG,"recoverBluetoothServiceFromError");
1480 synchronized (mConnection) {
1481 if (mBluetooth != null) {
1482 //Unregister callback object
1483 try {
1484 mBluetooth.unregisterCallback(mBluetoothCallback);
1485 } catch (RemoteException re) {
1486 Log.e(TAG, "Unable to unregister",re);
1487 }
1488 }
1489 }
1490
1491 SystemClock.sleep(500);
1492
1493 // disable
1494 handleDisable();
1495
1496 waitForOnOff(false, true);
1497
1498 sendBluetoothServiceDownCallback();
1499 synchronized (mConnection) {
1500 if (mBluetooth != null) {
1501 mBluetooth = null;
1502 //Unbind
1503 mContext.unbindService(mConnection);
1504 }
1505 }
1506
1507 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1508 mState = BluetoothAdapter.STATE_OFF;
1509
1510 mEnable = false;
1511
1512 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1513 // Send a Bluetooth Restart message to reenable bluetooth
1514 Message restartMsg = mHandler.obtainMessage(
1515 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1516 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1517 } else {
1518 // todo: notify user to power down and power up phone to make bluetooth work.
1519 }
1520 }
Mike Lockwood726d4de2014-10-28 14:06:28 -07001521
1522 @Override
1523 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Mike Lockwood75b52bb2014-12-18 14:16:36 -08001524 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
1525
Mike Lockwood726d4de2014-10-28 14:06:28 -07001526 writer.println("enabled: " + mEnable);
1527 writer.println("state: " + mState);
1528 writer.println("address: " + mAddress);
1529 writer.println("name: " + mName);
1530 if (mBluetooth == null) {
1531 writer.println("Bluetooth Service not connected");
1532 } else {
1533 try {
1534 writer.println(mBluetooth.dump());
1535 } catch (RemoteException re) {
1536 writer.println("RemoteException while calling Bluetooth Service");
1537 }
1538 }
1539 }
fredc0f420372012-04-12 00:02:00 -07001540}