summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/BluetoothManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/BluetoothManagerService.java')
-rw-r--r--services/java/com/android/server/BluetoothManagerService.java1262
1 files changed, 0 insertions, 1262 deletions
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
deleted file mode 100644
index 546324a..0000000
--- a/services/java/com/android/server/BluetoothManagerService.java
+++ /dev/null
@@ -1,1262 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.app.ActivityManager;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.IBluetooth;
-import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothCallback;
-import android.bluetooth.IBluetoothManager;
-import android.bluetooth.IBluetoothManagerCallback;
-import android.bluetooth.IBluetoothStateChangeCallback;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Process;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.Log;
-class BluetoothManagerService extends IBluetoothManager.Stub {
- private static final String TAG = "BluetoothManagerService";
- private static final boolean DBG = true;
-
- private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
- private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
- private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
- private static final String EXTRA_ACTION="action";
- private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID="bluetooth_addr_valid";
- private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
- private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
- private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
- private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
- //Maximum msec to wait for service restart
- private static final int SERVICE_RESTART_TIME_MS = 200;
- //Maximum msec to wait for restart due to error
- private static final int ERROR_RESTART_TIME_MS = 3000;
- //Maximum msec to delay MESSAGE_USER_SWITCHED
- private static final int USER_SWITCHED_TIME_MS = 200;
-
- private static final int MESSAGE_ENABLE = 1;
- private static final int MESSAGE_DISABLE = 2;
- private static final int MESSAGE_REGISTER_ADAPTER = 20;
- private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
- private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
- private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
- private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
- private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
- private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
- private static final int MESSAGE_BLUETOOTH_STATE_CHANGE=60;
- private static final int MESSAGE_TIMEOUT_BIND =100;
- private static final int MESSAGE_TIMEOUT_UNBIND =101;
- private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
- private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
- private static final int MESSAGE_USER_SWITCHED = 300;
- private static final int MAX_SAVE_RETRIES=3;
- private static final int MAX_ERROR_RESTART_RETRIES=6;
-
- // Bluetooth persisted setting is off
- private static final int BLUETOOTH_OFF=0;
- // Bluetooth persisted setting is on
- // and Airplane mode won't affect Bluetooth state at start up
- private static final int BLUETOOTH_ON_BLUETOOTH=1;
- // Bluetooth persisted setting is on
- // but Airplane mode will affect Bluetooth state at start up
- // and Airplane mode will have higher priority.
- private static final int BLUETOOTH_ON_AIRPLANE=2;
-
- private static final int SERVICE_IBLUETOOTH = 1;
- private static final int SERVICE_IBLUETOOTHGATT = 2;
-
- private final Context mContext;
-
- // Locks are not provided for mName and mAddress.
- // They are accessed in handler or broadcast receiver, same thread context.
- private String mAddress;
- private String mName;
- private final ContentResolver mContentResolver;
- private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
- private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
- private IBluetooth mBluetooth;
- private IBluetoothGatt mBluetoothGatt;
- private boolean mBinding;
- private boolean mUnbinding;
- // used inside handler thread
- private boolean mQuietEnable = false;
- // configuarion from external IBinder call which is used to
- // synchronize with broadcast receiver.
- private boolean mQuietEnableExternal;
- // configuarion from external IBinder call which is used to
- // synchronize with broadcast receiver.
- private boolean mEnableExternal;
- // used inside handler thread
- private boolean mEnable;
- private int mState;
- private final BluetoothHandler mHandler;
- private int mErrorRecoveryRetryCounter;
-
- private void registerForAirplaneMode(IntentFilter filter) {
- final ContentResolver resolver = mContext.getContentResolver();
- final String airplaneModeRadios = Settings.Global.getString(resolver,
- Settings.Global.AIRPLANE_MODE_RADIOS);
- final String toggleableRadios = Settings.Global.getString(resolver,
- Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
- boolean mIsAirplaneSensitive = airplaneModeRadios == null ? true :
- airplaneModeRadios.contains(Settings.Global.RADIO_BLUETOOTH);
- if (mIsAirplaneSensitive) {
- filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- }
- }
-
- private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
- @Override
- public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
- Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE,prevState,newState);
- mHandler.sendMessage(msg);
- }
- };
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
- String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
- if (DBG) Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
- if (newName != null) {
- storeNameAndAddress(newName, null);
- }
- } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
- synchronized(mReceiver) {
- if (isBluetoothPersistedStateOn()) {
- if (isAirplaneModeOn()) {
- persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
- } else {
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- }
- }
- if (isAirplaneModeOn()) {
- // disable without persisting the setting
- sendDisableMsg();
- } else if (mEnableExternal) {
- // enable without persisting the setting
- sendEnableMsg(mQuietEnableExternal);
- }
- }
- } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_USER_SWITCHED,
- intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0));
- } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
- synchronized(mReceiver) {
- if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
- //Enable
- if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
- sendEnableMsg(mQuietEnableExternal);
- }
- }
-
- if (!isNameAndAddressSet()) {
- //Sync the Bluetooth name and address from the Bluetooth Adapter
- if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address...");
- getNameAndAddress();
- }
- }
- }
- };
-
- BluetoothManagerService(Context context) {
- mHandler = new BluetoothHandler(IoThread.get().getLooper());
-
- mContext = context;
- mBluetooth = null;
- mBinding = false;
- mUnbinding = false;
- mEnable = false;
- mState = BluetoothAdapter.STATE_OFF;
- mQuietEnableExternal = false;
- mEnableExternal = false;
- mAddress = null;
- mName = null;
- mErrorRecoveryRetryCounter = 0;
- mContentResolver = context.getContentResolver();
- mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
- mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
- IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
- filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- registerForAirplaneMode(filter);
- mContext.registerReceiver(mReceiver, filter);
- loadStoredNameAndAddress();
- if (isBluetoothPersistedStateOn()) {
- mEnableExternal = true;
- }
- }
-
- /**
- * Returns true if airplane mode is currently on
- */
- private final boolean isAirplaneModeOn() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
- }
-
- /**
- * Returns true if the Bluetooth saved state is "on"
- */
- private final boolean isBluetoothPersistedStateOn() {
- return Settings.Global.getInt(mContentResolver,
- Settings.Global.BLUETOOTH_ON, 0) != BLUETOOTH_OFF;
- }
-
- /**
- * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
- */
- private final boolean isBluetoothPersistedStateOnBluetooth() {
- return Settings.Global.getInt(mContentResolver,
- Settings.Global.BLUETOOTH_ON, 0) == BLUETOOTH_ON_BLUETOOTH;
- }
-
- /**
- * Save the Bluetooth on/off state
- *
- */
- private void persistBluetoothSetting(int value) {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.BLUETOOTH_ON,
- value);
- }
-
- /**
- * Returns true if the Bluetooth Adapter's name and address is
- * locally cached
- * @return
- */
- private boolean isNameAndAddressSet() {
- return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
- }
-
- /**
- * Retrieve the Bluetooth Adapter's name and address and save it in
- * in the local cache
- */
- private void loadStoredNameAndAddress() {
- if (DBG) Log.d(TAG, "Loading stored name and address");
- if (mContext.getResources().getBoolean
- (com.android.internal.R.bool.config_bluetooth_address_validation) &&
- Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
- // if the valid flag is not set, don't load the address and name
- if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
- return;
- }
- mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
- mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
- if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
- }
-
- /**
- * Save the Bluetooth name and address in the persistent store.
- * Only non-null values will be saved.
- * @param name
- * @param address
- */
- private void storeNameAndAddress(String name, String address) {
- if (name != null) {
- Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
- mName = name;
- if (DBG) Log.d(TAG,"Stored Bluetooth name: " +
- Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
- }
-
- if (address != null) {
- Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
- mAddress=address;
- if (DBG) Log.d(TAG,"Stored Bluetoothaddress: " +
- Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
- }
-
- if ((name != null) && (address != null)) {
- Settings.Secure.putInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1);
- }
- }
-
- public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
- Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
- msg.obj = callback;
- mHandler.sendMessage(msg);
- synchronized(mConnection) {
- return mBluetooth;
- }
- }
-
- public void unregisterAdapter(IBluetoothManagerCallback callback) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
- Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
- msg.obj = callback;
- mHandler.sendMessage(msg);
- }
-
- public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
- Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
- msg.obj = callback;
- mHandler.sendMessage(msg);
- }
-
- public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
- Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
- msg.obj = callback;
- mHandler.sendMessage(msg);
- }
-
- public boolean isEnabled() {
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"isEnabled(): not allowed for non-active and non system user");
- return false;
- }
-
- synchronized(mConnection) {
- try {
- return (mBluetooth != null && mBluetooth.isEnabled());
- } catch (RemoteException e) {
- Log.e(TAG, "isEnabled()", e);
- }
- }
- return false;
- }
-
- public void getNameAndAddress() {
- if (DBG) {
- Log.d(TAG,"getNameAndAddress(): mBluetooth = " + mBluetooth +
- " mBinding = " + mBinding);
- }
- Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(msg);
- }
- public boolean enableNoAutoConnect()
- {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
-
- if (DBG) {
- Log.d(TAG,"enableNoAutoConnect(): mBluetooth =" + mBluetooth +
- " mBinding = " + mBinding);
- }
- int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
-
- if (callingAppId != Process.NFC_UID) {
- throw new SecurityException("no permission to enable Bluetooth quietly");
- }
-
- synchronized(mReceiver) {
- mQuietEnableExternal = true;
- mEnableExternal = true;
- sendEnableMsg(true);
- }
- return true;
-
- }
- public boolean enable() {
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"enable(): not allowed for non-active and non system user");
- return false;
- }
-
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permission");
- if (DBG) {
- Log.d(TAG,"enable(): mBluetooth =" + mBluetooth +
- " mBinding = " + mBinding);
- }
-
- synchronized(mReceiver) {
- mQuietEnableExternal = false;
- mEnableExternal = true;
- // waive WRITE_SECURE_SETTINGS permission check
- long callingIdentity = Binder.clearCallingIdentity();
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- Binder.restoreCallingIdentity(callingIdentity);
- sendEnableMsg(false);
- }
- return true;
- }
-
- public boolean disable(boolean persist) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
- "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
-
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"disable(): not allowed for non-active and non system user");
- return false;
- }
-
- if (DBG) {
- Log.d(TAG,"disable(): mBluetooth = " + mBluetooth +
- " mBinding = " + mBinding);
- }
-
- synchronized(mReceiver) {
- if (persist) {
- // waive WRITE_SECURE_SETTINGS permission check
- long callingIdentity = Binder.clearCallingIdentity();
- persistBluetoothSetting(BLUETOOTH_OFF);
- Binder.restoreCallingIdentity(callingIdentity);
- }
- mEnableExternal = false;
- sendDisableMsg();
- }
- return true;
- }
-
- public void unbindAndFinish() {
- if (DBG) {
- Log.d(TAG,"unbindAndFinish(): " + mBluetooth +
- " mBinding = " + mBinding);
- }
-
- synchronized (mConnection) {
- if (mUnbinding) return;
- mUnbinding = true;
- if (mBluetooth != null) {
- if (!mConnection.isGetNameAddressOnly()) {
- //Unregister callback object
- try {
- mBluetooth.unregisterCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to unregister BluetoothCallback",re);
- }
- }
- if (DBG) Log.d(TAG, "Sending unbind request.");
- mBluetooth = null;
- //Unbind
- mContext.unbindService(mConnection);
- mUnbinding = false;
- mBinding = false;
- } else {
- mUnbinding=false;
- }
- }
- }
-
- public IBluetoothGatt getBluetoothGatt() {
- // sync protection
- return mBluetoothGatt;
- }
-
- private void sendBluetoothStateCallback(boolean isUp) {
- int n = mStateChangeCallbacks.beginBroadcast();
- if (DBG) Log.d(TAG,"Broadcasting onBluetoothStateChange("+isUp+") to " + n + " receivers.");
- for (int i=0; i <n;i++) {
- try {
- mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i , e);
- }
- }
- mStateChangeCallbacks.finishBroadcast();
- }
-
- /**
- * Inform BluetoothAdapter instances that Adapter service is up
- */
- private void sendBluetoothServiceUpCallback() {
- if (!mConnection.isGetNameAddressOnly()) {
- if (DBG) Log.d(TAG,"Calling onBluetoothServiceUp callbacks");
- int n = mCallbacks.beginBroadcast();
- Log.d(TAG,"Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
- for (int i=0; i <n;i++) {
- try {
- mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
- }
- }
- mCallbacks.finishBroadcast();
- }
- }
- /**
- * Inform BluetoothAdapter instances that Adapter service is down
- */
- private void sendBluetoothServiceDownCallback() {
- if (!mConnection.isGetNameAddressOnly()) {
- if (DBG) Log.d(TAG,"Calling onBluetoothServiceDown callbacks");
- int n = mCallbacks.beginBroadcast();
- Log.d(TAG,"Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
- for (int i=0; i <n;i++) {
- try {
- mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
- }
- }
- mCallbacks.finishBroadcast();
- }
- }
- public String getAddress() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
-
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"getAddress(): not allowed for non-active and non system user");
- return null;
- }
-
- synchronized(mConnection) {
- if (mBluetooth != null) {
- try {
- return mBluetooth.getAddress();
- } catch (RemoteException e) {
- Log.e(TAG, "getAddress(): Unable to retrieve address remotely..Returning cached address",e);
- }
- }
- }
- // mAddress is accessed from outside.
- // It is alright without a lock. Here, bluetooth is off, no other thread is
- // changing mAddress
- return mAddress;
- }
-
- public String getName() {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
- "Need BLUETOOTH permission");
-
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
- (!checkIfCallerIsForegroundUser())) {
- Log.w(TAG,"getName(): not allowed for non-active and non system user");
- return null;
- }
-
- synchronized(mConnection) {
- if (mBluetooth != null) {
- try {
- return mBluetooth.getName();
- } catch (RemoteException e) {
- Log.e(TAG, "getName(): Unable to retrieve name remotely..Returning cached name",e);
- }
- }
- }
- // mName is accessed from outside.
- // It alright without a lock. Here, bluetooth is off, no other thread is
- // changing mName
- return mName;
- }
-
- private class BluetoothServiceConnection implements ServiceConnection {
-
- private boolean mGetNameAddressOnly;
-
- public void setGetNameAddressOnly(boolean getOnly) {
- mGetNameAddressOnly = getOnly;
- }
-
- public boolean isGetNameAddressOnly() {
- return mGetNameAddressOnly;
- }
-
- public void onServiceConnected(ComponentName className, IBinder service) {
- if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
- Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
- // TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
- if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
- msg.arg1 = SERVICE_IBLUETOOTH;
- // } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
- } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
- msg.arg1 = SERVICE_IBLUETOOTHGATT;
- } else {
- Log.e(TAG, "Unknown service connected: " + className.getClassName());
- return;
- }
- msg.obj = service;
- mHandler.sendMessage(msg);
- }
-
- public void onServiceDisconnected(ComponentName className) {
- // Called if we unexpected disconnected.
- if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
- className.getClassName());
- Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
- if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
- msg.arg1 = SERVICE_IBLUETOOTH;
- } else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
- msg.arg1 = SERVICE_IBLUETOOTHGATT;
- } else {
- Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
- return;
- }
- mHandler.sendMessage(msg);
- }
- }
-
- private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
-
- private class BluetoothHandler extends Handler {
- public BluetoothHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (DBG) Log.d (TAG, "Message: " + msg.what);
- switch (msg.what) {
- case MESSAGE_GET_NAME_AND_ADDRESS: {
- if (DBG) Log.d(TAG,"MESSAGE_GET_NAME_AND_ADDRESS");
- synchronized(mConnection) {
- //Start bind request
- if ((mBluetooth == null) && (!mBinding)) {
- if (DBG) Log.d(TAG, "Binding to service to get name and address");
- mConnection.setGetNameAddressOnly(true);
- //Start bind timeout and bind
- Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
- mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
- Intent i = new Intent(IBluetooth.class.getName());
- if (!doBind(i, mConnection,
- Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
- } else {
- mBinding = true;
- }
- }
- else {
- Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
- saveMsg.arg1 = 0;
- if (mBluetooth != null) {
- mHandler.sendMessage(saveMsg);
- } else {
- // if enable is also called to bind the service
- // wait for MESSAGE_BLUETOOTH_SERVICE_CONNECTED
- mHandler.sendMessageDelayed(saveMsg, TIMEOUT_SAVE_MS);
- }
- }
- }
- break;
- }
- case MESSAGE_SAVE_NAME_AND_ADDRESS: {
- boolean unbind = false;
- if (DBG) Log.d(TAG,"MESSAGE_SAVE_NAME_AND_ADDRESS");
- synchronized(mConnection) {
- if (!mEnable && mBluetooth != null) {
- try {
- mBluetooth.enable();
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to call enable()",e);
- }
- }
- }
- if (mBluetooth != null) waitForOnOff(true, false);
- synchronized(mConnection) {
- if (mBluetooth != null) {
- String name = null;
- String address = null;
- try {
- name = mBluetooth.getName();
- address = mBluetooth.getAddress();
- } catch (RemoteException re) {
- Log.e(TAG,"",re);
- }
-
- if (name != null && address != null) {
- storeNameAndAddress(name,address);
- if (mConnection.isGetNameAddressOnly()) {
- unbind = true;
- }
- } else {
- if (msg.arg1 < MAX_SAVE_RETRIES) {
- Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
- retryMsg.arg1= 1+msg.arg1;
- if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
- mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
- } else {
- Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
- if (mConnection.isGetNameAddressOnly()) {
- unbind = true;
- }
- }
- }
- if (!mEnable) {
- try {
- mBluetooth.disable();
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to call disable()",e);
- }
- }
- } else {
- // rebind service by Request GET NAME AND ADDRESS
- // if service is unbinded by disable or
- // MESSAGE_BLUETOOTH_SERVICE_CONNECTED is not received
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- }
- }
- if (!mEnable && mBluetooth != null) waitForOnOff(false, true);
- if (unbind) {
- unbindAndFinish();
- }
- break;
- }
- case MESSAGE_ENABLE:
- if (DBG) {
- Log.d(TAG, "MESSAGE_ENABLE: mBluetooth = " + mBluetooth);
- }
- mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mEnable = true;
- handleEnable(msg.arg1 == 1);
- break;
-
- case MESSAGE_DISABLE:
- mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- if (mEnable && mBluetooth != null) {
- waitForOnOff(true, false);
- mEnable = false;
- handleDisable();
- waitForOnOff(false, false);
- } else {
- mEnable = false;
- handleDisable();
- }
- break;
-
- case MESSAGE_REGISTER_ADAPTER:
- {
- IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
- boolean added = mCallbacks.register(callback);
- Log.d(TAG,"Added callback: " + (callback == null? "null": callback) +":" +added );
- }
- break;
- case MESSAGE_UNREGISTER_ADAPTER:
- {
- IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
- boolean removed = mCallbacks.unregister(callback);
- Log.d(TAG,"Removed callback: " + (callback == null? "null": callback) +":" + removed);
- break;
- }
- case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
- {
- IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
- if (callback != null) {
- mStateChangeCallbacks.register(callback);
- }
- break;
- }
- case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
- {
- IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
- if (callback != null) {
- mStateChangeCallbacks.unregister(callback);
- }
- break;
- }
- case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
- {
- if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
-
- IBinder service = (IBinder) msg.obj;
- synchronized(mConnection) {
- if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
- mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
- break;
- } // else must be SERVICE_IBLUETOOTH
-
- //Remove timeout
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
-
- mBinding = false;
- mBluetooth = IBluetooth.Stub.asInterface(service);
-
- try {
- boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
- Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
- if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
- Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
- }
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to call configHciSnoopLog", e);
- }
-
- if (mConnection.isGetNameAddressOnly()) {
- //Request GET NAME AND ADDRESS
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- if (!mEnable) return;
- }
-
- mConnection.setGetNameAddressOnly(false);
- //Register callback object
- try {
- mBluetooth.registerCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to register BluetoothCallback",re);
- }
- //Inform BluetoothAdapter instances that service is up
- sendBluetoothServiceUpCallback();
-
- //Do enable request
- try {
- if (mQuietEnable == false) {
- if(!mBluetooth.enable()) {
- Log.e(TAG,"IBluetooth.enable() returned false");
- }
- }
- else
- {
- if(!mBluetooth.enableNoAutoConnect()) {
- Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to call enable()",e);
- }
- }
-
- if (!mEnable) {
- waitForOnOff(true, false);
- handleDisable();
- waitForOnOff(false, false);
- }
- break;
- }
- case MESSAGE_TIMEOUT_BIND: {
- Log.e(TAG, "MESSAGE_TIMEOUT_BIND");
- synchronized(mConnection) {
- mBinding = false;
- }
- break;
- }
- case MESSAGE_BLUETOOTH_STATE_CHANGE:
- {
- int prevState = msg.arg1;
- int newState = msg.arg2;
- if (DBG) Log.d(TAG, "MESSAGE_BLUETOOTH_STATE_CHANGE: prevState = " + prevState + ", newState=" + newState);
- mState = newState;
- bluetoothStateChangeHandler(prevState, newState);
- // handle error state transition case from TURNING_ON to OFF
- // unbind and rebind bluetooth service and enable bluetooth
- if ((prevState == BluetoothAdapter.STATE_TURNING_ON) &&
- (newState == BluetoothAdapter.STATE_OFF) &&
- (mBluetooth != null) && mEnable) {
- recoverBluetoothServiceFromError();
- }
- if (newState == BluetoothAdapter.STATE_ON) {
- // bluetooth is working, reset the counter
- if (mErrorRecoveryRetryCounter != 0) {
- Log.w(TAG, "bluetooth is recovered from error");
- mErrorRecoveryRetryCounter = 0;
- }
- }
- break;
- }
- case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
- {
- Log.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: " + msg.arg1);
- synchronized(mConnection) {
- if (msg.arg1 == SERVICE_IBLUETOOTH) {
- // if service is unbinded already, do nothing and return
- if (mBluetooth == null) break;
- mBluetooth = null;
- } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
- mBluetoothGatt = null;
- break;
- } else {
- Log.e(TAG, "Bad msg.arg1: " + msg.arg1);
- break;
- }
- }
-
- if (mEnable) {
- mEnable = false;
- // Send a Bluetooth Restart message
- Message restartMsg = mHandler.obtainMessage(
- MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg,
- SERVICE_RESTART_TIME_MS);
- }
-
- if (!mConnection.isGetNameAddressOnly()) {
- sendBluetoothServiceDownCallback();
-
- // Send BT state broadcast to update
- // the BT icon correctly
- if ((mState == BluetoothAdapter.STATE_TURNING_ON) ||
- (mState == BluetoothAdapter.STATE_ON)) {
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
- mState = BluetoothAdapter.STATE_TURNING_OFF;
- }
- if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_OFF);
- }
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
- }
- break;
- }
- case MESSAGE_RESTART_BLUETOOTH_SERVICE:
- {
- Log.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE:"
- +" Restart IBluetooth service");
- /* Enable without persisting the setting as
- it doesnt change when IBluetooth
- service restarts */
- mEnable = true;
- handleEnable(mQuietEnable);
- break;
- }
-
- case MESSAGE_TIMEOUT_UNBIND:
- {
- Log.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
- synchronized(mConnection) {
- mUnbinding = false;
- }
- break;
- }
-
- case MESSAGE_USER_SWITCHED:
- {
- if (DBG) {
- Log.d(TAG, "MESSAGE_USER_SWITCHED");
- }
- mHandler.removeMessages(MESSAGE_USER_SWITCHED);
- /* disable and enable BT when detect a user switch */
- if (mEnable && mBluetooth != null) {
- synchronized (mConnection) {
- if (mBluetooth != null) {
- //Unregister callback object
- try {
- mBluetooth.unregisterCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to unregister",re);
- }
- }
- }
-
- if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
- // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
- mState = BluetoothAdapter.STATE_OFF;
- }
- if (mState == BluetoothAdapter.STATE_OFF) {
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
- mState = BluetoothAdapter.STATE_TURNING_ON;
- }
-
- waitForOnOff(true, false);
-
- if (mState == BluetoothAdapter.STATE_TURNING_ON) {
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
- }
-
- // disable
- handleDisable();
- // Pbap service need receive STATE_TURNING_OFF intent to close
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
-
- waitForOnOff(false, true);
-
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_OFF);
- sendBluetoothServiceDownCallback();
- synchronized (mConnection) {
- if (mBluetooth != null) {
- mBluetooth = null;
- //Unbind
- mContext.unbindService(mConnection);
- }
- }
- SystemClock.sleep(100);
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
- // enable
- handleEnable(mQuietEnable);
- } else if (mBinding || mBluetooth != null) {
- Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
- userMsg.arg2 = 1 + msg.arg2;
- // if user is switched when service is being binding
- // delay sending MESSAGE_USER_SWITCHED
- mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
- if (DBG) {
- Log.d(TAG, "delay MESSAGE_USER_SWITCHED " + userMsg.arg2);
- }
- }
- break;
- }
- }
- }
- }
-
- private void handleEnable(boolean quietMode) {
- mQuietEnable = quietMode;
-
- synchronized(mConnection) {
- if ((mBluetooth == null) && (!mBinding)) {
- //Start bind timeout and bind
- Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
- mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
- mConnection.setGetNameAddressOnly(false);
- Intent i = new Intent(IBluetooth.class.getName());
- if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE, UserHandle.CURRENT)) {
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
- } else {
- mBinding = true;
- }
- } else if (mBluetooth != null) {
- if (mConnection.isGetNameAddressOnly()) {
- // if GetNameAddressOnly is set, we can clear this flag,
- // so the service won't be unbind
- // after name and address are saved
- mConnection.setGetNameAddressOnly(false);
- //Register callback object
- try {
- mBluetooth.registerCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to register BluetoothCallback",re);
- }
- //Inform BluetoothAdapter instances that service is up
- sendBluetoothServiceUpCallback();
- }
-
- //Enable bluetooth
- try {
- if (!mQuietEnable) {
- if(!mBluetooth.enable()) {
- Log.e(TAG,"IBluetooth.enable() returned false");
- }
- }
- else {
- if(!mBluetooth.enableNoAutoConnect()) {
- Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to call enable()",e);
- }
- }
- }
- }
-
- boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
- ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
- intent.setComponent(comp);
- if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
- Log.e(TAG, "Fail to bind to: " + intent);
- return false;
- }
- return true;
- }
-
- private void handleDisable() {
- synchronized(mConnection) {
- // don't need to disable if GetNameAddressOnly is set,
- // service will be unbinded after Name and Address are saved
- if ((mBluetooth != null) && (!mConnection.isGetNameAddressOnly())) {
- if (DBG) Log.d(TAG,"Sending off request.");
-
- try {
- if(!mBluetooth.disable()) {
- Log.e(TAG,"IBluetooth.disable() returned false");
- }
- } catch (RemoteException e) {
- Log.e(TAG,"Unable to call disable()",e);
- }
- }
- }
- }
-
- private boolean checkIfCallerIsForegroundUser() {
- int foregroundUser;
- int callingUser = UserHandle.getCallingUserId();
- int callingUid = Binder.getCallingUid();
- long callingIdentity = Binder.clearCallingIdentity();
- int callingAppId = UserHandle.getAppId(callingUid);
- boolean valid = false;
- try {
- foregroundUser = ActivityManager.getCurrentUser();
- valid = (callingUser == foregroundUser) ||
- callingAppId == Process.NFC_UID;
- if (DBG) {
- Log.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid
- + " callingUser=" + callingUser
- + " foregroundUser=" + foregroundUser);
- }
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- return valid;
- }
-
- private void bluetoothStateChangeHandler(int prevState, int newState) {
- if (prevState != newState) {
- //Notify all proxy objects first of adapter state change
- if (newState == BluetoothAdapter.STATE_ON || newState == BluetoothAdapter.STATE_OFF) {
- boolean isUp = (newState==BluetoothAdapter.STATE_ON);
- sendBluetoothStateCallback(isUp);
-
- if (isUp) {
- // connect to GattService
- if (mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_BLUETOOTH_LE)) {
- Intent i = new Intent(IBluetoothGatt.class.getName());
- doBind(i, mConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT);
- }
- } else {
- //If Bluetooth is off, send service down event to proxy objects, and unbind
- if (!isUp && canUnbindBluetoothService()) {
- sendBluetoothServiceDownCallback();
- unbindAndFinish();
- }
- }
- }
-
- //Send broadcast message to everyone else
- Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
- intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
- intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- if (DBG) Log.d(TAG,"Bluetooth State Change Intent: " + prevState + " -> " + newState);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
- BLUETOOTH_PERM);
- }
- }
-
- /**
- * if on is true, wait for state become ON
- * if off is true, wait for state become OFF
- * if both on and off are false, wait for state not ON
- */
- private boolean waitForOnOff(boolean on, boolean off) {
- int i = 0;
- while (i < 10) {
- synchronized(mConnection) {
- try {
- if (mBluetooth == null) break;
- if (on) {
- if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) return true;
- } else if (off) {
- if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) return true;
- } else {
- if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) return true;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "getState()", e);
- break;
- }
- }
- if (on || off) {
- SystemClock.sleep(300);
- } else {
- SystemClock.sleep(50);
- }
- i++;
- }
- Log.e(TAG,"waitForOnOff time out");
- return false;
- }
-
- private void sendDisableMsg() {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
- }
-
- private void sendEnableMsg(boolean quietMode) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,
- quietMode ? 1 : 0, 0));
- }
-
- private boolean canUnbindBluetoothService() {
- synchronized(mConnection) {
- //Only unbind with mEnable flag not set
- //For race condition: disable and enable back-to-back
- //Avoid unbind right after enable due to callback from disable
- //Only unbind with Bluetooth at OFF state
- //Only unbind without any MESSAGE_BLUETOOTH_STATE_CHANGE message
- try {
- if (mEnable || (mBluetooth == null)) return false;
- if (mHandler.hasMessages(MESSAGE_BLUETOOTH_STATE_CHANGE)) return false;
- return (mBluetooth.getState() == BluetoothAdapter.STATE_OFF);
- } catch (RemoteException e) {
- Log.e(TAG, "getState()", e);
- }
- }
- return false;
- }
-
- private void recoverBluetoothServiceFromError() {
- Log.e(TAG,"recoverBluetoothServiceFromError");
- synchronized (mConnection) {
- if (mBluetooth != null) {
- //Unregister callback object
- try {
- mBluetooth.unregisterCallback(mBluetoothCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "Unable to unregister",re);
- }
- }
- }
-
- SystemClock.sleep(500);
-
- // disable
- handleDisable();
-
- waitForOnOff(false, true);
-
- sendBluetoothServiceDownCallback();
- synchronized (mConnection) {
- if (mBluetooth != null) {
- mBluetooth = null;
- //Unbind
- mContext.unbindService(mConnection);
- }
- }
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
-
- mEnable = false;
-
- if (mErrorRecoveryRetryCounter++ < MAX_ERROR_RESTART_RETRIES) {
- // Send a Bluetooth Restart message to reenable bluetooth
- Message restartMsg = mHandler.obtainMessage(
- MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
- } else {
- // todo: notify user to power down and power up phone to make bluetooth work.
- }
- }
-}