Bluetooth Auto-connect per user, fix multidevice connections
When auto connecting to devices on bluetooth, store and try devices per
user. Added a CarUserService that is created for the current user on
UserSwitch. The CarUserService deals with scenarios where the
CarService, running as a System User, doesn't get to listen to events
from processes running as the current user.
Fix the issue where when 2 phones were connected on HFP, auto-connect
only connects to one.
Other cleanup and slight code re-org
Bug: b/35324581
Bug: b/37305537
Test: Manually tested by switching between different users and connecting
to multiple phones.
Change-Id: I53583bee9ed1ff1a6bfd20363d4544efd2cc152f
diff --git a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
index b000023..fe1e31e 100644
--- a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
+++ b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
@@ -16,6 +16,7 @@
package com.android.car;
+import android.app.ActivityManager;
import android.bluetooth.BluetoothA2dpSink;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -30,20 +31,24 @@
import android.car.hardware.cabin.CarCabinManager;
import android.car.hardware.property.CarPropertyEvent;
import android.car.hardware.property.ICarPropertyEventListener;
+import android.car.ICarBluetoothUserService;
+import android.car.ICarUserService;
+
+import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_AUTOCONNECT_MUSIC_DEVICES;
+import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_AUTOCONNECT_PHONE_DEVICES;
+import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_AUTOCONNECT_MESSAGING_DEVICES;
+
+import android.os.UserHandle;
+import android.provider.Settings;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.RemoteException;
-import android.util.AtomicFile;
import android.util.Log;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.lang.StringBuilder;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -51,21 +56,23 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
+
/**
* A Bluetooth Device Connection policy that is specific to the use cases of a Car. A car's
- * bluetooth capabilities in terms of the profiles it supports and its use cases are unique. Hence
- * the CarService manages the policy that drives when and what to connect to.
+ * bluetooth capabilities in terms of the profiles it supports and its use cases are unique.
+ * Hence the CarService manages the policy that drives when and what to connect to.
*
* When to connect:
- * The policy can be configured to listen to various vehicle events that are appropriate to trigger
- * a connection attempt. Signals like door unlock/open, ignition state changes indicate user entry
- * and there by attempt to connect to their devices. This removes the need for the user to manually
- * connect his device everytime they get in a car.
+ * The policy can be configured to listen to various vehicle events that are appropriate to
+ * trigger a connection attempt. Signals like door unlock/open, ignition state changes indicate
+ * user entry and there by attempt to connect to their devices. This removes the need for the user
+ * to manually connect his device everytime they get in a car.
*
* Which device to connect:
- * The policy also keeps track of the {Profile : DevicesThatCanConnectOnTheProfile} and when it is
- * time to connect, picks the device that is appropriate and available.
+ * The policy also keeps track of the {Profile : DevicesThatCanConnectOnTheProfile} and when
+ * it is time to connect, picks the device that is appropriate and available.
* For every profile, the policy attempts to connect to the last connected device first. The policy
* maintains a list of connect-able devices for every profile, in the order of how recently they
* connected. The device that successfully connects on a profile is moved to the top of the list
@@ -75,19 +82,30 @@
public class BluetoothDeviceConnectionPolicy {
private static final String TAG = "BTDevConnectionPolicy";
+ private static final String SETTINGS_DELIMITER = ",";
private static final boolean DBG = false;
- private Context mContext;
-
+ private final Context mContext;
private boolean mInitialized = false;
- // The main datastructure that holds on to the {profile:list of known and connectible devices}
+ // The main data structure that holds on to the {profile:list of known and connectible devices}
private HashMap<Integer, BluetoothDevicesInfo> mProfileToConnectableDevicesMap;
- // mProfileToConnectableDevicesInfo - holds information to serialize and write
- // to file, that can be used to rebuild the mProfileToConnectableDevicesMap on a reboot.
- private HashMap<Integer, List<String>> mProfileToConnectableDevicesInfo;
+
+ // The foll. number of connections are what the Bluetooth services and stack supports
+ // and has been tested with. MAP and A2DP are limited to one connection only. HFP and PBAP,
+ // though having the capability to support more than 2, has been tested with 2 connections.
+ private static final int NUM_SUPPORTED_PHONE_CONNECTIONS = 2; // num of HFP and PBAP connections
+ private static final int NUM_SUPPORTED_MSG_CONNECTIONS = 1; // num of MAP connections
+ private static final int NUM_SUPPORTED_MUSIC_CONNECTIONS = 1; // num of A2DP connections
+ private Map<Integer, Integer> mNumSupportedActiveConnections;
+
private BluetoothAutoConnectStateMachine mBluetoothAutoConnectStateMachine;
private final BluetoothAdapter mBluetoothAdapter;
- private BroadcastReceiver mReceiver;
+ private BroadcastReceiver mBluetoothBroadcastReceiver;
+
+ private ICarUserService mCarUserService;
+ private PerUserCarServiceHelper mUserServiceHelper;
+ private ICarBluetoothUserService mCarBluetoothUserService;
+ private ReentrantLock mCarUserServiceAccessLock;
// Events that are listened to for triggering an auto-connect:
// Cabin events like Door unlock coming from the Cabin Service.
@@ -97,40 +115,64 @@
private final CarSensorService mCarSensorService;
private final CarSensorEventListener mCarSensorEventListener;
- // Profile Proxies.
- private BluetoothHeadsetClient mBluetoothHeadsetClient;
- private BluetoothA2dpSink mBluetoothA2dpSink;
- private BluetoothPbapClient mBluetoothPbapClient;
- private BluetoothMapClient mBluetoothMapClient;
+ // PerUserCarService related listeners
+ private final UserServiceConnectionCallback mServiceCallback;
- // The Bluetooth profiles that the CarService will try to autoconnect on.
+ // The Bluetooth profiles that the CarService will try to auto-connect on.
private final List<Integer> mProfilesToConnect;
private static final int MAX_CONNECT_RETRIES = 1;
- // File to write connectable devices for a profile information
- private static final String DEVICE_INFO_FILE = "BluetoothDevicesInfo.map";
private static final int PROFILE_NOT_AVAILABLE = -1;
// Device & Profile currently being connected on
private ConnectionParams mConnectionInFlight;
public static BluetoothDeviceConnectionPolicy create(Context context,
- CarCabinService carCabinService, CarSensorService carSensorService) {
- return new BluetoothDeviceConnectionPolicy(context, carCabinService, carSensorService);
+ CarCabinService carCabinService, CarSensorService carSensorService,
+ PerUserCarServiceHelper userServiceHelper) {
+ return new BluetoothDeviceConnectionPolicy(context, carCabinService, carSensorService,
+ userServiceHelper);
}
private BluetoothDeviceConnectionPolicy(Context context, CarCabinService carCabinService,
- CarSensorService carSensorService) {
+ CarSensorService carSensorService, PerUserCarServiceHelper userServiceHelper) {
mContext = context;
mCarCabinService = carCabinService;
mCarSensorService = carSensorService;
+ mUserServiceHelper = userServiceHelper;
+ mCarUserServiceAccessLock = new ReentrantLock();
mProfilesToConnect = Arrays.asList(
- BluetoothProfile.HEADSET_CLIENT,
- BluetoothProfile.PBAP_CLIENT,
- BluetoothProfile.A2DP_SINK,
- BluetoothProfile.MAP_CLIENT);
+ BluetoothProfile.HEADSET_CLIENT, BluetoothProfile.A2DP_SINK,
+ BluetoothProfile.PBAP_CLIENT, BluetoothProfile.MAP_CLIENT);
+ // mNumSupportedActiveConnections is a HashMap of mProfilesToConnect and the number of
+ // connections each profile supports currently.
+ mNumSupportedActiveConnections = new HashMap<>(mProfilesToConnect.size());
+ for (Integer profile: mProfilesToConnect) {
+ switch (profile) {
+ case BluetoothProfile.HEADSET_CLIENT:
+ mNumSupportedActiveConnections.put(BluetoothProfile.HEADSET_CLIENT,
+ NUM_SUPPORTED_PHONE_CONNECTIONS);
+ break;
+ case BluetoothProfile.PBAP_CLIENT:
+ mNumSupportedActiveConnections.put(BluetoothProfile.PBAP_CLIENT,
+ NUM_SUPPORTED_PHONE_CONNECTIONS);
+ break;
+ case BluetoothProfile.A2DP_SINK:
+ mNumSupportedActiveConnections.put(BluetoothProfile.A2DP_SINK,
+ NUM_SUPPORTED_MUSIC_CONNECTIONS);
+ break;
+ case BluetoothProfile.MAP_CLIENT:
+ mNumSupportedActiveConnections.put(BluetoothProfile.MAP_CLIENT,
+ NUM_SUPPORTED_MSG_CONNECTIONS);
+ break;
+ }
+ }
+
+ // Listen to Cabin events for triggering auto connect
mCabinEventListener = new CarPropertyListener();
mCarSensorEventListener = new CarSensorEventListener();
+ // Listen to User switching to connect to per User device.
+ mServiceCallback = new UserServiceConnectionCallback();
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
Log.w(TAG, "No Bluetooth Adapter Available");
@@ -156,7 +198,7 @@
mBluetoothProfile = profile;
}
- public ConnectionParams(BluetoothDevice device, Integer profile) {
+ public ConnectionParams(Integer profile, BluetoothDevice device) {
mBluetoothProfile = profile;
mBluetoothDevice = device;
}
@@ -190,10 +232,14 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (DBG) {
- Log.d(TAG, "Received Intent " + action);
- }
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (DBG) {
+ if (device != null) {
+ Log.d(TAG, "Received Intent for device: " + device.getName() + action);
+ } else {
+ Log.d(TAG, "Received Intent no device: " + action);
+ }
+ }
ConnectionParams connectParams;
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(action)) {
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
@@ -201,43 +247,42 @@
updateBondState(device, bondState);
} else if (BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
- connectParams = new ConnectionParams(device, BluetoothProfile.A2DP_SINK);
+ connectParams = new ConnectionParams(BluetoothProfile.A2DP_SINK, device);
int currState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
notifyConnectionStatus(connectParams, currState);
} else if (BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
- connectParams = new ConnectionParams(device, BluetoothProfile.HEADSET_CLIENT);
+ connectParams = new ConnectionParams(BluetoothProfile.HEADSET_CLIENT, device);
int currState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
notifyConnectionStatus(connectParams, currState);
} else if (BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
- connectParams = new ConnectionParams(device, BluetoothProfile.PBAP_CLIENT);
+ connectParams = new ConnectionParams(BluetoothProfile.PBAP_CLIENT, device);
int currState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
notifyConnectionStatus(connectParams, currState);
} else if (BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
- connectParams = new ConnectionParams(device, BluetoothProfile.MAP_CLIENT);
+ connectParams = new ConnectionParams(BluetoothProfile.MAP_CLIENT, device);
int currState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
BluetoothProfile.STATE_DISCONNECTED);
notifyConnectionStatus(connectParams, currState);
} else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
- int currState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
- -1);
+ int currState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
if (DBG) {
Log.d(TAG, "Bluetooth Adapter State: " + currState);
}
if (currState == BluetoothAdapter.STATE_ON) {
- // Initialize and populate (from file if available) the
+ // Read from Settings which devices to connect to and populate
// mProfileToConnectableDevicesMap
- rebuildDeviceMapFromDeviceInfoLocked();
+ readAndRebuildDeviceMapFromSettings();
initiateConnection();
} else if (currState == BluetoothAdapter.STATE_OFF) {
// Write currently connected device snapshot to file.
- writeDeviceInfoToFile();
+ writeDeviceInfoToSettings();
resetBluetoothDevicesConnectionInfo();
}
}
@@ -245,6 +290,94 @@
}
/**
+ * Cleanup state and reinitialize whenever we connect to the PerUserCarService.
+ * This happens in init() and whenever the PerUserCarService is restarted on User Switch Events
+ */
+ private class UserServiceConnectionCallback implements PerUserCarServiceHelper.ServiceCallback {
+ @Override
+ public void onServiceConnected(ICarUserService carUserService) {
+ if (mCarUserServiceAccessLock != null) {
+ mCarUserServiceAccessLock.lock();
+ try {
+ mCarUserService = carUserService;
+ } finally {
+ mCarUserServiceAccessLock.unlock();
+ }
+ }
+ if (DBG) {
+ Log.d(TAG, "Connected to PerUserCarService");
+ }
+ // Clean up information related to user who went background.
+ cleanupUserSpecificInfo();
+ // re-initialize for current user.
+ initializeUserSpecificInfo();
+ }
+
+ @Override
+ public void onPreUnbind() {
+ if (DBG) {
+ Log.d(TAG, "Before Unbinding from UserService");
+ }
+ try {
+ if (mCarBluetoothUserService != null) {
+ mCarBluetoothUserService.closeBluetoothConnectionProxy();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG,
+ "Remote Exception during closeBluetoothConnectionProxy(): " + e.getMessage());
+ }
+
+ }
+ @Override
+ public void onServiceDisconnected() {
+ if (DBG) {
+ Log.d(TAG, "Disconnected from PerUserCarService");
+ }
+ if (mCarUserServiceAccessLock != null) {
+ mCarUserServiceAccessLock.lock();
+ try {
+ mCarBluetoothUserService = null;
+ mCarUserService = null;
+ } finally {
+ mCarUserServiceAccessLock.unlock();
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the Per User Car Bluetooth Service (ICarBluetoothService) from the PerUserCarService
+ * which acts as a top level Service running in the current user context.
+ * Also sets up the connection proxy objects required to communicate with the Bluetooth
+ * Profile Services.
+ * @return ICarBluetoothUserService running in current user
+ */
+ private ICarBluetoothUserService setupBluetoothUserService() {
+ ICarBluetoothUserService carBluetoothUserService = null;
+
+ if (mCarUserService != null) {
+ try {
+ carBluetoothUserService = mCarUserService.getBluetoothUserService();
+ if (carBluetoothUserService != null) {
+ if (DBG) {
+ Log.d(TAG, "Got CarBTUsrSvc");
+ }
+ carBluetoothUserService.setupBluetoothConnectionProxy();
+ }
+
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote Service Exception on ServiceConnection Callback: "
+ + e.getMessage());
+ }
+ } else {
+ if (DBG) {
+ Log.d(TAG, "PerUserCarService not connected");
+ }
+ }
+ return carBluetoothUserService;
+ }
+
+ /**
* Setup the Bluetooth profile service connections and Vehicle Event listeners.
* and start the state machine -{@link BluetoothAutoConnectStateMachine}
*/
@@ -252,31 +385,42 @@
if (DBG) {
Log.d(TAG, "init()");
}
- initDeviceMap();
// Register for various intents from the Bluetooth service.
- mReceiver = new BluetoothBroadcastReceiver();
- // Create a new ConnectionParams object to keep track of device & profile that are being
- // connected to.
- mConnectionInFlight = new ConnectionParams();
- setupIntentFilter();
- // Make connections to Profile Services.
- setupProfileProxy();
- mBluetoothAutoConnectStateMachine = BluetoothAutoConnectStateMachine.make(this);
+ mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
+ // Initialize information specific to current user.
+ initializeUserSpecificInfo();
// Listen to various events coming from the vehicle.
- setupEventListeners();
-
+ setupEventListenersLocked();
mInitialized = true;
}
/**
- * Setting up the intent filter to the connection and bonding state changes we are interested
- * in.
+ * Setup and initialize information that is specific per User account, which involves:
+ * 1. Reading the list of devices to connect for current user and initialize the deviceMap
+ * with that information.
+ * 2. Register a BroadcastReceiver for bluetooth related events for the current user.
+ * 3. Start and bind to {@link PerUserCarService} as current user.
+ * 4. Start the {@link BluetoothAutoConnectStateMachine}
+ */
+ private synchronized void initializeUserSpecificInfo() {
+ readAndRebuildDeviceMapFromSettings();
+ setupBluetoothEventsIntentFilter();
+
+ mBluetoothAutoConnectStateMachine = BluetoothAutoConnectStateMachine.make(this);
+ mConnectionInFlight = new ConnectionParams();
+ // Get the BluetoothUserService and also setup the Bluetooth Connection Proxy for
+ // all profiles.
+ mCarBluetoothUserService = setupBluetoothUserService();
+ }
+
+ /**
+ * Setting up the Intent filter for Bluetooth related broadcasts
* This includes knowing when the
* 1. Bluetooth Adapter turned on/off
* 2. Bonding State of a device changes
* 3. A specific profile's connection state changes.
*/
- private void setupIntentFilter() {
+ private void setupBluetoothEventsIntentFilter() {
IntentFilter profileFilter = new IntentFilter();
profileFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
profileFilter.addAction(BluetoothA2dpSink.ACTION_CONNECTION_STATE_CHANGED);
@@ -284,10 +428,8 @@
profileFilter.addAction(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
profileFilter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
profileFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
- mContext.registerReceiver(mReceiver, profileFilter);
- if (DBG) {
- Log.d(TAG, "Intent Receiver Registered");
- }
+ mContext.registerReceiverAsUser(mBluetoothBroadcastReceiver, UserHandle.CURRENT,
+ profileFilter, null, null);
}
/**
@@ -296,44 +438,33 @@
* method retrieves it from persistent memory.
*/
private synchronized void initDeviceMap() {
- boolean result = readDeviceInfoFromFile();
- if (!result && mProfileToConnectableDevicesMap == null) {
+ if (mProfileToConnectableDevicesMap == null) {
mProfileToConnectableDevicesMap = new HashMap<>();
for (Integer profile : mProfilesToConnect) {
- mProfileToConnectableDevicesMap.put(profile, new BluetoothDevicesInfo(profile));
+ // Build the BluetoothDevicesInfo for this profile.
+ BluetoothDevicesInfo devicesInfo = new BluetoothDevicesInfo(profile,
+ mNumSupportedActiveConnections.get(profile));
+ mProfileToConnectableDevicesMap.put(profile, devicesInfo);
}
if (DBG) {
- Log.d(TAG, "new Device Map created");
+ Log.d(TAG, "Created a new empty Device Map");
}
}
}
/**
- * Setup connections to the profile proxy object to talk to the Bluetooth profile services
- */
- private void setupProfileProxy() {
- if (DBG) {
- Log.d(TAG, "setupProfileProxy()");
- }
- if (mBluetoothAdapter == null) {
- return;
- }
- for (Integer profile : mProfilesToConnect) {
- mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, profile);
- }
- }
-
- /**
* Setting up Listeners to the various events we are interested in listening to for initiating
* Bluetooth connection attempts.
*/
- private void setupEventListeners() {
+ private void setupEventListenersLocked() {
// Setting up a listener for events from CarCabinService
// For now, we listen to door unlock signal coming from {@link CarCabinService},
// and Ignition state START from {@link CarSensorService}
mCarCabinService.registerListener(mCabinEventListener);
mCarSensorService.registerOrUpdateSensorListener(
CarSensorManager.SENSOR_TYPE_IGNITION_STATE, 0, mCarSensorEventListener);
+
+ mUserServiceHelper.registerServiceCallback(mServiceCallback);
}
/**
@@ -373,11 +504,10 @@
* Upon receiving the event that is of interest, initiate a connection attempt by calling
* the policy {@link BluetoothDeviceConnectionPolicy}
*/
-
private class CarSensorEventListener extends ICarSensorEventListener.Stub {
@Override
public void onSensorChanged(List<CarSensorEvent> events) throws RemoteException {
- if (events != null && !events.isEmpty()) {
+ if (events != null & !events.isEmpty()) {
CarSensorEvent event = events.get(0);
if (DBG) {
Log.d(TAG, "Sensor event Type : " + event.sensorType);
@@ -403,14 +533,20 @@
Log.d(TAG, "release()");
}
mInitialized = false;
-
- writeDeviceInfoToFile();
+ writeDeviceInfoToSettings();
+ cleanupUserSpecificInfo();
closeEventListeners();
- // Closing the connections to the Profile Services
- closeProfileProxy();
- mConnectionInFlight = null;
+ }
+
+ /**
+ * Clean up information related to user who went background.
+ */
+ private synchronized void cleanupUserSpecificInfo() {
// quit the state machine
mBluetoothAutoConnectStateMachine.doQuit();
+ mProfileToConnectableDevicesMap = null;
+ mConnectionInFlight = null;
+ mContext.unregisterReceiver(mBluetoothBroadcastReceiver);
}
/**
@@ -418,27 +554,10 @@
* CarService
*/
private void closeEventListeners() {
- // b/34723490 - Need to add more events other than the Cabin Event.
if (mCabinEventListener != null) {
mCarCabinService.unregisterListener(mCabinEventListener);
}
- }
-
- /**
- * Close connections to the profile proxy object
- */
- private void closeProfileProxy() {
- if (mBluetoothAdapter == null) {
- return;
- }
- if (DBG) {
- Log.d(TAG, "closeProfileProxy()");
- }
- mBluetoothAdapter.closeProfileProxy(BluetoothProfile.A2DP_SINK, mBluetoothA2dpSink);
- mBluetoothAdapter.closeProfileProxy(BluetoothProfile.HEADSET_CLIENT,
- mBluetoothHeadsetClient);
- mBluetoothAdapter.closeProfileProxy(BluetoothProfile.PBAP_CLIENT, mBluetoothPbapClient);
- mBluetoothAdapter.closeProfileProxy(BluetoothProfile.MAP_CLIENT, mBluetoothMapClient);
+ mUserServiceHelper.unregisterServiceCallback(mServiceCallback);
}
/**
@@ -446,7 +565,7 @@
* a clean slate. The ConnectionInfo has all the book keeping information regarding the state
* of connection attempts - like which device in the device list for the profile is the next
* to try connecting etc.
- * This method does not clear the {@link BluetoothDevicesInfo#mDeviceList} like the {@link
+ * This method does not clear the {@link BluetoothDevicesInfo#mDeviceInfoList} like the {@link
* #resetProfileToConnectableDevicesMap()} method does.
*/
private synchronized void resetBluetoothDevicesConnectionInfo() {
@@ -556,20 +675,16 @@
if (mBluetoothAdapter.isEnabled()) {
if (isDeviceMapEmpty()) {
if (DBG) {
- Log.d(TAG, "Device Map is empty. Querying bonded devices");
+ Log.d(TAG, "Device Map is empty. Nothing to connect to");
}
- if (populateDeviceMapFromBondedDevices() == false) {
- if (DBG) {
- Log.d(TAG, "No bonded devices");
- }
- return;
- }
+ return;
}
resetDeviceAvailableToConnect();
if (DBG) {
Log.d(TAG, "initiateConnection() Reset Device Availability");
}
- mBluetoothAutoConnectStateMachine.sendMessage(BluetoothAutoConnectStateMachine.CONNECT);
+ mBluetoothAutoConnectStateMachine.sendMessage(BluetoothAutoConnectStateMachine
+ .CONNECT);
} else {
if (DBG) {
Log.d(TAG, "Bluetooth Adapter not enabled.");
@@ -578,40 +693,6 @@
}
/**
- * If, for some reason, the {@link #mProfileToConnectableDevicesMap} is empty, query the
- * Bluetooth stack
- * for the list of bonded devices and use it to populate the {@link
- * #mProfileToConnectableDevicesMap}.
- *
- * @return true if devices were added
- * false if the bonded device list is also empty.
- */
- private synchronized boolean populateDeviceMapFromBondedDevices() {
- if (mBluetoothAdapter == null) {
- return false;
- }
- Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
- if (bondedDevices == null || bondedDevices.isEmpty()) {
- if (DBG) {
- Log.d(TAG, "populateDeviceMapFromBondedDevices() - No bonded devices");
- }
- return false;
- }
-
- for (BluetoothDevice bd : bondedDevices) {
- for (Integer profile : mProfilesToConnect) {
- if (bd != null) {
- if (DBG) {
- Log.d(TAG, "Adding device: " + bd.getName() + " profile: " + profile);
- }
- mProfileToConnectableDevicesMap.get(profile).addDeviceLocked(bd);
- }
- }
- }
- return true;
- }
-
- /**
* Find an unconnected profile and find a device to connect on it.
* Finds the appropriate device for the profile from the information available in
* {@link #mProfileToConnectableDevicesMap}
@@ -622,9 +703,16 @@
public synchronized boolean findDeviceToConnect() {
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()
|| mProfileToConnectableDevicesMap == null || !mInitialized) {
+ if (DBG) {
+ if (mProfileToConnectableDevicesMap == null) {
+ Log.d(TAG, "findDeviceToConnect(): Device Map null");
+ } else {
+ Log.d(TAG, "findDeviceToConnect(): BT Adapter not enabled");
+ }
+ }
return false;
}
- boolean deviceFound = false;
+ boolean connectingToADevice = false;
// Get the first unconnected profile that we can try to make a connection
Integer nextProfile = getNextProfileToConnectLocked();
// Keep going through the profiles until we find a device that we can connect to
@@ -633,16 +721,17 @@
Log.d(TAG, "connectToProfile(): " + nextProfile);
}
// find a device that is next in line for a connection attempt for that profile
- deviceFound = tryNextDeviceInQueueLocked(nextProfile);
+ // and try connecting to it.
+ connectingToADevice = connectToNextDeviceInQueueLocked(nextProfile);
// If we found a device to connect, break out of the loop
- if (deviceFound) {
+ if (connectingToADevice) {
if (DBG) {
Log.d(TAG, "Found device to connect to");
}
BluetoothDeviceConnectionPolicy.ConnectionParams btParams =
new BluetoothDeviceConnectionPolicy.ConnectionParams(
- mConnectionInFlight.getBluetoothDevice(),
- mConnectionInFlight.getBluetoothProfile());
+ mConnectionInFlight.getBluetoothProfile(),
+ mConnectionInFlight.getBluetoothDevice());
// set up a time out
mBluetoothAutoConnectStateMachine.sendMessageDelayed(
BluetoothAutoConnectStateMachine.CONNECT_TIMEOUT, btParams,
@@ -658,7 +747,7 @@
nextProfile = getNextProfileToConnectLocked();
}
}
- return deviceFound;
+ return connectingToADevice;
}
/**
@@ -673,8 +762,7 @@
for (Integer profile : mProfilesToConnect) {
BluetoothDevicesInfo devInfo = mProfileToConnectableDevicesMap.get(profile);
if (devInfo != null) {
- if (devInfo.isConnectedLocked() == false
- && devInfo.isDeviceAvailableToConnectLocked() == true) {
+ if (devInfo.isProfileConnectableLocked()) {
return profile;
}
} else {
@@ -682,6 +770,9 @@
}
}
// Reaching here denotes all profiles are connected or No devices available for any profile
+ if (DBG) {
+ Log.d(TAG, "No disconnected profiles");
+ }
return PROFILE_NOT_AVAILABLE;
}
@@ -692,110 +783,85 @@
* @return - true if we found a device to connect on for this profile
* false - if we cannot find a device to connect to.
*/
-
- private boolean tryNextDeviceInQueueLocked(Integer profile) {
+ private boolean connectToNextDeviceInQueueLocked(Integer profile) {
// Get the Device Information for the given profile and find the next device to connect on
- boolean deviceAvailable = true;
+ boolean connecting = true;
+ boolean proxyAvailable = true;
+ BluetoothDevice devToConnect = null;
BluetoothDevicesInfo devInfo = mProfileToConnectableDevicesMap.get(profile);
if (devInfo == null) {
Log.e(TAG, "Unexpected: No device Queue for this profile: " + profile);
return false;
}
- BluetoothDevice devToConnect = devInfo.getNextDeviceInQueueLocked();
- if (devToConnect != null) {
- switch (profile) {
- case BluetoothProfile.A2DP_SINK:
- if (mBluetoothA2dpSink != null) {
- if (DBG) {
- Log.d(TAG,
- "Connecting device " + devToConnect.getName() + " on A2DPSink");
- }
- mBluetoothA2dpSink.connect(devToConnect);
- } else {
- if (DBG) {
- Log.d(TAG, "Unexpected: BluetoothA2dpSink Profile proxy null");
- }
- deviceAvailable = false;
- }
- break;
-
- case BluetoothProfile.HEADSET_CLIENT:
- if (mBluetoothHeadsetClient != null) {
- if (DBG) {
- Log.d(TAG, "Connecting device " + devToConnect.getName()
- + " on HeadSetClient");
- }
- mBluetoothHeadsetClient.connect(devToConnect);
- } else {
- if (DBG) {
- Log.d(TAG, "Unexpected: BluetoothHeadsetClient Profile proxy null");
- }
- deviceAvailable = false;
- }
- break;
-
- case BluetoothProfile.PBAP_CLIENT:
- if (mBluetoothPbapClient != null) {
- if (DBG) {
- Log.d(TAG, "Connecting device " + devToConnect.getName()
- + " on PbapClient");
- }
- mBluetoothPbapClient.connect(devToConnect);
- } else {
- if (DBG) {
- Log.d(TAG, "Unexpected: BluetoothPbapClient Profile proxy null");
- }
- deviceAvailable = false;
- }
- break;
-
- case BluetoothProfile.MAP_CLIENT:
- if (mBluetoothMapClient != null) {
- if (DBG) {
- Log.d(TAG, "Connecting device " + devToConnect.getName()
- + " on MAPClient");
- }
- mBluetoothMapClient.connect(devToConnect);
- } else {
- if (DBG) {
- Log.d(TAG, "Unexpected: BluetoothMAPClient Profile proxy null");
- }
- deviceAvailable = false;
- }
- break;
-
- default:
+ // Check if the Bluetooth profile service's proxy object is available before
+ // attempting to connect.
+ if (mCarBluetoothUserService == null) {
+ mCarBluetoothUserService = setupBluetoothUserService();
+ }
+ if (mCarBluetoothUserService != null) {
+ try {
+ if (!mCarBluetoothUserService.isBluetoothConnectionProxyAvailable(profile)) {
+ // proxy unavailable.
if (DBG) {
- Log.d(TAG, "Unsupported Bluetooth profile being tried for connection: "
- + profile);
+ Log.d(TAG,
+ "Proxy for Bluetooth Profile Service Unavailable: " + profile);
}
- break;
- }
- // Increment the retry count & cache what is being connected to
- if (deviceAvailable) {
- // This method is already called from a synchronized context.
- mConnectionInFlight.setBluetoothDevice(devToConnect);
- mConnectionInFlight.setBluetoothProfile(profile);
- devInfo.incrementRetryCountLocked();
- if (DBG) {
- Log.d(TAG, "Increment Retry to: " + devInfo.getRetryCountLocked());
+ proxyAvailable = false;
}
- } else {
- if (DBG) {
- Log.d(TAG, "Not incrementing retry.");
- }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Car BT Service Remote Exception.");
+ proxyAvailable = false;
}
} else {
- if (DBG) {
- Log.d(TAG, "No paired nearby device to connect to for profile: " + profile);
+ Log.d(TAG, "CarBluetoothUserSvc null. Car service not bound to PerUserCarSvc.");
+ proxyAvailable = false;
+ }
+
+ if (proxyAvailable) {
+ // Get the next device in the device list for this profile.
+ devToConnect = devInfo.getNextDeviceInQueueLocked();
+ if (devToConnect != null) {
+ // deviceAvailable && proxyAvailable
+ try {
+ if (mCarBluetoothUserService != null) {
+ mCarBluetoothUserService.bluetoothConnectToProfile((int) profile,
+ devToConnect);
+ } else {
+ Log.e(TAG, "CarBluetoothUserSvc null");
+ connecting = false;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Remote User Service stopped responding: " + e.getMessage());
+ connecting = false;
+ }
+ } else {
+ // device unavailable
+ if (DBG) {
+ Log.d(TAG, "No paired nearby device to connect to for profile: " + profile);
+ }
+ connecting = false;
}
+ } else {
+ connecting = false;
+ }
+
+ if (connecting && devToConnect != null) {
+ devInfo.setConnectionStateLocked(devToConnect, BluetoothProfile.STATE_CONNECTING);
+ // Increment the retry count & cache what is being connected to
+ // This method is already called from a synchronized context.
+ mConnectionInFlight.setBluetoothDevice(devToConnect);
+ mConnectionInFlight.setBluetoothProfile(profile);
+ devInfo.incrementRetryCountLocked();
+ if (DBG) {
+ Log.d(TAG, "Increment Retry to: " + devInfo.getRetryCountLocked());
+ }
+ } else {
// reset the mConnectionInFlight
mConnectionInFlight.setBluetoothProfile(0);
mConnectionInFlight.setBluetoothDevice(null);
devInfo.setDeviceAvailableToConnectLocked(false);
- deviceAvailable = false;
}
- return deviceAvailable;
+ return connecting;
}
/**
@@ -879,8 +945,9 @@
if (mConnectionInFlight != null && mConnectionInFlight.getBluetoothDevice() != null) {
if (deviceThatConnected.equals(mConnectionInFlight.getBluetoothDevice()) == false) {
- Log.d(TAG, "Connected device " + deviceThatConnected.getName()
- + " different from connection in flight");
+ Log.d(TAG, "Updating device: " + deviceThatConnected.getName()
+ + " different from connection in flight: "
+ + mConnectionInFlight.getBluetoothDevice().getName());
}
}
@@ -900,7 +967,7 @@
}
devInfo.updateConnectionStatusLocked(deviceThatConnected, didConnect, retry);
// Write to persistent memory to have the latest snapshot available
- writeDeviceInfoToFile();
+ writeDeviceInfoToSettings(params);
return true;
}
@@ -975,162 +1042,130 @@
if (mProfileToConnectableDevicesMap == null) {
return;
}
- writer.println("Bluetooth Profile -> Connectable Device List ");
for (BluetoothDevicesInfo devInfo : mProfileToConnectableDevicesMap.values()) {
- writer.println("Profile: " + devInfo.getProfileLocked() + "\t");
- writer.print("Connected: " + devInfo.isConnectedLocked() +
- "\t Device Available: " + devInfo.isDeviceAvailableToConnectLocked());
+ writer.print("Profile: " + devInfo.getProfileLocked() + "\t");
+ writer.print("Active Connections: " + devInfo.getNumberOfActiveConnectionsLocked());
writer.println();
- writer.println("Device List:");
- List<BluetoothDevice> deviceList = devInfo.getDeviceList();
- if (deviceList != null) {
- for (BluetoothDevice device : deviceList) {
- writer.print(device.getName() + "\t");
+ List<BluetoothDevicesInfo.DeviceInfo> deviceInfoList = devInfo.getDeviceInfoList();
+ if (deviceInfoList != null) {
+ for (BluetoothDevicesInfo.DeviceInfo devicesInfo : deviceInfoList) {
+ if (devicesInfo.getBluetoothDevice() != null) {
+ writer.print(devicesInfo.getBluetoothDevice().getName() + ":");
+ writer.print(devicesInfo.getConnectionState() + "\t");
+ }
}
+ writer.println();
}
}
}
/**
- * Utility function - could be called from a adb shell dump command to dump the
- * {@link #mProfileToConnectableDevicesInfo}
- *
- * @param writer - PrintWriter
- */
- public synchronized void printDeviceInfo(PrintWriter writer) {
- if (mProfileToConnectableDevicesInfo == null) {
- Log.d(TAG, "mProfileToConnectableDevicesInfo null");
- return;
- }
- writer.println("Bluetooth Profile -> device Info");
- for (Map.Entry<Integer, List<String>> entry : mProfileToConnectableDevicesInfo.entrySet()) {
- writer.println("Profile: " + entry.getKey());
- for (String devname : entry.getValue()) {
- writer.print(devname + "\t");
- }
- writer.println();
- }
- }
-
- /**
- * Write information about which devices connected on which profile to persistent memory.
- * Essentially the list of devices that a profile can connect on the next auto-connect
- * attempt.
+ * Write the device list for all bluetooth profiles that connected.
*
* @return true if the write was successful, false otherwise
*/
- public synchronized boolean writeDeviceInfoToFile() {
+ private synchronized boolean writeDeviceInfoToSettings() {
+ ConnectionParams params;
+ boolean writeResult;
+ for (Integer profile : mProfilesToConnect) {
+ params = new ConnectionParams(profile);
+ writeResult = writeDeviceInfoToSettings(params);
+ if (!writeResult) {
+ Log.e(TAG, "Error writing Device Info for profile:" + profile);
+ return writeResult;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Write information about which devices connected on which profile to Settings.Secure.
+ * Essentially the list of devices that a profile can connect on the next auto-connect
+ * attempt.
+ *
+ * @param params - ConnectionParams indicating which bluetooth profile to write this
+ * information
+ * for.
+ * @return true if the write was successful, false otherwise
+ */
+ public synchronized boolean writeDeviceInfoToSettings(ConnectionParams params) {
boolean writeSuccess = true;
+ Integer profileToUpdate = params.getBluetoothProfile();
+
if (mProfileToConnectableDevicesMap == null) {
writeSuccess = false;
} else {
- extractDeviceInfoFromDeviceMapLocked();
- try {
- AtomicFile oFile = new AtomicFile(
- new File(mContext.getFilesDir(), DEVICE_INFO_FILE));
- FileOutputStream outFile = oFile.startWrite();
- ObjectOutputStream ostream = new ObjectOutputStream(outFile);
- ostream.writeObject(mProfileToConnectableDevicesInfo);
- ostream.flush();
- ostream.close();
- oFile.finishWrite(outFile);
- outFile.close();
- if (DBG) {
- Log.d(TAG, "Writing successful");
+ List<String> deviceNames = new ArrayList<>();
+ BluetoothDevicesInfo devicesInfo = mProfileToConnectableDevicesMap.get(profileToUpdate);
+ StringBuilder sb = new StringBuilder();
+ String delimiter = ""; // start off with no delimiter.
+
+ // Iterate through the List<BluetoothDevice> and build a String that is
+ // names of all devices to be connected for this profile joined together and
+ // delimited by a delimiter (its a ',' here)
+ if (devicesInfo != null && devicesInfo.getDeviceList() != null) {
+ for (BluetoothDevice device : devicesInfo.getDeviceList()) {
+ sb.append(delimiter);
+ sb.append(device.getAddress());
+ delimiter = SETTINGS_DELIMITER;
}
- } catch (IOException e) {
- Log.e(TAG, e.getMessage());
- writeSuccess = false;
+
+ }
+ // joinedDeviceNames has something like "22:22:33:44:55:AB,22:23:xx:xx:xx:xx"
+ // mac addresses of connectable devices separated by a delimiter
+ String joinedDeviceNames = sb.toString();
+ Log.d(TAG, "Profile: " + profileToUpdate + " Writing: " + joinedDeviceNames);
+
+ long userId = ActivityManager.getCurrentUser();
+ switch (profileToUpdate) {
+ case BluetoothProfile.A2DP_SINK:
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ KEY_BLUETOOTH_AUTOCONNECT_MUSIC_DEVICES,
+ joinedDeviceNames, (int) userId);
+ break;
+
+ case BluetoothProfile.HEADSET_CLIENT:
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ KEY_BLUETOOTH_AUTOCONNECT_PHONE_DEVICES,
+ joinedDeviceNames, (int) userId);
+ break;
+
+ case BluetoothProfile.PBAP_CLIENT:
+ // use the phone
+ break;
+
+ case BluetoothProfile.MAP_CLIENT:
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ KEY_BLUETOOTH_AUTOCONNECT_MESSAGING_DEVICES,
+ joinedDeviceNames, (int) userId);
+ break;
+
}
}
return writeSuccess;
}
-
/**
- * Extracts {@link #mProfileToConnectableDevicesInfo} from
- * {@link #mProfileToConnectableDevicesMap}
- * {@link #mProfileToConnectableDevicesInfo} is a map of Profiles to List of names of
- * Connectable
- * devices that gets written to a file.
- */
- private void extractDeviceInfoFromDeviceMapLocked() {
- mProfileToConnectableDevicesInfo = new HashMap<Integer, List<String>>();
-
- for (Map.Entry<Integer, BluetoothDevicesInfo> entry : mProfileToConnectableDevicesMap
- .entrySet()) {
- // for every entry, extract the Profile and the list of device names
- Integer profile = entry.getKey();
- if (DBG) {
- Log.d(TAG, "Extracting for profile " + profile);
- }
- List<String> deviceNames = new ArrayList<>();
- BluetoothDevicesInfo devicesInfo = entry.getValue();
- // Iterate through the List<BluetoothDevice> and build List<DeviceNames>
- if (devicesInfo != null && devicesInfo.getDeviceList() != null) {
- for (BluetoothDevice device : devicesInfo.getDeviceList()) {
- deviceNames.add(device.getName());
- if (DBG) {
- Log.d(TAG, "Device: " + device.getName());
- }
- }
- }
- mProfileToConnectableDevicesInfo.put(profile, deviceNames);
- }
- }
-
- /**
- * Read the device information from file and populate the
+ * Read the device information from Settings.Secure and populate the
* {@link #mProfileToConnectableDevicesMap}
*
- * @return - true if the read was successful, false if not.
- */
- public synchronized boolean readDeviceInfoFromFile() {
- boolean readSuccess = true;
- try {
- AtomicFile iFile = new AtomicFile(new File(mContext.getFilesDir(), DEVICE_INFO_FILE));
- if (DBG) {
- Log.d(TAG, "Reading from file");
- }
- FileInputStream inFile = iFile.openRead();
- ObjectInputStream istream = new ObjectInputStream(inFile);
- mProfileToConnectableDevicesInfo =
- (HashMap<Integer, List<String>>) istream.readObject();
- istream.close();
- inFile.close();
- } catch (IOException | ClassNotFoundException e) {
- Log.e(TAG, e.getMessage());
- if (DBG) {
- Log.d(TAG, "No previously connected device information available");
- }
- readSuccess = false;
- }
-
- if (readSuccess) {
- readSuccess = rebuildDeviceMapFromDeviceInfoLocked();
- }
- return readSuccess;
- }
-
- /**
- * Rebuild the {@link #mProfileToConnectableDevicesMap} from the {@link
- * #mProfileToConnectableDevicesInfo}
+ * Device MAC addresses are written to Settings.Secure delimited by a ','.
+ * Ex: android.car.BLUETOOTH_AUTOCONNECT_PHONE_DEVICES: xx:xx:xx:xx:xx:xx,yy:yy:yy:yy:yy
+ * denotes that two devices with addresses xx:xx:xx:xx:xx:xx & yy:yy:yy:yy:yy:yy were connected
+ * as phones (in HFP and PBAP profiles) the last time this user was logged in.
*
- * @return true if the reconstruction was successful, false if not.
+ * @return - true if the read was successful, false if 1. BT Adapter not enabled 2. No prior
+ * bonded devices 3. No information stored in Settings for this user.
*/
- private boolean rebuildDeviceMapFromDeviceInfoLocked() {
- if (DBG) {
- Log.d(TAG, "Rebuilding device map");
- }
-
- if (mProfileToConnectableDevicesInfo == null) {
- Log.w(TAG, "No Device Info to rebuild the Device Map");
- return false;
- }
-
+ public synchronized boolean readAndRebuildDeviceMapFromSettings() {
+ List<String> deviceList;
+ String devices = null;
+ // Create and initialize mProfileToConnectableDevicesMap if needed.
+ initDeviceMap();
if (mBluetoothAdapter != null) {
if (DBG) {
- Log.d(TAG, "Bonded devices size:" + mBluetoothAdapter.getBondedDevices().size());
+ Log.d(TAG,
+ "Number of Bonded devices:" + mBluetoothAdapter.getBondedDevices().size());
}
if (mBluetoothAdapter.getBondedDevices().isEmpty()) {
if (DBG) {
@@ -1139,32 +1174,65 @@
return false;
}
}
+ // Read from Settings.Secure for the current user. There are 3 keys 1 each for Phone
+ // (HFP & PBAP), 1 for Music (A2DP) and 1 for Messaging device (MAP)
+ long userId = ActivityManager.getCurrentUser();
+ for (Integer profile : mProfilesToConnect) {
+ switch (profile) {
+ case BluetoothProfile.A2DP_SINK:
+ devices = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ KEY_BLUETOOTH_AUTOCONNECT_MUSIC_DEVICES, (int) userId);
+ break;
+ case BluetoothProfile.PBAP_CLIENT:
+ // fall through
+ case BluetoothProfile.HEADSET_CLIENT:
+ devices = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ KEY_BLUETOOTH_AUTOCONNECT_PHONE_DEVICES, (int) userId);
+ break;
+ case BluetoothProfile.MAP_CLIENT:
+ devices = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ KEY_BLUETOOTH_AUTOCONNECT_MESSAGING_DEVICES, (int) userId);
+ break;
+ default:
+ Log.e(TAG, "Unexpected profile");
+ break;
+ }
- // Iterate through the Map's entries and build the {@link #mProfileToConnectableDevicesMap}
- if (mProfileToConnectableDevicesMap == null) {
- mProfileToConnectableDevicesMap = new HashMap<>();
- }
-
- for (Map.Entry<Integer, List<String>> entry : mProfileToConnectableDevicesInfo.entrySet()) {
- Integer profile = entry.getKey();
- List<String> deviceList = entry.getValue();
- // Build the BluetoothDevicesInfo for this profile.
- BluetoothDevicesInfo devicesInfo = new BluetoothDevicesInfo(profile);
+ if (devices == null) {
+ if (DBG) {
+ Log.d(TAG, "No device information stored in Settings");
+ }
+ return false;
+ }
+ if (DBG) {
+ Log.d(TAG, "Devices: " + devices);
+ }
+ // Get a list of Device Mac Addresses from the value
+ deviceList = Arrays.asList(devices.split(SETTINGS_DELIMITER));
+ if (deviceList == null) {
+ return false;
+ }
+ BluetoothDevicesInfo devicesInfo = mProfileToConnectableDevicesMap.get(profile);
// Do we have a bonded device with this name? If so, get it and populate the device
// map.
- for (String name : deviceList) {
- BluetoothDevice deviceToAdd = getBondedDeviceWithGivenName(name);
+ for (String address : deviceList) {
+ if (DBG) {
+ Log.d(TAG, "Rebuilding - looking for " + address + " profile :" + profile);
+ }
+ BluetoothDevice deviceToAdd = getBondedDeviceWithGivenName(address);
if (deviceToAdd != null) {
+ if (DBG) {
+ Log.d(TAG, "Adding device " + deviceToAdd.getName());
+ }
devicesInfo.addDeviceLocked(deviceToAdd);
} else {
if (DBG) {
- Log.d(TAG, "No device with name " + name + " found in bonded devices");
+ Log.d(TAG, "No device with name " + address + " found in bonded devices");
}
}
}
mProfileToConnectableDevicesMap.put(profile, devicesInfo);
}
-
return true;
}
@@ -1191,7 +1259,7 @@
BluetoothDevice btDevice = null;
Set<BluetoothDevice> bondedDevices = mBluetoothAdapter.getBondedDevices();
for (BluetoothDevice bd : bondedDevices) {
- if (name.equals(bd.getName())) {
+ if (name.equals(bd.getAddress())) {
btDevice = bd;
break;
}
@@ -1199,70 +1267,6 @@
return btDevice;
}
- /**
- * All the BluetoothProfile.ServiceListeners to get the Profile Proxy objects
- */
- private BluetoothProfile.ServiceListener mProfileListener =
- new BluetoothProfile.ServiceListener() {
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- if (DBG) {
- Log.d(TAG, "OnServiceConnected profile: " + profile);
- }
- switch (profile) {
- case BluetoothProfile.A2DP_SINK:
- mBluetoothA2dpSink = (BluetoothA2dpSink) proxy;
- break;
-
- case BluetoothProfile.HEADSET_CLIENT:
- mBluetoothHeadsetClient = (BluetoothHeadsetClient) proxy;
- break;
-
- case BluetoothProfile.PBAP_CLIENT:
- mBluetoothPbapClient = (BluetoothPbapClient) proxy;
- break;
-
- case BluetoothProfile.MAP_CLIENT:
- mBluetoothMapClient = (BluetoothMapClient) proxy;
- break;
-
- default:
- if (DBG) {
- Log.d(TAG, "Unhandled profile");
- }
- break;
- }
-
- }
-
- public void onServiceDisconnected(int profile) {
- if (DBG) {
- Log.d(TAG, "onServiceDisconnected profile: " + profile);
- }
- switch (profile) {
- case BluetoothProfile.A2DP_SINK:
- mBluetoothA2dpSink = null;
- break;
-
- case BluetoothProfile.HEADSET_CLIENT:
- mBluetoothHeadsetClient = null;
- break;
-
- case BluetoothProfile.PBAP_CLIENT:
- mBluetoothPbapClient = null;
- break;
-
- case BluetoothProfile.MAP_CLIENT:
- mBluetoothMapClient = null;
- break;
-
- default:
- if (DBG) {
- Log.d(TAG, "Unhandled profile");
- }
- break;
- }
- }
- };
public void dump(PrintWriter writer) {
writer.println("*BluetoothDeviceConnectionPolicy*");