blob: 3117a17175ba97e221d71c8b33fca3329d1b35f0 [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 }
538 Intent intent = null;
539 if (bluetoothProfile == BluetoothProfile.HEADSET) {
540 intent = new Intent(IBluetoothHeadset.class.getName());
541 } else {
542 return false;
543 }
544 psc = new ProfileServiceConnections(intent);
545 mProfileServices.put(new Integer(bluetoothProfile), psc);
546 psc.bindService();
547 }
548 }
549
550 // Introducing a delay to give the client app time to prepare
551 Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
552 addProxyMsg.arg1 = bluetoothProfile;
553 addProxyMsg.obj = proxy;
554 mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
555 return true;
556 }
557
558 @Override
559 public void unbindBluetoothProfileService(int bluetoothProfile,
560 IBluetoothProfileServiceConnection proxy) {
561 synchronized (mProfileServices) {
562 ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
563 if (psc == null) {
564 return;
565 }
566 psc.removeProxy(proxy);
567 }
568 }
569
570 private void unbindAllBluetoothProfileServices() {
571 synchronized (mProfileServices) {
572 for (Integer i : mProfileServices.keySet()) {
573 ProfileServiceConnections psc = mProfileServices.get(i);
574 mContext.unbindService(psc);
575 psc.removeAllProxies();
576 }
577 mProfileServices.clear();
578 }
579 }
580
581 /**
582 * This class manages the clients connected to a given ProfileService
583 * and maintains the connection with that service.
584 */
585 final private class ProfileServiceConnections implements ServiceConnection,
586 IBinder.DeathRecipient {
587 final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
588 new RemoteCallbackList <IBluetoothProfileServiceConnection>();
589 IBinder mService;
590 ComponentName mClassName;
591 Intent mIntent;
592
593 ProfileServiceConnections(Intent intent) {
594 mService = null;
595 mClassName = null;
596 mIntent = intent;
597 }
598
599 private void bindService() {
600 if (mIntent != null && mService == null) {
601 if (!doBind(mIntent, this, 0, UserHandle.CURRENT_OR_SELF)) {
602 Log.w(TAG, "Unable to bind with intent: " + mIntent
603 + ". Triggering retry.");
604 }
605 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
606 msg.obj = this;
607 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
608 }
609 }
610
611 private void addProxy(IBluetoothProfileServiceConnection proxy) {
612 mProxies.register(proxy);
613 if (mService != null) {
614 try{
615 proxy.onServiceConnected(mClassName, mService);
616 } catch (RemoteException e) {
617 Log.e(TAG, "Unable to connect to proxy", e);
618 }
619 } else {
620 if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
621 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
622 msg.obj = this;
623 mHandler.sendMessage(msg);
624 }
625 }
626 }
627
628 private void removeProxy(IBluetoothProfileServiceConnection proxy) {
629 if (proxy != null) {
630 if (mProxies.unregister(proxy)) {
631 try {
632 proxy.onServiceDisconnected(mClassName);
633 } catch (RemoteException e) {
634 Log.e(TAG, "Unable to disconnect proxy", e);
635 }
636 }
637 } else {
638 Log.w(TAG, "Trying to remove a null proxy");
639 }
640 }
641
642 private void removeAllProxies() {
643 onServiceDisconnected(mClassName);
644 mProxies.kill();
645 }
646
647 @Override
648 public void onServiceConnected(ComponentName className, IBinder service) {
649 // remove timeout message
650 mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
651 mService = service;
652 mClassName = className;
653 try {
654 mService.linkToDeath(this, 0);
655 } catch (RemoteException e) {
656 Log.e(TAG, "Unable to linkToDeath", e);
657 }
658 int n = mProxies.beginBroadcast();
659 for (int i = 0; i < n; i++) {
660 try {
661 mProxies.getBroadcastItem(i).onServiceConnected(className, service);
662 } catch (RemoteException e) {
663 Log.e(TAG, "Unable to connect to proxy", e);
664 }
665 }
666 mProxies.finishBroadcast();
667 }
668
669 @Override
670 public void onServiceDisconnected(ComponentName className) {
671 if (mService == null) {
672 return;
673 }
674 mService.unlinkToDeath(this, 0);
675 mService = null;
676 mClassName = null;
677 int n = mProxies.beginBroadcast();
678 for (int i = 0; i < n; i++) {
679 try {
680 mProxies.getBroadcastItem(i).onServiceDisconnected(className);
681 } catch (RemoteException e) {
682 Log.e(TAG, "Unable to disconnect from proxy", e);
683 }
684 }
685 mProxies.finishBroadcast();
686 }
687
688 @Override
689 public void binderDied() {
690 if (DBG) {
691 Log.w(TAG, "Profile service for profile: " + mClassName
692 + " died.");
693 }
694 onServiceDisconnected(mClassName);
695 // Trigger rebind
696 Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
697 msg.obj = this;
698 mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
699 }
700 }
701
fredcbf072a72012-05-09 16:52:50 -0700702 private void sendBluetoothStateCallback(boolean isUp) {
703 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700704 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700705 for (int i=0; i <n;i++) {
706 try {
707 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
708 } catch (RemoteException e) {
709 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
710 }
711 }
712 mStateChangeCallbacks.finishBroadcast();
713 }
714
715 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700716 * Inform BluetoothAdapter instances that Adapter service is up
717 */
718 private void sendBluetoothServiceUpCallback() {
719 if (!mConnection.isGetNameAddressOnly()) {
720 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
721 int n = mCallbacks.beginBroadcast();
722 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
723 for (int i=0; i <n;i++) {
724 try {
725 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
726 } catch (RemoteException e) {
727 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
728 }
729 }
730 mCallbacks.finishBroadcast();
731 }
732 }
733 /**
fredcbf072a72012-05-09 16:52:50 -0700734 * Inform BluetoothAdapter instances that Adapter service is down
735 */
736 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700737 if (!mConnection.isGetNameAddressOnly()) {
738 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
739 int n = mCallbacks.beginBroadcast();
740 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
741 for (int i=0; i <n;i++) {
742 try {
743 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
744 } catch (RemoteException e) {
745 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
746 }
747 }
748 mCallbacks.finishBroadcast();
749 }
750 }
fredc0f420372012-04-12 00:02:00 -0700751 public String getAddress() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800752 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
753 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700754
Zhihai Xu6eb76522012-11-29 15:41:04 -0800755 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
756 (!checkIfCallerIsForegroundUser())) {
757 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
758 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700759 }
760
fredc116d1d462012-04-20 14:47:08 -0700761 synchronized(mConnection) {
762 if (mBluetooth != null) {
763 try {
764 return mBluetooth.getAddress();
765 } catch (RemoteException e) {
766 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
767 }
768 }
769 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700770 // mAddress is accessed from outside.
771 // It is alright without a lock. Here, bluetooth is off, no other thread is
772 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700773 return mAddress;
774 }
fredc649fe492012-04-19 01:07:18 -0700775
fredc0f420372012-04-12 00:02:00 -0700776 public String getName() {
Matthew Xieaf5ddbf2012-12-04 10:47:43 -0800777 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
778 "Need BLUETOOTH permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700779
Zhihai Xu6eb76522012-11-29 15:41:04 -0800780 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
781 (!checkIfCallerIsForegroundUser())) {
782 Log.w(TAG,"getName(): not allowed for non-active and non system user");
783 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700784 }
785
fredc116d1d462012-04-20 14:47:08 -0700786 synchronized(mConnection) {
787 if (mBluetooth != null) {
788 try {
789 return mBluetooth.getName();
790 } catch (RemoteException e) {
791 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
792 }
793 }
794 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700795 // mName is accessed from outside.
796 // It alright without a lock. Here, bluetooth is off, no other thread is
797 // changing mName
fredc0f420372012-04-12 00:02:00 -0700798 return mName;
799 }
800
fredc0f420372012-04-12 00:02:00 -0700801 private class BluetoothServiceConnection implements ServiceConnection {
802
803 private boolean mGetNameAddressOnly;
804
805 public void setGetNameAddressOnly(boolean getOnly) {
806 mGetNameAddressOnly = getOnly;
807 }
808
809 public boolean isGetNameAddressOnly() {
810 return mGetNameAddressOnly;
811 }
812
813 public void onServiceConnected(ComponentName className, IBinder service) {
Matthew Xieddf7e472013-03-01 18:41:02 -0800814 if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700815 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800816 // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
817 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
818 msg.arg1 = SERVICE_IBLUETOOTH;
819 // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
820 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
821 msg.arg1 = SERVICE_IBLUETOOTHGATT;
822 } else {
823 Log.e(TAG, "Unknown service connected: " + className.getClassName());
824 return;
825 }
fredc0f420372012-04-12 00:02:00 -0700826 msg.obj = service;
827 mHandler.sendMessage(msg);
828 }
829
830 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700831 // Called if we unexpected disconnected.
Matthew Xieddf7e472013-03-01 18:41:02 -0800832 if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
833 className.getClassName());
fredc0f420372012-04-12 00:02:00 -0700834 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
Matthew Xieddf7e472013-03-01 18:41:02 -0800835 if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
836 msg.arg1 = SERVICE_IBLUETOOTH;
837 } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
838 msg.arg1 = SERVICE_IBLUETOOTHGATT;
839 } else {
840 Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
841 return;
842 }
fredc0f420372012-04-12 00:02:00 -0700843 mHandler.sendMessage(msg);
844 }
845 }
846
847 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
848
Zhihai Xu40874a02012-10-08 17:57:03 -0700849 private class BluetoothHandler extends Handler {
850 public BluetoothHandler(Looper looper) {
851 super(looper);
852 }
853
fredc0f420372012-04-12 00:02:00 -0700854 @Override
855 public void handleMessage(Message msg) {
856 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700857 switch (msg.what) {
858 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700859 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700860 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700861 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -0700862 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -0700863 if (DBG) Log.d(TAG, "Binding to service to get name and address");
864 mConnection.setGetNameAddressOnly(true);
865 //Start bind timeout and bind
866 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
867 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
868 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackborn221ea892013-08-04 16:50:16 -0700869 if (!doBind(i, mConnection,
Dianne Hackbornce09f5a2014-10-10 15:03:13 -0700870 Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
871 UserHandle.CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700872 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -0700873 } else {
874 mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700875 }
876 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700877 else {
878 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -0700879 saveMsg.arg1 = 0;
880 if (mBluetooth != null) {
881 mHandler.sendMessage(saveMsg);
882 } else {
883 // if enable is also called to bind the service
884 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
885 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
886 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700887 }
fredc0f420372012-04-12 00:02:00 -0700888 }
fredc649fe492012-04-19 01:07:18 -0700889 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700890 }
fredc0f420372012-04-12 00:02:00 -0700891 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -0700892 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -0700893 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700894 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700895 if (!mEnable && mBluetooth != null) {
896 try {
897 mBluetooth.enable();
898 } catch (RemoteException e) {
899 Log.e(TAG,"Unable to call enable()",e);
900 }
901 }
902 }
903 if (mBluetooth != null) waitForOnOff(true, false);
904 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700905 if (mBluetooth != null) {
906 String name = null;
907 String address = null;
908 try {
909 name = mBluetooth.getName();
910 address = mBluetooth.getAddress();
911 } catch (RemoteException re) {
912 Log.e(TAG,"",re);
913 }
fredc0f420372012-04-12 00:02:00 -0700914
Matthew Xiecdce0b92012-07-12 19:06:15 -0700915 if (name != null && address != null) {
916 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -0700917 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700918 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700919 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700920 } else {
921 if (msg.arg1 < MAX_SAVE_RETRIES) {
922 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
923 retryMsg.arg1= 1+msg.arg1;
924 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
925 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
926 } else {
927 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -0700928 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700929 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700930 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700931 }
fredc0f420372012-04-12 00:02:00 -0700932 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700933 if (!mEnable) {
934 try {
935 mBluetooth.disable();
936 } catch (RemoteException e) {
937 Log.e(TAG,"Unable to call disable()",e);
938 }
939 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700940 } else {
941 // rebind service by Request GET NAME AND ADDRESS
942 // if service is unbinded by disable or
943 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
944 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
945 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -0700946 }
947 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700948 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
949 if (unbind) {
950 unbindAndFinish();
951 }
fredc649fe492012-04-19 01:07:18 -0700952 break;
fredc649fe492012-04-19 01:07:18 -0700953 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700954 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700955 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700956 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700957 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700958 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
959 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -0800960 handleEnable(msg.arg1 == 1);
fredc649fe492012-04-19 01:07:18 -0700961 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700962
fredc0f420372012-04-12 00:02:00 -0700963 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -0700964 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
965 if (mEnable && mBluetooth != null) {
966 waitForOnOff(true, false);
967 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800968 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700969 waitForOnOff(false, false);
970 } else {
971 mEnable = false;
Zhihai Xu401202b2012-12-03 11:36:21 -0800972 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -0700973 }
fredc0f420372012-04-12 00:02:00 -0700974 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700975
fredc0f420372012-04-12 00:02:00 -0700976 case MESSAGE_REGISTER_ADAPTER:
977 {
978 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700979 boolean added = mCallbacks.register(callback);
980 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700981 }
982 break;
983 case MESSAGE_UNREGISTER_ADAPTER:
984 {
985 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700986 boolean removed = mCallbacks.unregister(callback);
987 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700988 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700989 }
fredc0f420372012-04-12 00:02:00 -0700990 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
991 {
992 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -0700993 if (callback != null) {
994 mStateChangeCallbacks.register(callback);
995 }
fredc0f420372012-04-12 00:02:00 -0700996 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700997 }
fredc0f420372012-04-12 00:02:00 -0700998 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
999 {
1000 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
Matthew Xie9b693992013-10-10 11:21:40 -07001001 if (callback != null) {
1002 mStateChangeCallbacks.unregister(callback);
1003 }
fredc0f420372012-04-12 00:02:00 -07001004 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001005 }
Benjamin Franze8b98922014-11-12 15:57:54 +00001006 case MESSAGE_ADD_PROXY_DELAYED:
1007 {
1008 ProfileServiceConnections psc = mProfileServices.get(
1009 new Integer(msg.arg1));
1010 if (psc == null) {
1011 break;
1012 }
1013 IBluetoothProfileServiceConnection proxy =
1014 (IBluetoothProfileServiceConnection) msg.obj;
1015 psc.addProxy(proxy);
1016 break;
1017 }
1018 case MESSAGE_BIND_PROFILE_SERVICE:
1019 {
1020 ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
1021 removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
1022 if (psc == null) {
1023 break;
1024 }
1025 psc.bindService();
1026 break;
1027 }
fredc0f420372012-04-12 00:02:00 -07001028 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
1029 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001030 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
fredc0f420372012-04-12 00:02:00 -07001031
1032 IBinder service = (IBinder) msg.obj;
1033 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001034 if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1035 mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
1036 break;
1037 } // else must be SERVICE_IBLUETOOTH
1038
1039 //Remove timeout
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001040 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Matthew Xieddf7e472013-03-01 18:41:02 -08001041
fredc0f420372012-04-12 00:02:00 -07001042 mBinding = false;
1043 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -07001044
Zhihai Xuaf5971e2013-06-10 20:28:31 -07001045 try {
1046 boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
1047 Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
1048 if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
1049 Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
1050 }
1051 } catch (RemoteException e) {
1052 Log.e(TAG,"Unable to call configHciSnoopLog", e);
1053 }
1054
Matthew Xiecdce0b92012-07-12 19:06:15 -07001055 if (mConnection.isGetNameAddressOnly()) {
1056 //Request GET NAME AND ADDRESS
1057 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
1058 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -07001059 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001060 }
fredc0f420372012-04-12 00:02:00 -07001061
Zhihai Xu40874a02012-10-08 17:57:03 -07001062 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -07001063 //Register callback object
fredcbf072a72012-05-09 16:52:50 -07001064 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001065 mBluetooth.registerCallback(mBluetoothCallback);
1066 } catch (RemoteException re) {
1067 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -07001068 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001069 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -07001070 sendBluetoothServiceUpCallback();
1071
Matthew Xiecdce0b92012-07-12 19:06:15 -07001072 //Do enable request
1073 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001074 if (mQuietEnable == false) {
1075 if(!mBluetooth.enable()) {
1076 Log.e(TAG,"IBluetooth.enable() returned false");
1077 }
1078 }
1079 else
1080 {
1081 if(!mBluetooth.enableNoAutoConnect()) {
1082 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1083 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001084 }
1085 } catch (RemoteException e) {
1086 Log.e(TAG,"Unable to call enable()",e);
1087 }
Freda8c6df02012-07-11 10:25:23 -07001088 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001089
1090 if (!mEnable) {
1091 waitForOnOff(true, false);
Zhihai Xu401202b2012-12-03 11:36:21 -08001092 handleDisable();
Zhihai Xu40874a02012-10-08 17:57:03 -07001093 waitForOnOff(false, false);
1094 }
fredc649fe492012-04-19 01:07:18 -07001095 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001096 }
fredc649fe492012-04-19 01:07:18 -07001097 case MESSAGE_TIMEOUT_BIND: {
1098 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -07001099 synchronized(mConnection) {
1100 mBinding = false;
1101 }
fredc649fe492012-04-19 01:07:18 -07001102 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001103 }
fredcbf072a72012-05-09 16:52:50 -07001104 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -07001105 {
fredcbf072a72012-05-09 16:52:50 -07001106 int prevState = msg.arg1;
1107 int newState = msg.arg2;
1108 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -07001109 mState = newState;
1110 bluetoothStateChangeHandler(prevState, newState);
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001111 // handle error state transition case from TURNING_ON to OFF
1112 // unbind and rebind bluetooth service and enable bluetooth
1113 if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
1114 (newState == BluetoothAdapter.STATE_OFF) &&
1115 (mBluetooth != null) && mEnable) {
1116 recoverBluetoothServiceFromError();
1117 }
1118 if (newState == BluetoothAdapter.STATE_ON) {
1119 // bluetooth is working, reset the counter
1120 if (mErrorRecoveryRetryCounter != 0) {
1121 Log.w(TAG, "bluetooth is recovered from error");
1122 mErrorRecoveryRetryCounter = 0;
1123 }
1124 }
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_BLUETOOTH_SERVICE_DISCONNECTED:
1128 {
Matthew Xieddf7e472013-03-01 18:41:02 -08001129 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301130 synchronized(mConnection) {
Matthew Xieddf7e472013-03-01 18:41:02 -08001131 if (msg.arg1 == SERVICE_IBLUETOOTH) {
1132 // if service is unbinded already, do nothing and return
1133 if (mBluetooth == null) break;
1134 mBluetooth = null;
1135 } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
1136 mBluetoothGatt = null;
1137 break;
1138 } else {
1139 Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
1140 break;
1141 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301142 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001143
1144 if (mEnable) {
1145 mEnable = false;
1146 // Send a Bluetooth Restart message
1147 Message restartMsg = mHandler.obtainMessage(
1148 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1149 mHandler.sendMessageDelayed(restartMsg,
1150 SERVICE_RESTART_TIME_MS);
1151 }
1152
1153 if (!mConnection.isGetNameAddressOnly()) {
1154 sendBluetoothServiceDownCallback();
1155
1156 // Send BT state broadcast to update
1157 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001158 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
1159 (mState == BluetoothAdapter.STATE_ON)) {
1160 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1161 BluetoothAdapter.STATE_TURNING_OFF);
1162 mState = BluetoothAdapter.STATE_TURNING_OFF;
1163 }
1164 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1165 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
1166 BluetoothAdapter.STATE_OFF);
1167 }
1168
1169 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -07001170 mState = BluetoothAdapter.STATE_OFF;
1171 }
fredc649fe492012-04-19 01:07:18 -07001172 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001173 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301174 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
1175 {
1176 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
1177 +" Restart IBluetooth service");
1178 /* Enable without persisting the setting as
1179 it doesnt change when IBluetooth
1180 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -07001181 mEnable = true;
Zhihai Xu401202b2012-12-03 11:36:21 -08001182 handleEnable(mQuietEnable);
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +05301183 break;
1184 }
1185
fredc0f420372012-04-12 00:02:00 -07001186 case MESSAGE_TIMEOUT_UNBIND:
1187 {
fredc649fe492012-04-19 01:07:18 -07001188 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -07001189 synchronized(mConnection) {
1190 mUnbinding = false;
1191 }
fredc649fe492012-04-19 01:07:18 -07001192 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001193 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001194
1195 case MESSAGE_USER_SWITCHED:
1196 {
1197 if (DBG) {
1198 Log.d(TAG, "MESSAGE_USER_SWITCHED");
1199 }
1200 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
1201 /* disable and enable BT when detect a user switch */
1202 if (mEnable && mBluetooth != null) {
1203 synchronized (mConnection) {
1204 if (mBluetooth != null) {
1205 //Unregister callback object
1206 try {
1207 mBluetooth.unregisterCallback(mBluetoothCallback);
1208 } catch (RemoteException re) {
1209 Log.e(TAG, "Unable to unregister",re);
1210 }
1211 }
1212 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001213
1214 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
1215 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
1216 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
1217 mState = BluetoothAdapter.STATE_OFF;
1218 }
1219 if (mState == BluetoothAdapter.STATE_OFF) {
1220 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
1221 mState = BluetoothAdapter.STATE_TURNING_ON;
1222 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001223
1224 waitForOnOff(true, false);
1225
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001226 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
1227 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
1228 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001229
Benjamin Franze8b98922014-11-12 15:57:54 +00001230 unbindAllBluetoothProfileServices();
Zhihai Xu40874a02012-10-08 17:57:03 -07001231 // disable
Zhihai Xu401202b2012-12-03 11:36:21 -08001232 handleDisable();
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001233 // Pbap service need receive STATE_TURNING_OFF intent to close
1234 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
1235 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001236
1237 waitForOnOff(false, true);
1238
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001239 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -07001240 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -07001241 sendBluetoothServiceDownCallback();
1242 synchronized (mConnection) {
1243 if (mBluetooth != null) {
1244 mBluetooth = null;
1245 //Unbind
1246 mContext.unbindService(mConnection);
1247 }
1248 }
1249 SystemClock.sleep(100);
1250
Zhihai Xu4e22ad32012-11-13 15:11:26 -08001251 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1252 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -07001253 // enable
Zhihai Xu401202b2012-12-03 11:36:21 -08001254 handleEnable(mQuietEnable);
John Spurlock8a985d22014-02-25 09:40:05 -05001255 } else if (mBinding || mBluetooth != null) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001256 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
1257 userMsg.arg2 = 1 + msg.arg2;
1258 // if user is switched when service is being binding
1259 // delay sending MESSAGE_USER_SWITCHED
1260 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
1261 if (DBG) {
1262 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
1263 }
John Spurlock8a985d22014-02-25 09:40:05 -05001264 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001265 break;
1266 }
fredc0f420372012-04-12 00:02:00 -07001267 }
1268 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001269 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001270
Zhihai Xu401202b2012-12-03 11:36:21 -08001271 private void handleEnable(boolean quietMode) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001272 mQuietEnable = quietMode;
1273
Matthew Xiecdce0b92012-07-12 19:06:15 -07001274 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001275 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001276 //Start bind timeout and bind
1277 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
1278 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
1279 mConnection.setGetNameAddressOnly(false);
1280 Intent i = new Intent(IBluetooth.class.getName());
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001281 if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1282 UserHandle.CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001283 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Zhihai Xu40874a02012-10-08 17:57:03 -07001284 } else {
1285 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -07001286 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001287 } else if (mBluetooth != null) {
1288 if (mConnection.isGetNameAddressOnly()) {
1289 // if GetNameAddressOnly is set, we can clear this flag,
1290 // so the service won't be unbind
1291 // after name and address are saved
1292 mConnection.setGetNameAddressOnly(false);
1293 //Register callback object
1294 try {
1295 mBluetooth.registerCallback(mBluetoothCallback);
1296 } catch (RemoteException re) {
1297 Log.e(TAG, "Unable to register BluetoothCallback",re);
1298 }
1299 //Inform BluetoothAdapter instances that service is up
1300 sendBluetoothServiceUpCallback();
1301 }
1302
Matthew Xiecdce0b92012-07-12 19:06:15 -07001303 //Enable bluetooth
1304 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -07001305 if (!mQuietEnable) {
1306 if(!mBluetooth.enable()) {
1307 Log.e(TAG,"IBluetooth.enable() returned false");
1308 }
1309 }
1310 else {
1311 if(!mBluetooth.enableNoAutoConnect()) {
1312 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
1313 }
Matthew Xiecdce0b92012-07-12 19:06:15 -07001314 }
1315 } catch (RemoteException e) {
1316 Log.e(TAG,"Unable to call enable()",e);
1317 }
1318 }
1319 }
1320 }
1321
Dianne Hackborn221ea892013-08-04 16:50:16 -07001322 boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
1323 ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
1324 intent.setComponent(comp);
1325 if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
1326 Log.e(TAG, "Fail to bind to: " + intent);
1327 return false;
1328 }
1329 return true;
1330 }
1331
Zhihai Xu401202b2012-12-03 11:36:21 -08001332 private void handleDisable() {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001333 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -07001334 // don't need to disable if GetNameAddressOnly is set,
1335 // service will be unbinded after Name and Address are saved
1336 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -07001337 if (DBG) Log.d(TAG,"Sending off request.");
1338
1339 try {
1340 if(!mBluetooth.disable()) {
1341 Log.e(TAG,"IBluetooth.disable() returned false");
1342 }
1343 } catch (RemoteException e) {
1344 Log.e(TAG,"Unable to call disable()",e);
1345 }
1346 }
1347 }
1348 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001349
1350 private boolean checkIfCallerIsForegroundUser() {
1351 int foregroundUser;
1352 int callingUser = UserHandle.getCallingUserId();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001353 int callingUid = Binder.getCallingUid();
Zhihai Xu40874a02012-10-08 17:57:03 -07001354 long callingIdentity = Binder.clearCallingIdentity();
Benjamin Franze8b98922014-11-12 15:57:54 +00001355 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1356 UserInfo ui = um.getProfileParent(callingUser);
1357 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001358 int callingAppId = UserHandle.getAppId(callingUid);
Zhihai Xu40874a02012-10-08 17:57:03 -07001359 boolean valid = false;
1360 try {
1361 foregroundUser = ActivityManager.getCurrentUser();
Martijn Coenen8385c5a2012-11-29 10:14:16 -08001362 valid = (callingUser == foregroundUser) ||
Benjamin Franze8b98922014-11-12 15:57:54 +00001363 parentUser == foregroundUser ||
Adrian Roosbd9a9a52014-08-18 15:31:57 +02001364 callingAppId == Process.NFC_UID ||
1365 callingAppId == mSystemUiUid;
Zhihai Xu40874a02012-10-08 17:57:03 -07001366 if (DBG) {
1367 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
1368 + " callingUser=" + callingUser
Benjamin Franze8b98922014-11-12 15:57:54 +00001369 + " parentUser=" + parentUser
Zhihai Xu40874a02012-10-08 17:57:03 -07001370 + " foregroundUser=" + foregroundUser);
1371 }
1372 } finally {
1373 Binder.restoreCallingIdentity(callingIdentity);
1374 }
1375 return valid;
1376 }
1377
Zhihai Xu40874a02012-10-08 17:57:03 -07001378 private void bluetoothStateChangeHandler(int prevState, int newState) {
1379 if (prevState != newState) {
1380 //Notify all proxy objects first of adapter state change
1381 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
1382 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1383 sendBluetoothStateCallback(isUp);
1384
Matthew Xieddf7e472013-03-01 18:41:02 -08001385 if (isUp) {
1386 // connect to GattService
Matthew Xie32ab77b2013-05-08 19:26:57 -07001387 if (mContext.getPackageManager().hasSystemFeature(
1388 PackageManager.FEATURE_BLUETOOTH_LE)) {
1389 Intent i = new Intent(IBluetoothGatt.class.getName());
Dianne Hackbornce09f5a2014-10-10 15:03:13 -07001390 doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
1391 UserHandle.CURRENT);
Matthew Xieddf7e472013-03-01 18:41:02 -08001392 }
1393 } else {
1394 //If Bluetooth is off, send service down event to proxy objects, and unbind
1395 if (!isUp && canUnbindBluetoothService()) {
Benjamin Franze8b98922014-11-12 15:57:54 +00001396 unbindAllBluetoothProfileServices();
Matthew Xieddf7e472013-03-01 18:41:02 -08001397 sendBluetoothServiceDownCallback();
1398 unbindAndFinish();
1399 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001400 }
1401 }
1402
1403 //Send broadcast message to everyone else
1404 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1405 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1406 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1407 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1408 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
1409 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1410 BLUETOOTH_PERM);
1411 }
1412 }
1413
1414 /**
1415 * if on is true, wait for state become ON
1416 * if off is true, wait for state become OFF
1417 * if both on and off are false, wait for state not ON
1418 */
1419 private boolean waitForOnOff(boolean on, boolean off) {
1420 int i = 0;
1421 while (i < 10) {
1422 synchronized(mConnection) {
1423 try {
1424 if (mBluetooth == null) break;
1425 if (on) {
1426 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1427 } else if (off) {
1428 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001429 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001430 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001431 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001432 } catch (RemoteException e) {
1433 Log.e(TAG, "getState()", e);
1434 break;
1435 }
1436 }
1437 if (on || off) {
1438 SystemClock.sleep(300);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001439 } else {
Zhihai Xu40874a02012-10-08 17:57:03 -07001440 SystemClock.sleep(50);
Robert Greenwalt665e1ae2012-08-21 19:27:00 -07001441 }
Zhihai Xu40874a02012-10-08 17:57:03 -07001442 i++;
1443 }
1444 Log.e(TAG,"waitForOnOff time out");
1445 return false;
1446 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001447
Zhihai Xu401202b2012-12-03 11:36:21 -08001448 private void sendDisableMsg() {
1449 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
1450 }
1451
1452 private void sendEnableMsg(boolean quietMode) {
1453 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
1454 quietMode ? 1 : 0, 0));
1455 }
1456
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001457 private boolean canUnbindBluetoothService() {
1458 synchronized(mConnection) {
1459 //Only unbind with mEnable flag not set
1460 //For race condition: disable and enable back-to-back
1461 //Avoid unbind right after enable due to callback from disable
1462 //Only unbind with Bluetooth at OFF state
1463 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1464 try {
1465 if (mEnable || (mBluetooth == null)) return false;
1466 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1467 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1468 } catch (RemoteException e) {
1469 Log.e(TAG, "getState()", e);
1470 }
1471 }
1472 return false;
1473 }
Zhihai Xudd9d17d2013-01-08 17:05:58 -08001474
1475 private void recoverBluetoothServiceFromError() {
1476 Log.e(TAG,"recoverBluetoothServiceFromError");
1477 synchronized (mConnection) {
1478 if (mBluetooth != null) {
1479 //Unregister callback object
1480 try {
1481 mBluetooth.unregisterCallback(mBluetoothCallback);
1482 } catch (RemoteException re) {
1483 Log.e(TAG, "Unable to unregister",re);
1484 }
1485 }
1486 }
1487
1488 SystemClock.sleep(500);
1489
1490 // disable
1491 handleDisable();
1492
1493 waitForOnOff(false, true);
1494
1495 sendBluetoothServiceDownCallback();
1496 synchronized (mConnection) {
1497 if (mBluetooth != null) {
1498 mBluetooth = null;
1499 //Unbind
1500 mContext.unbindService(mConnection);
1501 }
1502 }
1503
1504 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
1505 mState = BluetoothAdapter.STATE_OFF;
1506
1507 mEnable = false;
1508
1509 if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
1510 // Send a Bluetooth Restart message to reenable bluetooth
1511 Message restartMsg = mHandler.obtainMessage(
1512 MESSAGE_RESTART_BLUETOOTH_SERVICE);
1513 mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
1514 } else {
1515 // todo: notify user to power down and power up phone to make bluetooth work.
1516 }
1517 }
Mike Lockwood726d4de2014-10-28 14:06:28 -07001518
1519 @Override
1520 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1521 writer.println("enabled: " + mEnable);
1522 writer.println("state: " + mState);
1523 writer.println("address: " + mAddress);
1524 writer.println("name: " + mName);
1525 if (mBluetooth == null) {
1526 writer.println("Bluetooth Service not connected");
1527 } else {
1528 try {
1529 writer.println(mBluetooth.dump());
1530 } catch (RemoteException re) {
1531 writer.println("RemoteException while calling Bluetooth Service");
1532 }
1533 }
1534 }
fredc0f420372012-04-12 00:02:00 -07001535}