release-request-33811b80-8470-43aa-a2e6-0c80aa8b51af-for-git_oc-release-4070583 snap-temp-L92300000070865789

Change-Id: I7b28a55a6c175308adf7babfbfc57bd8b3b1261d
diff --git a/car-lib/src/android/car/ICarBluetoothUserService.aidl b/car-lib/src/android/car/ICarBluetoothUserService.aidl
index b1f7a39..a906a3c 100644
--- a/car-lib/src/android/car/ICarBluetoothUserService.aidl
+++ b/car-lib/src/android/car/ICarBluetoothUserService.aidl
@@ -24,4 +24,5 @@
     void closeBluetoothConnectionProxy();
     boolean isBluetoothConnectionProxyAvailable(in int profile);
     void bluetoothConnectToProfile(in int profile, in BluetoothDevice device);
+    void setProfilePriority(in int profile, in BluetoothDevice device, in int priority);
 }
diff --git a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
index 4cdb640..e80b843 100644
--- a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
+++ b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
@@ -24,6 +24,7 @@
 import android.bluetooth.BluetoothMapClient;
 import android.bluetooth.BluetoothPbapClient;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
 import android.car.hardware.CarPropertyValue;
 import android.car.hardware.CarSensorEvent;
 import android.car.hardware.CarSensorManager;
@@ -38,6 +39,8 @@
 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.ParcelUuid;
+import android.os.Parcelable;
 import android.os.UserHandle;
 import android.provider.Settings;
 
@@ -237,7 +240,7 @@
             BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
             if (DBG) {
                 if (device != null) {
-                    Log.d(TAG, "Received Intent for device: " + device.getName() + action);
+                    Log.d(TAG, "Received Intent for device: " + device + " " + action);
                 } else {
                     Log.d(TAG, "Received Intent no device: " + action);
                 }
@@ -287,6 +290,91 @@
                     writeDeviceInfoToSettings();
                     resetBluetoothDevicesConnectionInfo();
                 }
+            } else if (BluetoothDevice.ACTION_UUID.equals(action)) {
+                // Received during pairing with the UUIDs of the Bluetooth profiles supported by
+                // the remote device.
+                if (DBG) {
+                    Log.d(TAG, "Received UUID intent for device " + device);
+                }
+                Parcelable[] uuids = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
+                if (uuids != null) {
+                    ParcelUuid[] uuidsToSend = new ParcelUuid[uuids.length];
+                    for (int i = 0; i < uuidsToSend.length; i++) {
+                        uuidsToSend[i] = (ParcelUuid)uuids[i];
+                    }
+                    setProfilePriorities(device, uuidsToSend, BluetoothProfile.PRIORITY_ON);
+                }
+
+            }
+        }
+    }
+
+    /**
+     * Set priority for the Bluetooth profiles.
+     *
+     * The Bluetooth service stores the priority of a Bluetooth profile per device as a key value
+     * pair - BluetoothProfile_device:<Priority>.
+     * When we pair a device from the Settings App, the expected behavior is for the app to connect
+     * on all appropriate profiles after successful pairing automatically, without the user having
+     * to explicitly issue a connect. The settings app checks for the priority of the device from
+     * the above key-value pair and if the priority is set to PRIORITY_OFF or PRIORITY_UNDEFINED,
+     * the settings app will stop with just pairing and not connect.
+     * This scenario will happen when we pair a device, then unpair it and then pair it again.  When
+     * the device is unpaired, the BT stack sets the priority for that device to PRIORITY_UNDEFINED
+     * ( as a way of resetting).  So, the next time the same device is paired, the Settings app will
+     * stop with just pairing and not connect as explained above. Here, we register to receive the
+     * ACTION_UUID intent, which will broadcast the UUIDs corresponding to the profiles supported by
+     * the remote device which is successfully paired and we turn on the priority so when the
+     * Settings app tries to check before connecting, the priority is set to the expected value.
+     *
+     * @param device   - Remote Bluetooth device
+     * @param uuids    - UUIDs of the Bluetooth Profiles supported by the remote device
+     * @param priority - priority to set
+     */
+    private void setProfilePriorities(BluetoothDevice device, ParcelUuid[] uuids, int priority) {
+        // need the BluetoothProfile proxy to be able to call the setPriority API
+        if (mCarBluetoothUserService == null) {
+            mCarBluetoothUserService = setupBluetoothUserService();
+        }
+        if (mCarBluetoothUserService != null) {
+            for (Integer profile : mProfilesToConnect) {
+                setBluetoothProfilePriorityIfUuidFound(uuids, profile, device, priority);
+            }
+        }
+    }
+
+    private void setBluetoothProfilePriorityIfUuidFound(ParcelUuid[] uuids, int profile,
+            BluetoothDevice device, int priority) {
+        if (mCarBluetoothUserService == null || device == null) {
+            return;
+        }
+        // Build a list of UUIDs that represent a profile.
+        List<ParcelUuid> uuidsToCheck = new ArrayList<>();
+        switch (profile) {
+            case BluetoothProfile.A2DP_SINK:
+                uuidsToCheck.add(BluetoothUuid.AudioSource);
+                break;
+            case BluetoothProfile.HEADSET_CLIENT:
+                uuidsToCheck.add(BluetoothUuid.Handsfree_AG);
+                uuidsToCheck.add(BluetoothUuid.HSP_AG);
+                break;
+            case BluetoothProfile.PBAP_CLIENT:
+                uuidsToCheck.add(BluetoothUuid.PBAP_PSE);
+                break;
+            case BluetoothProfile.MAP_CLIENT:
+                uuidsToCheck.add(BluetoothUuid.MAS);
+                break;
+        }
+
+        for (ParcelUuid uuid : uuidsToCheck) {
+            if (BluetoothUuid.isUuidPresent(uuids, uuid)) {
+                try {
+                    mCarBluetoothUserService.setProfilePriority(profile, device, priority);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException calling setProfilePriority");
+                }
+                // if any one of the uuid in uuidsTocheck is present, set the priority and break
+                break;
             }
         }
     }
@@ -309,6 +397,9 @@
             if (DBG) {
                 Log.d(TAG, "Connected to PerUserCarService");
             }
+            // Get the BluetoothUserService and also setup the Bluetooth Connection Proxy for
+            // all profiles.
+            mCarBluetoothUserService = setupBluetoothUserService();
             // re-initialize for current user.
             initializeUserSpecificInfo();
         }
@@ -415,9 +506,6 @@
             setupBluetoothEventsIntentFilterLocked();
 
             mConnectionInFlight = new ConnectionParams();
-            // Get the BluetoothUserService and also setup the Bluetooth Connection Proxy for
-            // all profiles.
-            mCarBluetoothUserService = setupBluetoothUserService();
             mUserSpecificInfoInitialized = true;
         }
     }
@@ -438,8 +526,11 @@
         profileFilter.addAction(BluetoothPbapClient.ACTION_CONNECTION_STATE_CHANGED);
         profileFilter.addAction(BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
         profileFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        mContext.registerReceiverAsUser(mBluetoothBroadcastReceiver, UserHandle.CURRENT,
-                profileFilter, null, null);
+        profileFilter.addAction(BluetoothDevice.ACTION_UUID);
+        if (mContext != null) {
+            mContext.registerReceiverAsUser(mBluetoothBroadcastReceiver, UserHandle.CURRENT,
+                    profileFilter, null, null);
+        }
     }
 
     /**
@@ -646,7 +737,7 @@
             return;
         }
         if (DBG) {
-            Log.d(TAG, "BondState :" + bondState + " Device: " + device.getName());
+            Log.d(TAG, "BondState :" + bondState + " Device: " + device);
         }
         // Bonded devices are added to a profile's device list after the device CONNECTS on the
         // profile.  When unpaired, we remove the device from all of the profiles' device list.
diff --git a/service/src/com/android/car/CarBluetoothUserService.java b/service/src/com/android/car/CarBluetoothUserService.java
index 7ee02cf..55365a0 100644
--- a/service/src/com/android/car/CarBluetoothUserService.java
+++ b/service/src/com/android/car/CarBluetoothUserService.java
@@ -31,7 +31,7 @@
 
 
 public class CarBluetoothUserService extends ICarBluetoothUserService.Stub {
-    private static final boolean DBG = false;
+    private static final boolean DBG = true;
     private static final String TAG = "CarBluetoothUsrSvc";
     private BluetoothAdapter mBluetoothAdapter = null;
     private final PerUserCarService mService;
@@ -164,6 +164,36 @@
     }
 
     /**
+     * Set the priority of the given Bluetooth profile for the given remote device
+     * @param profile - Bluetooth profile
+     * @param device - remote Bluetooth device
+     * @param priority - priority to set
+     */
+    @Override
+    public void setProfilePriority(int profile, BluetoothDevice device, int priority) {
+        if (!isBluetoothConnectionProxyAvailable(profile)) {
+            Log.e(TAG, "Cannot connect to Profile. Proxy Unavailable");
+            return;
+        }
+        switch (profile) {
+            case BluetoothProfile.A2DP_SINK:
+                mBluetoothA2dpSink.setPriority(device, priority);
+                break;
+            case BluetoothProfile.HEADSET_CLIENT:
+                mBluetoothHeadsetClient.setPriority(device, priority);
+                break;
+            case BluetoothProfile.MAP_CLIENT:
+                mBluetoothMapClient.setPriority(device, priority);
+                break;
+            case BluetoothProfile.PBAP_CLIENT:
+                mBluetoothPbapClient.setPriority(device, priority);
+                break;
+            default:
+                Log.d(TAG, "Unknown Profile");
+                break;
+        }
+    }
+    /**
      * All the BluetoothProfile.ServiceListeners to get the Profile Proxy objects
      */
     private BluetoothProfile.ServiceListener mProfileListener =
diff --git a/tools/bootanalyze/bootanalyze.py b/tools/bootanalyze/bootanalyze.py
index 7010725..da874ce 100755
--- a/tools/bootanalyze/bootanalyze.py
+++ b/tools/bootanalyze/bootanalyze.py
@@ -680,7 +680,7 @@
   return math.sqrt(variance)
 
 def grab_bootchart(boot_chart_file_name):
-  subprocess.call("./system/core/init/grab-bootchart.sh --no-viewer", shell=True)
+  subprocess.call("./system/core/init/grab-bootchart.sh", shell=True)
   print "Saving boot chart as " + boot_chart_file_name + ".tgz"
   subprocess.call('cp /tmp/android-bootchart/bootchart.tgz ./' + boot_chart_file_name + '.tgz',\
                   shell=True)