blob: e05fcf4d408b4bd3e90646e90f7793718d4f2827 [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;
21import android.bluetooth.IBluetooth;
fredcbf072a72012-05-09 16:52:50 -070022import android.bluetooth.IBluetoothCallback;
fredc0f420372012-04-12 00:02:00 -070023import android.bluetooth.IBluetoothManager;
24import android.bluetooth.IBluetoothManagerCallback;
25import android.bluetooth.IBluetoothStateChangeCallback;
fredc0f420372012-04-12 00:02:00 -070026import android.content.BroadcastReceiver;
27import android.content.ComponentName;
28import android.content.ContentResolver;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.ServiceConnection;
Zhihai Xu40874a02012-10-08 17:57:03 -070033import android.os.Binder;
fredc0f420372012-04-12 00:02:00 -070034import android.os.Handler;
Zhihai Xu40874a02012-10-08 17:57:03 -070035import android.os.HandlerThread;
fredc0f420372012-04-12 00:02:00 -070036import android.os.IBinder;
Zhihai Xu40874a02012-10-08 17:57:03 -070037import android.os.Looper;
fredc0f420372012-04-12 00:02:00 -070038import android.os.Message;
Zhihai Xu40874a02012-10-08 17:57:03 -070039import android.os.Process;
fredcd6883532012-04-25 17:46:13 -070040import android.os.RemoteCallbackList;
fredc0f420372012-04-12 00:02:00 -070041import android.os.RemoteException;
Zhihai Xu40874a02012-10-08 17:57:03 -070042import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070043import android.os.UserHandle;
fredc0f420372012-04-12 00:02:00 -070044import android.provider.Settings;
45import android.util.Log;
fredc0f420372012-04-12 00:02:00 -070046import java.util.ArrayList;
Zhihai Xu40874a02012-10-08 17:57:03 -070047import java.util.List;
fredc0f420372012-04-12 00:02:00 -070048class BluetoothManagerService extends IBluetoothManager.Stub {
49 private static final String TAG = "BluetoothManagerService";
50 private static final boolean DBG = true;
51
fredc0f420372012-04-12 00:02:00 -070052 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
53 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
fredc0f420372012-04-12 00:02:00 -070054 private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
55 private static final String EXTRA_ACTION="action";
Zhihai Xud31c3222012-10-31 16:08:57 -070056 private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
fredc0f420372012-04-12 00:02:00 -070057 private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
58 private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
fredc0f420372012-04-12 00:02:00 -070059 private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
60 private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053061 //Maximum msec to wait for service restart
62 private static final int SERVICE_RESTART_TIME_MS = 200;
Zhihai Xu40874a02012-10-08 17:57:03 -070063 //Maximum msec to delay MESSAGE_USER_SWITCHED
64 private static final int USER_SWITCHED_TIME_MS = 200;
fredc0f420372012-04-12 00:02:00 -070065
66 private static final int MESSAGE_ENABLE = 1;
67 private static final int MESSAGE_DISABLE = 2;
fredc649fe492012-04-19 01:07:18 -070068 private static final int MESSAGE_REGISTER_ADAPTER = 20;
69 private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
70 private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
71 private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
72 private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
73 private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +053074 private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
fredcbf072a72012-05-09 16:52:50 -070075 private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
fredc0f420372012-04-12 00:02:00 -070076 private static final int MESSAGE_TIMEOUT_BIND =100;
77 private static final int MESSAGE_TIMEOUT_UNBIND =101;
78 private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
79 private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
Zhihai Xu40874a02012-10-08 17:57:03 -070080 private static final int MESSAGE_USER_SWITCHED = 300;
fredc0f420372012-04-12 00:02:00 -070081 private static final int MAX_SAVE_RETRIES=3;
82
83 private final Context mContext;
Matthew Xiecdce0b92012-07-12 19:06:15 -070084
85 // Locks are not provided for mName and mAddress.
86 // They are accessed in handler or broadcast receiver, same thread context.
fredc0f420372012-04-12 00:02:00 -070087 private String mAddress;
88 private String mName;
Matthew Xie6fde3092012-07-11 17:10:07 -070089 private final ContentResolver mContentResolver;
90 private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
91 private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
fredc649fe492012-04-19 01:07:18 -070092 private IBluetooth mBluetooth;
93 private boolean mBinding;
94 private boolean mUnbinding;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -070095 private boolean mQuietEnable = false;
Zhihai Xu40874a02012-10-08 17:57:03 -070096 private boolean mEnable;
97 private int mState;
98 private HandlerThread mThread;
99 private final BluetoothHandler mHandler;
fredc0f420372012-04-12 00:02:00 -0700100
fredc649fe492012-04-19 01:07:18 -0700101 private void registerForAirplaneMode(IntentFilter filter) {
102 final ContentResolver resolver = mContext.getContentResolver();
Christopher Tatec09cdce2012-09-10 16:50:14 -0700103 final String airplaneModeRadios = Settings.Global.getString(resolver,
104 Settings.Global.AIRPLANE_MODE_RADIOS);
105 final String toggleableRadios = Settings.Global.getString(resolver,
106 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
fredc649fe492012-04-19 01:07:18 -0700107 boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
Christopher Tatec09cdce2012-09-10 16:50:14 -0700108 airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
fredc649fe492012-04-19 01:07:18 -0700109 if (mIsAirplaneSensitive) {
110 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
111 }
112 }
113
fredcbf072a72012-05-09 16:52:50 -0700114 private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
115 @Override
116 public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
117 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
118 mHandler.sendMessage(msg);
119 }
120 };
121
122 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
fredc0f420372012-04-12 00:02:00 -0700123 @Override
124 public void onReceive(Context context, Intent intent) {
125 String action = intent.getAction();
fredcbf072a72012-05-09 16:52:50 -0700126 if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
fredc0f420372012-04-12 00:02:00 -0700127 String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
Freda8c6df02012-07-11 10:25:23 -0700128 if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
fredc0f420372012-04-12 00:02:00 -0700129 if (newName != null) {
130 storeNameAndAddress(newName, null);
131 }
fredc649fe492012-04-19 01:07:18 -0700132 } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
133 if (isAirplaneModeOn()) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700134 // disable without persisting the setting
135 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE,
136 0, 0));
137 } else if (isBluetoothPersistedStateOn()) {
138 // enable without persisting the setting
139 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
140 0, 0));
fredc649fe492012-04-19 01:07:18 -0700141 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700142 } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
143 mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
144 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
fredc0f420372012-04-12 00:02:00 -0700145 }
146 }
147 };
148
149 BluetoothManagerService(Context context) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700150 mThread = new HandlerThread("BluetoothManager");
151 mThread.start();
152 mHandler = new BluetoothHandler(mThread.getLooper());
153
fredc0f420372012-04-12 00:02:00 -0700154 mContext = context;
155 mBluetooth = null;
156 mBinding = false;
157 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700158 mEnable = false;
159 mState = BluetoothAdapter.STATE_OFF;
fredc0f420372012-04-12 00:02:00 -0700160 mAddress = null;
161 mName = null;
162 mContentResolver = context.getContentResolver();
fredcd6883532012-04-25 17:46:13 -0700163 mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
164 mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
Matthew Xie6fde3092012-07-11 17:10:07 -0700165 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
166 filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
Zhihai Xu40874a02012-10-08 17:57:03 -0700167 filter.addAction(Intent.ACTION_USER_SWITCHED);
Matthew Xie6fde3092012-07-11 17:10:07 -0700168 registerForAirplaneMode(filter);
169 mContext.registerReceiver(mReceiver, filter);
fredc649fe492012-04-19 01:07:18 -0700170 boolean airplaneModeOn = isAirplaneModeOn();
171 boolean bluetoothOn = isBluetoothPersistedStateOn();
fredc0f420372012-04-12 00:02:00 -0700172 loadStoredNameAndAddress();
fredc649fe492012-04-19 01:07:18 -0700173 if (DBG) Log.d(TAG, "airplaneModeOn: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
Andre Eisenbacha732ffd2012-05-02 00:39:24 -0700174 if (bluetoothOn) {
fredc0f420372012-04-12 00:02:00 -0700175 //Enable
fredc649fe492012-04-19 01:07:18 -0700176 if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
Zhihai Xu40874a02012-10-08 17:57:03 -0700177 enableHelper();
Zhihai Xud31c3222012-10-31 16:08:57 -0700178 }
179
180 if (!isNameAndAddressSet()) {
fredc649fe492012-04-19 01:07:18 -0700181 //Sync the Bluetooth name and address from the Bluetooth Adapter
182 if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
fredc0f420372012-04-12 00:02:00 -0700183 getNameAndAddress();
184 }
185 }
186
fredc649fe492012-04-19 01:07:18 -0700187 /**
188 * Returns true if airplane mode is currently on
189 */
190 private final boolean isAirplaneModeOn() {
Christopher Tatec09cdce2012-09-10 16:50:14 -0700191 return Settings.Global.getInt(mContext.getContentResolver(),
192 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
fredc649fe492012-04-19 01:07:18 -0700193 }
194
195 /**
196 * Returns true if the Bluetooth saved state is "on"
197 */
198 private final boolean isBluetoothPersistedStateOn() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700199 return Settings.Global.getInt(mContentResolver,
200 Settings.Global.BLUETOOTH_ON, 0) ==1;
fredc649fe492012-04-19 01:07:18 -0700201 }
202
203 /**
204 * Save the Bluetooth on/off state
205 *
206 */
207 private void persistBluetoothSetting(boolean setOn) {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700208 Settings.Global.putInt(mContext.getContentResolver(),
209 Settings.Global.BLUETOOTH_ON,
fredc649fe492012-04-19 01:07:18 -0700210 setOn ? 1 : 0);
211 }
212
213 /**
214 * Returns true if the Bluetooth Adapter's name and address is
215 * locally cached
216 * @return
217 */
fredc0f420372012-04-12 00:02:00 -0700218 private boolean isNameAndAddressSet() {
219 return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
220 }
221
fredc649fe492012-04-19 01:07:18 -0700222 /**
223 * Retrieve the Bluetooth Adapter's name and address and save it in
224 * in the local cache
225 */
fredc0f420372012-04-12 00:02:00 -0700226 private void loadStoredNameAndAddress() {
227 if (DBG) Log.d(TAG, "Loading stored name and address");
Zhihai Xud31c3222012-10-31 16:08:57 -0700228 if (mContext.getResources().getBoolean
229 (com.android.internal.R.bool.config_bluetooth_address_validation) &&
230 Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
231 // if the valid flag is not set, don't load the address and name
232 if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
233 return;
234 }
fredc0f420372012-04-12 00:02:00 -0700235 mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
236 mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
Zhihai Xud31c3222012-10-31 16:08:57 -0700237 if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
fredc0f420372012-04-12 00:02:00 -0700238 }
239
fredc649fe492012-04-19 01:07:18 -0700240 /**
241 * Save the Bluetooth name and address in the persistent store.
242 * Only non-null values will be saved.
243 * @param name
244 * @param address
245 */
fredc0f420372012-04-12 00:02:00 -0700246 private void storeNameAndAddress(String name, String address) {
247 if (name != null) {
248 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
fredc0f420372012-04-12 00:02:00 -0700249 mName = name;
fredc649fe492012-04-19 01:07:18 -0700250 if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
251 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
fredc0f420372012-04-12 00:02:00 -0700252 }
253
254 if (address != null) {
255 Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
fredc0f420372012-04-12 00:02:00 -0700256 mAddress=address;
fredc649fe492012-04-19 01:07:18 -0700257 if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
258 Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
fredc0f420372012-04-12 00:02:00 -0700259 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700260
261 if ((name != null) && (address != null)) {
262 Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
263 }
fredc0f420372012-04-12 00:02:00 -0700264 }
265
266 public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
fredc0f420372012-04-12 00:02:00 -0700267 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
268 msg.obj = callback;
269 mHandler.sendMessage(msg);
270 synchronized(mConnection) {
271 return mBluetooth;
272 }
273 }
274
275 public void unregisterAdapter(IBluetoothManagerCallback callback) {
276 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
277 "Need BLUETOOTH permission");
278 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
279 msg.obj = callback;
280 mHandler.sendMessage(msg);
281 }
282
283 public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
284 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
285 "Need BLUETOOTH permission");
286 Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
287 msg.obj = callback;
288 mHandler.sendMessage(msg);
289 }
290
291 public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
292 mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
293 "Need BLUETOOTH permission");
294 Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
295 msg.obj = callback;
296 mHandler.sendMessage(msg);
297 }
298
299 public boolean isEnabled() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800300 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
301 (!checkIfCallerIsForegroundUser())) {
302 Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700303 return false;
304 }
305
fredc0f420372012-04-12 00:02:00 -0700306 synchronized(mConnection) {
307 try {
308 return (mBluetooth != null && mBluetooth.isEnabled());
309 } catch (RemoteException e) {
310 Log.e(TAG, "isEnabled()", e);
311 }
312 }
313 return false;
314 }
315
316 public void getNameAndAddress() {
fredcf2458862012-04-16 15:18:27 -0700317 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700318 Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
319 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700320 }
fredc0f420372012-04-12 00:02:00 -0700321 Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
322 mHandler.sendMessage(msg);
323 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700324 public boolean enableNoAutoConnect()
325 {
326 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
327 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700328
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700329 if (DBG) {
330 Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
331 " mBinding = " + mBinding);
332 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700333 if (Binder.getCallingUid() != Process.NFC_UID) {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700334 throw new SecurityException("no permission to enable Bluetooth quietly");
335 }
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700336 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
337 msg.arg1=0; //No persist
338 msg.arg2=1; //Quiet mode
339 mHandler.sendMessage(msg);
340 return true;
341
342 }
fredc0f420372012-04-12 00:02:00 -0700343 public boolean enable() {
Zhihai Xu6eb76522012-11-29 15:41:04 -0800344 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
345 (!checkIfCallerIsForegroundUser())) {
346 Log.w(TAG,"enable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700347 return false;
fredcf2458862012-04-16 15:18:27 -0700348 }
349
Zhihai Xu40874a02012-10-08 17:57:03 -0700350 return enableHelper();
fredc0f420372012-04-12 00:02:00 -0700351 }
352
353 public boolean disable(boolean persist) {
354 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
355 "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
Zhihai Xu40874a02012-10-08 17:57:03 -0700356
Zhihai Xu6eb76522012-11-29 15:41:04 -0800357 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
358 (!checkIfCallerIsForegroundUser())) {
359 Log.w(TAG,"disable(): not allowed for non-active and non system user");
Zhihai Xu40874a02012-10-08 17:57:03 -0700360 return false;
361 }
362
fredcf2458862012-04-16 15:18:27 -0700363 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700364 Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
365 " mBinding = " + mBinding);
366 }
fredcf2458862012-04-16 15:18:27 -0700367
fredc0f420372012-04-12 00:02:00 -0700368 Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
fredc649fe492012-04-19 01:07:18 -0700369 msg.arg1=(persist?1:0);
fredc0f420372012-04-12 00:02:00 -0700370 mHandler.sendMessage(msg);
371 return true;
372 }
373
fredc649fe492012-04-19 01:07:18 -0700374 public void unbindAndFinish() {
fredcf2458862012-04-16 15:18:27 -0700375 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700376 Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
377 " mBinding = " + mBinding);
fredcf2458862012-04-16 15:18:27 -0700378 }
379
fredc0f420372012-04-12 00:02:00 -0700380 synchronized (mConnection) {
381 if (mUnbinding) return;
382 mUnbinding = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700383 if (mBluetooth != null) {
fredcbf072a72012-05-09 16:52:50 -0700384 if (!mConnection.isGetNameAddressOnly()) {
385 //Unregister callback object
386 try {
387 mBluetooth.unregisterCallback(mBluetoothCallback);
388 } catch (RemoteException re) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700389 Log.e(TAG, "Unable to unregister BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700390 }
391 }
fredc0f420372012-04-12 00:02:00 -0700392 if (DBG) Log.d(TAG, "Sending unbind request.");
fredcd6883532012-04-25 17:46:13 -0700393 mBluetooth = null;
394 //Unbind
fredc0f420372012-04-12 00:02:00 -0700395 mContext.unbindService(mConnection);
fredcd6883532012-04-25 17:46:13 -0700396 mUnbinding = false;
Zhihai Xu40874a02012-10-08 17:57:03 -0700397 mBinding = false;
fredcf2458862012-04-16 15:18:27 -0700398 } else {
399 mUnbinding=false;
fredc0f420372012-04-12 00:02:00 -0700400 }
401 }
402 }
403
fredcbf072a72012-05-09 16:52:50 -0700404 private void sendBluetoothStateCallback(boolean isUp) {
405 int n = mStateChangeCallbacks.beginBroadcast();
Freda8c6df02012-07-11 10:25:23 -0700406 if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
fredcbf072a72012-05-09 16:52:50 -0700407 for (int i=0; i <n;i++) {
408 try {
409 mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
410 } catch (RemoteException e) {
411 Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
412 }
413 }
414 mStateChangeCallbacks.finishBroadcast();
415 }
416
417 /**
Zhihai Xu40874a02012-10-08 17:57:03 -0700418 * Inform BluetoothAdapter instances that Adapter service is up
419 */
420 private void sendBluetoothServiceUpCallback() {
421 if (!mConnection.isGetNameAddressOnly()) {
422 if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
423 int n = mCallbacks.beginBroadcast();
424 Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
425 for (int i=0; i <n;i++) {
426 try {
427 mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
428 } catch (RemoteException e) {
429 Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
430 }
431 }
432 mCallbacks.finishBroadcast();
433 }
434 }
435 /**
fredcbf072a72012-05-09 16:52:50 -0700436 * Inform BluetoothAdapter instances that Adapter service is down
437 */
438 private void sendBluetoothServiceDownCallback() {
fredcd6883532012-04-25 17:46:13 -0700439 if (!mConnection.isGetNameAddressOnly()) {
440 if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
441 int n = mCallbacks.beginBroadcast();
442 Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
443 for (int i=0; i <n;i++) {
444 try {
445 mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
446 } catch (RemoteException e) {
447 Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
448 }
449 }
450 mCallbacks.finishBroadcast();
451 }
452 }
fredc0f420372012-04-12 00:02:00 -0700453 public String getAddress() {
454 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
455 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700456
Zhihai Xu6eb76522012-11-29 15:41:04 -0800457 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
458 (!checkIfCallerIsForegroundUser())) {
459 Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
460 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700461 }
462
fredc116d1d462012-04-20 14:47:08 -0700463 synchronized(mConnection) {
464 if (mBluetooth != null) {
465 try {
466 return mBluetooth.getAddress();
467 } catch (RemoteException e) {
468 Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
469 }
470 }
471 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700472 // mAddress is accessed from outside.
473 // It is alright without a lock. Here, bluetooth is off, no other thread is
474 // changing mAddress
fredc0f420372012-04-12 00:02:00 -0700475 return mAddress;
476 }
fredc649fe492012-04-19 01:07:18 -0700477
fredc0f420372012-04-12 00:02:00 -0700478 public String getName() {
479 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
480 "Need BLUETOOTH ADMIN permission");
Zhihai Xu40874a02012-10-08 17:57:03 -0700481
Zhihai Xu6eb76522012-11-29 15:41:04 -0800482 if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
483 (!checkIfCallerIsForegroundUser())) {
484 Log.w(TAG,"getName(): not allowed for non-active and non system user");
485 return null;
Zhihai Xu40874a02012-10-08 17:57:03 -0700486 }
487
fredc116d1d462012-04-20 14:47:08 -0700488 synchronized(mConnection) {
489 if (mBluetooth != null) {
490 try {
491 return mBluetooth.getName();
492 } catch (RemoteException e) {
493 Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
494 }
495 }
496 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700497 // mName is accessed from outside.
498 // It alright without a lock. Here, bluetooth is off, no other thread is
499 // changing mName
fredc0f420372012-04-12 00:02:00 -0700500 return mName;
501 }
502
fredc0f420372012-04-12 00:02:00 -0700503 private class BluetoothServiceConnection implements ServiceConnection {
504
505 private boolean mGetNameAddressOnly;
506
507 public void setGetNameAddressOnly(boolean getOnly) {
508 mGetNameAddressOnly = getOnly;
509 }
510
511 public boolean isGetNameAddressOnly() {
512 return mGetNameAddressOnly;
513 }
514
515 public void onServiceConnected(ComponentName className, IBinder service) {
fredc649fe492012-04-19 01:07:18 -0700516 if (DBG) Log.d(TAG, "BluetoothServiceConnection: connected to AdapterService");
fredc0f420372012-04-12 00:02:00 -0700517 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
518 msg.obj = service;
519 mHandler.sendMessage(msg);
520 }
521
522 public void onServiceDisconnected(ComponentName className) {
fredc0f420372012-04-12 00:02:00 -0700523 // Called if we unexpected disconnected.
fredc649fe492012-04-19 01:07:18 -0700524 if (DBG) Log.d(TAG, "BluetoothServiceConnection: disconnected from AdapterService");
fredc0f420372012-04-12 00:02:00 -0700525 Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
526 mHandler.sendMessage(msg);
527 }
528 }
529
530 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
531
Zhihai Xu40874a02012-10-08 17:57:03 -0700532 private class BluetoothHandler extends Handler {
533 public BluetoothHandler(Looper looper) {
534 super(looper);
535 }
536
fredc0f420372012-04-12 00:02:00 -0700537 @Override
538 public void handleMessage(Message msg) {
539 if (DBG) Log.d (TAG, "Message: " + msg.what);
fredc0f420372012-04-12 00:02:00 -0700540 switch (msg.what) {
541 case MESSAGE_GET_NAME_AND_ADDRESS: {
fredc649fe492012-04-19 01:07:18 -0700542 if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700543 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700544 //Start bind request
Zhihai Xu40874a02012-10-08 17:57:03 -0700545 if ((mBluetooth == null) && (!mBinding)) {
fredc0f420372012-04-12 00:02:00 -0700546 if (DBG) Log.d(TAG, "Binding to service to get name and address");
547 mConnection.setGetNameAddressOnly(true);
548 //Start bind timeout and bind
549 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
550 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
551 Intent i = new Intent(IBluetooth.class.getName());
552 if (!mContext.bindService(i, mConnection,
Matthew Xiefca9d632012-10-04 12:25:28 -0700553 Context.BIND_AUTO_CREATE, UserHandle.USER_CURRENT)) {
fredc0f420372012-04-12 00:02:00 -0700554 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
555 Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700556 } else {
557 mBinding = true;
fredc0f420372012-04-12 00:02:00 -0700558 }
559 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700560 else {
561 Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
Zhihai Xu40874a02012-10-08 17:57:03 -0700562 saveMsg.arg1 = 0;
563 if (mBluetooth != null) {
564 mHandler.sendMessage(saveMsg);
565 } else {
566 // if enable is also called to bind the service
567 // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
568 mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
569 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700570 }
fredc0f420372012-04-12 00:02:00 -0700571 }
fredc649fe492012-04-19 01:07:18 -0700572 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700573 }
fredc0f420372012-04-12 00:02:00 -0700574 case MESSAGE_SAVE_NAME_AND_ADDRESS: {
Zhihai Xud31c3222012-10-31 16:08:57 -0700575 boolean unbind = false;
fredc649fe492012-04-19 01:07:18 -0700576 if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
Matthew Xiecdce0b92012-07-12 19:06:15 -0700577 synchronized(mConnection) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700578 if (!mEnable && mBluetooth != null) {
579 try {
580 mBluetooth.enable();
581 } catch (RemoteException e) {
582 Log.e(TAG,"Unable to call enable()",e);
583 }
584 }
585 }
586 if (mBluetooth != null) waitForOnOff(true, false);
587 synchronized(mConnection) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700588 if (mBluetooth != null) {
589 String name = null;
590 String address = null;
591 try {
592 name = mBluetooth.getName();
593 address = mBluetooth.getAddress();
594 } catch (RemoteException re) {
595 Log.e(TAG,"",re);
596 }
fredc0f420372012-04-12 00:02:00 -0700597
Matthew Xiecdce0b92012-07-12 19:06:15 -0700598 if (name != null && address != null) {
599 storeNameAndAddress(name,address);
Zhihai Xu40874a02012-10-08 17:57:03 -0700600 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700601 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700602 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700603 } else {
604 if (msg.arg1 < MAX_SAVE_RETRIES) {
605 Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
606 retryMsg.arg1= 1+msg.arg1;
607 if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
608 mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
609 } else {
610 Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
Zhihai Xu40874a02012-10-08 17:57:03 -0700611 if (mConnection.isGetNameAddressOnly()) {
Zhihai Xud31c3222012-10-31 16:08:57 -0700612 unbind = true;
Zhihai Xu40874a02012-10-08 17:57:03 -0700613 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700614 }
fredc0f420372012-04-12 00:02:00 -0700615 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700616 if (!mEnable) {
617 try {
618 mBluetooth.disable();
619 } catch (RemoteException e) {
620 Log.e(TAG,"Unable to call disable()",e);
621 }
622 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700623 } else {
624 // rebind service by Request GET NAME AND ADDRESS
625 // if service is unbinded by disable or
626 // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
627 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
628 mHandler.sendMessage(getMsg);
fredc0f420372012-04-12 00:02:00 -0700629 }
630 }
Zhihai Xud31c3222012-10-31 16:08:57 -0700631 if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
632 if (unbind) {
633 unbindAndFinish();
634 }
fredc649fe492012-04-19 01:07:18 -0700635 break;
fredc649fe492012-04-19 01:07:18 -0700636 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700637 case MESSAGE_ENABLE:
fredcf2458862012-04-16 15:18:27 -0700638 if (DBG) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700639 Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
fredc649fe492012-04-19 01:07:18 -0700640 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700641 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
642 mEnable = true;
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700643 handleEnable(msg.arg1 == 1, msg.arg2 ==1);
fredc649fe492012-04-19 01:07:18 -0700644 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700645
fredc0f420372012-04-12 00:02:00 -0700646 case MESSAGE_DISABLE:
Zhihai Xu40874a02012-10-08 17:57:03 -0700647 mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
648 if (mEnable && mBluetooth != null) {
649 waitForOnOff(true, false);
650 mEnable = false;
651 handleDisable(msg.arg1 == 1);
652 waitForOnOff(false, false);
653 } else {
654 mEnable = false;
655 handleDisable(msg.arg1 == 1);
656 }
fredc0f420372012-04-12 00:02:00 -0700657 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700658
fredc0f420372012-04-12 00:02:00 -0700659 case MESSAGE_REGISTER_ADAPTER:
660 {
661 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700662 boolean added = mCallbacks.register(callback);
663 Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
fredc0f420372012-04-12 00:02:00 -0700664 }
665 break;
666 case MESSAGE_UNREGISTER_ADAPTER:
667 {
668 IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700669 boolean removed = mCallbacks.unregister(callback);
670 Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
fredc0f420372012-04-12 00:02:00 -0700671 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700672 }
fredc0f420372012-04-12 00:02:00 -0700673 case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
674 {
675 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700676 mStateChangeCallbacks.register(callback);
fredc0f420372012-04-12 00:02:00 -0700677 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700678 }
fredc0f420372012-04-12 00:02:00 -0700679 case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
680 {
681 IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
fredcd6883532012-04-25 17:46:13 -0700682 mStateChangeCallbacks.unregister(callback);
fredc0f420372012-04-12 00:02:00 -0700683 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700684 }
fredc0f420372012-04-12 00:02:00 -0700685 case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
686 {
fredc649fe492012-04-19 01:07:18 -0700687 if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED");
688
fredc0f420372012-04-12 00:02:00 -0700689 //Remove timeout
690 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
691
692 IBinder service = (IBinder) msg.obj;
693 synchronized(mConnection) {
fredc0f420372012-04-12 00:02:00 -0700694 mBinding = false;
695 mBluetooth = IBluetooth.Stub.asInterface(service);
fredc0f420372012-04-12 00:02:00 -0700696
Matthew Xiecdce0b92012-07-12 19:06:15 -0700697 if (mConnection.isGetNameAddressOnly()) {
698 //Request GET NAME AND ADDRESS
699 Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
700 mHandler.sendMessage(getMsg);
Zhihai Xu40874a02012-10-08 17:57:03 -0700701 if (!mEnable) return;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700702 }
fredc0f420372012-04-12 00:02:00 -0700703
Zhihai Xu40874a02012-10-08 17:57:03 -0700704 mConnection.setGetNameAddressOnly(false);
Matthew Xiecdce0b92012-07-12 19:06:15 -0700705 //Register callback object
fredcbf072a72012-05-09 16:52:50 -0700706 try {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700707 mBluetooth.registerCallback(mBluetoothCallback);
708 } catch (RemoteException re) {
709 Log.e(TAG, "Unable to register BluetoothCallback",re);
fredcbf072a72012-05-09 16:52:50 -0700710 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700711 //Inform BluetoothAdapter instances that service is up
Zhihai Xu40874a02012-10-08 17:57:03 -0700712 sendBluetoothServiceUpCallback();
713
Matthew Xiecdce0b92012-07-12 19:06:15 -0700714 //Do enable request
715 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700716 if (mQuietEnable == false) {
717 if(!mBluetooth.enable()) {
718 Log.e(TAG,"IBluetooth.enable() returned false");
719 }
720 }
721 else
722 {
723 if(!mBluetooth.enableNoAutoConnect()) {
724 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
725 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700726 }
727 } catch (RemoteException e) {
728 Log.e(TAG,"Unable to call enable()",e);
729 }
Freda8c6df02012-07-11 10:25:23 -0700730 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700731
732 if (!mEnable) {
733 waitForOnOff(true, false);
734 handleDisable(false);
735 waitForOnOff(false, false);
736 }
fredc649fe492012-04-19 01:07:18 -0700737 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700738 }
fredc649fe492012-04-19 01:07:18 -0700739 case MESSAGE_TIMEOUT_BIND: {
740 Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
fredc0f420372012-04-12 00:02:00 -0700741 synchronized(mConnection) {
742 mBinding = false;
743 }
fredc649fe492012-04-19 01:07:18 -0700744 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700745 }
fredcbf072a72012-05-09 16:52:50 -0700746 case MESSAGE_BLUETOOTH_STATE_CHANGE:
fredc0f420372012-04-12 00:02:00 -0700747 {
fredcbf072a72012-05-09 16:52:50 -0700748 int prevState = msg.arg1;
749 int newState = msg.arg2;
750 if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
Zhihai Xu40874a02012-10-08 17:57:03 -0700751 mState = newState;
752 bluetoothStateChangeHandler(prevState, newState);
fredc649fe492012-04-19 01:07:18 -0700753 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700754 }
fredc0f420372012-04-12 00:02:00 -0700755 case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
756 {
Zhihai Xu40874a02012-10-08 17:57:03 -0700757 Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED");
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530758 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700759 // if service is unbinded already, do nothing and return
760 if (mBluetooth == null) return;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530761 mBluetooth = null;
762 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700763
764 if (mEnable) {
765 mEnable = false;
766 // Send a Bluetooth Restart message
767 Message restartMsg = mHandler.obtainMessage(
768 MESSAGE_RESTART_BLUETOOTH_SERVICE);
769 mHandler.sendMessageDelayed(restartMsg,
770 SERVICE_RESTART_TIME_MS);
771 }
772
773 if (!mConnection.isGetNameAddressOnly()) {
774 sendBluetoothServiceDownCallback();
775
776 // Send BT state broadcast to update
777 // the BT icon correctly
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800778 if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
779 (mState == BluetoothAdapter.STATE_ON)) {
780 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
781 BluetoothAdapter.STATE_TURNING_OFF);
782 mState = BluetoothAdapter.STATE_TURNING_OFF;
783 }
784 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
785 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
786 BluetoothAdapter.STATE_OFF);
787 }
788
789 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
Zhihai Xu40874a02012-10-08 17:57:03 -0700790 mState = BluetoothAdapter.STATE_OFF;
791 }
fredc649fe492012-04-19 01:07:18 -0700792 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700793 }
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530794 case MESSAGE_RESTART_BLUETOOTH_SERVICE:
795 {
796 Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
797 +" Restart IBluetooth service");
798 /* Enable without persisting the setting as
799 it doesnt change when IBluetooth
800 service restarts */
Zhihai Xu40874a02012-10-08 17:57:03 -0700801 mEnable = true;
Syed Ibrahim M1223e5a2012-08-29 18:07:26 +0530802 handleEnable(false, mQuietEnable);
803 break;
804 }
805
fredc0f420372012-04-12 00:02:00 -0700806 case MESSAGE_TIMEOUT_UNBIND:
807 {
fredc649fe492012-04-19 01:07:18 -0700808 Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
fredc0f420372012-04-12 00:02:00 -0700809 synchronized(mConnection) {
810 mUnbinding = false;
811 }
fredc649fe492012-04-19 01:07:18 -0700812 break;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700813 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700814
815 case MESSAGE_USER_SWITCHED:
816 {
817 if (DBG) {
818 Log.d(TAG, "MESSAGE_USER_SWITCHED");
819 }
820 mHandler.removeMessages(MESSAGE_USER_SWITCHED);
821 /* disable and enable BT when detect a user switch */
822 if (mEnable && mBluetooth != null) {
823 synchronized (mConnection) {
824 if (mBluetooth != null) {
825 //Unregister callback object
826 try {
827 mBluetooth.unregisterCallback(mBluetoothCallback);
828 } catch (RemoteException re) {
829 Log.e(TAG, "Unable to unregister",re);
830 }
831 }
832 }
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800833
834 if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
835 // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
836 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
837 mState = BluetoothAdapter.STATE_OFF;
838 }
839 if (mState == BluetoothAdapter.STATE_OFF) {
840 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
841 mState = BluetoothAdapter.STATE_TURNING_ON;
842 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700843
844 waitForOnOff(true, false);
845
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800846 if (mState == BluetoothAdapter.STATE_TURNING_ON) {
847 bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
848 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700849
850 // disable
851 handleDisable(false);
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800852 // Pbap service need receive STATE_TURNING_OFF intent to close
853 bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
854 BluetoothAdapter.STATE_TURNING_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700855
856 waitForOnOff(false, true);
857
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800858 bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
Zhihai Xu40874a02012-10-08 17:57:03 -0700859 BluetoothAdapter.STATE_OFF);
Zhihai Xu40874a02012-10-08 17:57:03 -0700860 sendBluetoothServiceDownCallback();
861 synchronized (mConnection) {
862 if (mBluetooth != null) {
863 mBluetooth = null;
864 //Unbind
865 mContext.unbindService(mConnection);
866 }
867 }
868 SystemClock.sleep(100);
869
Zhihai Xu4e22ad32012-11-13 15:11:26 -0800870 mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
871 mState = BluetoothAdapter.STATE_OFF;
Zhihai Xu40874a02012-10-08 17:57:03 -0700872 // enable
873 handleEnable(false, mQuietEnable);
874 } else if (mBinding || mBluetooth != null) {
875 Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
876 userMsg.arg2 = 1 + msg.arg2;
877 // if user is switched when service is being binding
878 // delay sending MESSAGE_USER_SWITCHED
879 mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
880 if (DBG) {
881 Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
882 }
883 }
884 break;
885 }
fredc0f420372012-04-12 00:02:00 -0700886 }
887 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700888 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700889
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700890 private void handleEnable(boolean persist, boolean quietMode) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700891 if (persist) {
892 persistBluetoothSetting(true);
893 }
894
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700895 mQuietEnable = quietMode;
896
Matthew Xiecdce0b92012-07-12 19:06:15 -0700897 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700898 if ((mBluetooth == null) && (!mBinding)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700899 //Start bind timeout and bind
900 Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
901 mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
902 mConnection.setGetNameAddressOnly(false);
903 Intent i = new Intent(IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700904 if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE,
Matthew Xiefca9d632012-10-04 12:25:28 -0700905 UserHandle.USER_CURRENT)) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700906 mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
907 Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
Zhihai Xu40874a02012-10-08 17:57:03 -0700908 } else {
909 mBinding = true;
Matthew Xiecdce0b92012-07-12 19:06:15 -0700910 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700911 } else if (mBluetooth != null) {
912 if (mConnection.isGetNameAddressOnly()) {
913 // if GetNameAddressOnly is set, we can clear this flag,
914 // so the service won't be unbind
915 // after name and address are saved
916 mConnection.setGetNameAddressOnly(false);
917 //Register callback object
918 try {
919 mBluetooth.registerCallback(mBluetoothCallback);
920 } catch (RemoteException re) {
921 Log.e(TAG, "Unable to register BluetoothCallback",re);
922 }
923 //Inform BluetoothAdapter instances that service is up
924 sendBluetoothServiceUpCallback();
925 }
926
Matthew Xiecdce0b92012-07-12 19:06:15 -0700927 //Enable bluetooth
928 try {
Ganesh Ganapathi Battafffa86b2012-08-08 15:35:49 -0700929 if (!mQuietEnable) {
930 if(!mBluetooth.enable()) {
931 Log.e(TAG,"IBluetooth.enable() returned false");
932 }
933 }
934 else {
935 if(!mBluetooth.enableNoAutoConnect()) {
936 Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
937 }
Matthew Xiecdce0b92012-07-12 19:06:15 -0700938 }
939 } catch (RemoteException e) {
940 Log.e(TAG,"Unable to call enable()",e);
941 }
942 }
943 }
944 }
945
946 private void handleDisable(boolean persist) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700947 if (persist) {
948 persistBluetoothSetting(false);
949 }
950
Matthew Xiecdce0b92012-07-12 19:06:15 -0700951 synchronized(mConnection) {
Zhihai Xu40874a02012-10-08 17:57:03 -0700952 // don't need to disable if GetNameAddressOnly is set,
953 // service will be unbinded after Name and Address are saved
954 if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
Matthew Xiecdce0b92012-07-12 19:06:15 -0700955 if (DBG) Log.d(TAG,"Sending off request.");
956
957 try {
958 if(!mBluetooth.disable()) {
959 Log.e(TAG,"IBluetooth.disable() returned false");
960 }
961 } catch (RemoteException e) {
962 Log.e(TAG,"Unable to call disable()",e);
963 }
964 }
965 }
966 }
Zhihai Xu40874a02012-10-08 17:57:03 -0700967
968 private boolean checkIfCallerIsForegroundUser() {
969 int foregroundUser;
970 int callingUser = UserHandle.getCallingUserId();
971 long callingIdentity = Binder.clearCallingIdentity();
972 boolean valid = false;
973 try {
974 foregroundUser = ActivityManager.getCurrentUser();
975 valid = (callingUser == foregroundUser);
976 if (DBG) {
977 Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
978 + " callingUser=" + callingUser
979 + " foregroundUser=" + foregroundUser);
980 }
981 } finally {
982 Binder.restoreCallingIdentity(callingIdentity);
983 }
984 return valid;
985 }
986
987 private boolean enableHelper() {
988 mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
989 "Need BLUETOOTH ADMIN permission");
990 if (DBG) {
991 Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
992 " mBinding = " + mBinding);
993 }
994
995 Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
996 msg.arg1=1; //persist
997 msg.arg2=0; //No Quiet Mode
998 mHandler.sendMessage(msg);
999 return true;
1000 }
1001
1002 private void bluetoothStateChangeHandler(int prevState, int newState) {
1003 if (prevState != newState) {
1004 //Notify all proxy objects first of adapter state change
1005 if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
1006 boolean isUp = (newState==BluetoothAdapter.STATE_ON);
1007 sendBluetoothStateCallback(isUp);
1008
1009 //If Bluetooth is off, send service down event to proxy objects, and unbind
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001010 if (!isUp && canUnbindBluetoothService()) {
1011 sendBluetoothServiceDownCallback();
1012 unbindAndFinish();
Zhihai Xu40874a02012-10-08 17:57:03 -07001013 }
1014 }
1015
1016 //Send broadcast message to everyone else
1017 Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
1018 intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
1019 intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
1020 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1021 if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
1022 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1023 BLUETOOTH_PERM);
1024 }
1025 }
1026
1027 /**
1028 * if on is true, wait for state become ON
1029 * if off is true, wait for state become OFF
1030 * if both on and off are false, wait for state not ON
1031 */
1032 private boolean waitForOnOff(boolean on, boolean off) {
1033 int i = 0;
1034 while (i < 10) {
1035 synchronized(mConnection) {
1036 try {
1037 if (mBluetooth == null) break;
1038 if (on) {
1039 if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
1040 } else if (off) {
1041 if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
1042 } else {
1043 if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
1044 }
1045 } catch (RemoteException e) {
1046 Log.e(TAG, "getState()", e);
1047 break;
1048 }
1049 }
1050 if (on || off) {
1051 SystemClock.sleep(300);
1052 } else {
1053 SystemClock.sleep(50);
1054 }
1055 i++;
1056 }
1057 Log.e(TAG,"waitForOnOff time out");
1058 return false;
1059 }
Zhihai Xu681ae7f2012-11-12 15:14:18 -08001060
1061 private boolean canUnbindBluetoothService() {
1062 synchronized(mConnection) {
1063 //Only unbind with mEnable flag not set
1064 //For race condition: disable and enable back-to-back
1065 //Avoid unbind right after enable due to callback from disable
1066 //Only unbind with Bluetooth at OFF state
1067 //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
1068 try {
1069 if (mEnable || (mBluetooth == null)) return false;
1070 if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
1071 return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
1072 } catch (RemoteException e) {
1073 Log.e(TAG, "getState()", e);
1074 }
1075 }
1076 return false;
1077 }
fredc0f420372012-04-12 00:02:00 -07001078}