Snap for 4756844 from 7cc0bb4431931e2cdb7af395a4751e4aa389cf5e to pi-release

Change-Id: I679cf6bf047f47a5514b9d73327c78fb968037d3
diff --git a/src/com/android/server/telecom/BluetoothHeadsetProxy.java b/src/com/android/server/telecom/BluetoothHeadsetProxy.java
index c5afafe..7de49fc 100644
--- a/src/com/android/server/telecom/BluetoothHeadsetProxy.java
+++ b/src/com/android/server/telecom/BluetoothHeadsetProxy.java
@@ -60,11 +60,18 @@
         return mBluetoothHeadset.isAudioConnected(device);
     }
 
-    public boolean connectAudio(String deviceAddress) {
-        // TODO: update once the BT stack has this api.
+    public boolean connectAudio() {
         return mBluetoothHeadset.connectAudio();
     }
 
+    public boolean setActiveDevice(BluetoothDevice device) {
+        return mBluetoothHeadset.setActiveDevice(device);
+    }
+
+    public boolean isAudioOn() {
+        return mBluetoothHeadset.isAudioOn();
+    }
+
     public boolean disconnectAudio() {
         return mBluetoothHeadset.disconnectAudio();
     }
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index a1581f1..b335d77 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -778,6 +778,8 @@
                     // Send ringer mode change because we transit to ActiveBluetoothState even
                     // when HFP is connecting
                     mCallAudioManager.onRingerModeChange();
+                    // Update the in-call app on the new active BT device in case that changed.
+                    updateSystemAudioState();
                     return HANDLED;
                 case SWITCH_BLUETOOTH:
                 case USER_SWITCH_BLUETOOTH:
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index ff81b4d..d50ef1a 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -129,6 +129,10 @@
         mBluetoothHeadsetService = bluetoothHeadset;
     }
 
+    public BluetoothDevice getDeviceFromAddress(String address) {
+        return mConnectedDevicesByAddress.get(address);
+    }
+
     void onDeviceConnected(BluetoothDevice device) {
         synchronized (mLock) {
             if (!mConnectedDevicesByAddress.containsKey(device.getAddress())) {
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index cdb8b4e..5679522 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -17,11 +17,7 @@
 package com.android.server.telecom.bluetooth;
 
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.os.Message;
 import android.telecom.Log;
 import android.telecom.Logging.Session;
@@ -712,7 +708,20 @@
             Log.w(this, "Trying to connect audio but no headset service exists.");
             return false;
         }
-        return bluetoothHeadset.connectAudio(address);
+        BluetoothDevice device = mDeviceManager.getDeviceFromAddress(address);
+        if (device == null) {
+            Log.w(this, "Attempting to turn on audio for a disconnected device");
+            return false;
+        }
+        boolean success = bluetoothHeadset.setActiveDevice(device);
+        if (!success) {
+            Log.w(LOG_TAG, "Couldn't set active device to %s", address);
+            return false;
+        }
+        if (!bluetoothHeadset.isAudioOn()) {
+            return bluetoothHeadset.connectAudio();
+        }
+        return true;
     }
 
     private void disconnectAudio() {
diff --git a/testapps/AndroidManifest.xml b/testapps/AndroidManifest.xml
index a539de9..48451d1 100644
--- a/testapps/AndroidManifest.xml
+++ b/testapps/AndroidManifest.xml
@@ -22,6 +22,7 @@
         android:minSdkVersion="23"
         android:targetSdkVersion="23" />
 
+    <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
diff --git a/testapps/res/layout/incall_screen.xml b/testapps/res/layout/incall_screen.xml
index 36ffb27..452cb2b 100644
--- a/testapps/res/layout/incall_screen.xml
+++ b/testapps/res/layout/incall_screen.xml
@@ -29,7 +29,7 @@
     <GridLayout
         android:columnCount="3"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:orientation="horizontal">
         <Button
             android:id="@+id/end_call_button"
@@ -72,4 +72,48 @@
             android:layout_height="wrap_content"
             android:text="@string/handoverButton"/>
     </GridLayout>
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <Spinner
+            android:id="@+id/available_bt_devices"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"/>
+        <Button
+            android:id="@+id/set_bt_device_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/setBtDeviceButton"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <Button
+            android:id="@+id/earpiece_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/earpieceButton"/>
+        <Button
+            android:id="@+id/speaker_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/speakerButton"/>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <TextView
+            android:id="@+id/current_route_label"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/currentRouteLabel"/>
+        <TextView
+            android:id="@+id/current_audio_route"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="10dp"/>
+    </LinearLayout>
 </LinearLayout>
diff --git a/testapps/res/values/donottranslate_strings.xml b/testapps/res/values/donottranslate_strings.xml
index a0485d0..abd2949 100644
--- a/testapps/res/values/donottranslate_strings.xml
+++ b/testapps/res/values/donottranslate_strings.xml
@@ -68,6 +68,13 @@
 
     <string name="getKeyButton">Get Key Json</string>
 
+    <string name="earpieceButton">Earpiece/Wired</string>
+
+    <string name="speakerButton">Speakerphone</string>
+
+    <string name="setBtDeviceButton">Set BT device</string>
+
+    <string name="currentRouteLabel">Current audio route</string>
     <!-- String for button in SelfManagedCallingActivity. -->
     <string name="checkIfPermittedBeforeCallingButton">Check if calls permitted before calling</string>
 
diff --git a/testapps/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java b/testapps/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java
index 03ca3d0..78b8bcc 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestInCallServiceImpl.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.telecom.Call;
+import android.telecom.CallAudioState;
 import android.telecom.InCallService;
 import android.telecom.Phone;
 import android.util.Log;
@@ -32,6 +33,7 @@
  */
 public class TestInCallServiceImpl extends InCallService {
     private static final String TAG = "TestInCallServiceImpl";
+    public static TestInCallServiceImpl sInstance;
 
     private Phone mPhone;
 
@@ -63,14 +65,24 @@
     }
 
     @Override
-    public void onPhoneDestroyed(Phone phone) {
+    public boolean onUnbind(Intent intent) {
         Log.i(TAG, "onPhoneDestroyed");
         mPhone.removeListener(mPhoneListener);
         mPhone = null;
         TestCallList.getInstance().clearCalls();
+        sInstance = null;
+        return super.onUnbind(intent);
+    }
+
+    @Override
+    public void onCallAudioStateChanged(CallAudioState cas) {
+        if (TestInCallUI.sInstance != null) {
+            TestInCallUI.sInstance.updateCallAudioState(cas);
+        }
     }
 
     private void startInCallUI() {
+        sInstance = this;
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.setClass(this, TestInCallUI.class);
diff --git a/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java b/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
index d99798c..9851253 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestInCallUI.java
@@ -17,9 +17,11 @@
 package com.android.server.telecom.testapps;
 
 import android.app.Activity;
+import android.bluetooth.BluetoothDevice;
 import android.content.Intent;
 import android.os.Bundle;
 import android.telecom.Call;
+import android.telecom.CallAudioState;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -27,21 +29,50 @@
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
 import android.widget.ListView;
+import android.widget.Spinner;
+import android.widget.TextView;
 import android.widget.Toast;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
 
 public class TestInCallUI extends Activity {
+    private class BluetoothDeviceAdapter extends ArrayAdapter<BluetoothDevice> {
+        public BluetoothDeviceAdapter() {
+            super(TestInCallUI.this, android.R.layout.simple_spinner_item);
+            setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        }
 
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            BluetoothDevice info = getItem(position);
+            TextView result = new TextView(TestInCallUI.this);
+            result.setText(info.getName());
+            return result;
+        }
+
+        public void update(Collection<BluetoothDevice> devices) {
+            clear();
+            addAll(devices);
+        }
+    }
+
+    public static TestInCallUI sInstance;
     private ListView mListView;
     private TestCallList mCallList;
+    private Spinner mBtDeviceList;
+    private BluetoothDeviceAdapter mBluetoothDeviceAdapter;
+    private TextView mCurrentRouteDisplay;
 
     /** ${inheritDoc} */
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        sInstance = this;
 
         setContentView(R.layout.incall_screen);
 
@@ -90,6 +121,13 @@
         View startRttButton = findViewById(R.id.start_rtt_button);
         View acceptRttButton = findViewById(R.id.accept_rtt_button);
         View handoverButton = findViewById(R.id.request_handover_button);
+        View setBtDeviceButton = findViewById(R.id.set_bt_device_button);
+        View earpieceButton = findViewById(R.id.earpiece_button);
+        View speakerButton = findViewById(R.id.speaker_button);
+        mBtDeviceList = findViewById(R.id.available_bt_devices);
+        mBluetoothDeviceAdapter = new BluetoothDeviceAdapter();
+        mBtDeviceList.setAdapter(mBluetoothDeviceAdapter);
+        mCurrentRouteDisplay = findViewById(R.id.current_audio_route);
 
         endCallButton.setOnClickListener(new OnClickListener() {
             @Override
@@ -146,6 +184,22 @@
             }
         });
 
+        earpieceButton.setOnClickListener(view -> {
+            TestInCallServiceImpl.sInstance.setAudioRoute(CallAudioState.ROUTE_WIRED_OR_EARPIECE);
+        });
+
+        speakerButton.setOnClickListener(view -> {
+            TestInCallServiceImpl.sInstance.setAudioRoute(CallAudioState.ROUTE_SPEAKER);
+        });
+
+        setBtDeviceButton.setOnClickListener(view -> {
+            if (mBtDeviceList.getSelectedItem() != null
+                    && TestInCallServiceImpl.sInstance != null) {
+                TestInCallServiceImpl.sInstance.requestBluetoothAudio(
+                        (BluetoothDevice) mBtDeviceList.getSelectedItem());
+            }
+        });
+
         acceptRttButton.setOnClickListener(view -> {
             Call call = mCallList.getCall(0);
             if (!call.isRttActive()) {
@@ -163,9 +217,33 @@
         });
     }
 
+    public void updateCallAudioState(CallAudioState cas) {
+        mBluetoothDeviceAdapter.update(cas.getSupportedBluetoothDevices());
+        String routeText;
+        switch (cas.getRoute()) {
+            case CallAudioState.ROUTE_EARPIECE:
+                routeText = "Earpiece";
+                break;
+            case CallAudioState.ROUTE_SPEAKER:
+                routeText = "Speaker";
+                break;
+            case CallAudioState.ROUTE_WIRED_HEADSET:
+                routeText = "Wired";
+                break;
+            case CallAudioState.ROUTE_BLUETOOTH:
+                BluetoothDevice activeDevice = cas.getActiveBluetoothDevice();
+                routeText = activeDevice == null ? "null bt" : activeDevice.getName();
+                break;
+            default:
+                routeText = "unknown: " + cas.getRoute();
+        }
+        mCurrentRouteDisplay.setText(routeText);
+    }
+
     /** ${inheritDoc} */
     @Override
     protected void onDestroy() {
+        sInstance = null;
         super.onDestroy();
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
index 67af4ca..5cf4c1d 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
@@ -41,6 +41,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
@@ -73,7 +74,7 @@
         setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null);
         when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                 nullable(ContentResolver.class))).thenReturn(0L);
-        when(mHeadsetProxy.connectAudio(nullable(String.class))).thenReturn(false);
+        when(mHeadsetProxy.connectAudio()).thenReturn(false);
         executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, null);
         // Wait 3 times: for the first connection attempt, the retry attempt,
         // the second retry, and once more to make sure there are only three attempts.
@@ -81,7 +82,7 @@
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
-        verify(mHeadsetProxy, times(3)).connectAudio(DEVICE1.getAddress());
+        verifyConnectionAttempt(DEVICE1, 3);
         assertEquals(BluetoothRouteManager.AUDIO_OFF_STATE_NAME, sm.getCurrentState().getName());
         sm.getHandler().removeMessages(BluetoothRouteManager.CONNECTION_TIMEOUT);
         sm.quitNow();
@@ -95,7 +96,7 @@
         setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null);
         when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                 nullable(ContentResolver.class))).thenReturn(0L);
-        when(mHeadsetProxy.connectAudio(nullable(String.class))).thenReturn(false);
+        when(mHeadsetProxy.connectAudio()).thenReturn(false);
         executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, DEVICE2.getAddress());
         // Wait 3 times: the first connection attempt is accounted for in executeRoutingAction,
         // so wait twice for the retry attempt, again to make sure there are only three attempts,
@@ -104,7 +105,7 @@
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
-        verify(mHeadsetProxy, times(3)).connectAudio(DEVICE2.getAddress());
+        verifyConnectionAttempt(DEVICE2, 3);
         assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
                         + ":" + DEVICE1.getAddress(),
                 sm.getCurrentState().getName());
@@ -122,13 +123,13 @@
                 BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null);
         setupConnectedDevices(new BluetoothDevice[]{DEVICE3, DEVICE2, DEVICE1}, null);
         executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, DEVICE1.getAddress());
-        verify(mHeadsetProxy, times(1)).connectAudio(DEVICE1.getAddress());
+        verifyConnectionAttempt(DEVICE1, 1);
 
         setupConnectedDevices(new BluetoothDevice[]{DEVICE3, DEVICE2, DEVICE1}, DEVICE1);
         executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, DEVICE1.getAddress());
 
         executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, DEVICE2.getAddress());
-        verify(mHeadsetProxy, times(1)).connectAudio(DEVICE2.getAddress());
+        verifyConnectionAttempt(DEVICE2, 1);
 
         setupConnectedDevices(new BluetoothDevice[]{DEVICE3, DEVICE2, DEVICE1}, DEVICE2);
         executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, DEVICE2.getAddress());
@@ -136,7 +137,7 @@
         setupConnectedDevices(new BluetoothDevice[]{DEVICE3, DEVICE1}, null);
         executeRoutingAction(sm, BluetoothRouteManager.LOST_DEVICE, DEVICE2.getAddress());
         // Verify that we've fallen back to device 1
-        verify(mHeadsetProxy, times(2)).connectAudio(DEVICE1.getAddress());
+        verifyConnectionAttempt(DEVICE1, 2);
         assertEquals(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
                         + ":" + DEVICE1.getAddress(),
                 sm.getCurrentState().getName());
@@ -150,7 +151,7 @@
         setupConnectedDevices(new BluetoothDevice[]{DEVICE3}, null);
         executeRoutingAction(sm, BluetoothRouteManager.LOST_DEVICE, DEVICE1.getAddress());
         // Verify that we've fallen back to device 3
-        verify(mHeadsetProxy, times(1)).connectAudio(DEVICE3.getAddress());
+        verifyConnectionAttempt(DEVICE3, 1);
         assertEquals(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
                         + ":" + DEVICE3.getAddress(),
                 sm.getCurrentState().getName());
@@ -174,7 +175,7 @@
                 BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null);
         setupConnectedDevices(new BluetoothDevice[]{DEVICE3, DEVICE2, DEVICE1}, null);
         executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, DEVICE3.getAddress());
-        verify(mHeadsetProxy, times(1)).connectAudio(DEVICE3.getAddress());
+        verifyConnectionAttempt(DEVICE3, 1);
 
         setupConnectedDevices(new BluetoothDevice[]{DEVICE3, DEVICE2, DEVICE1}, DEVICE3);
         executeRoutingAction(sm, BluetoothRouteManager.HFP_IS_ON, DEVICE3.getAddress());
@@ -183,7 +184,7 @@
         setupConnectedDevices(new BluetoothDevice[]{DEVICE2, DEVICE1}, null);
         executeRoutingAction(sm, BluetoothRouteManager.LOST_DEVICE, DEVICE3.getAddress());
         // Verify that we've fallen back to device 2
-        verify(mHeadsetProxy, times(1)).connectAudio(DEVICE2.getAddress());
+        verifyConnectionAttempt(DEVICE2, 1);
         assertEquals(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
                         + ":" + DEVICE2.getAddress(),
                 sm.getCurrentState().getName());
@@ -197,7 +198,7 @@
         setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null);
         executeRoutingAction(sm, BluetoothRouteManager.LOST_DEVICE, DEVICE2.getAddress());
         // Verify that we've fallen back to device 1
-        verify(mHeadsetProxy, times(1)).connectAudio(DEVICE1.getAddress());
+        verifyConnectionAttempt(DEVICE1, 1);
         assertEquals(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
                         + ":" + DEVICE1.getAddress(),
                 sm.getCurrentState().getName());
@@ -235,6 +236,9 @@
                     (String) invocation.getArguments()[0]);
             return first == null ? null : first.getAddress();
         }).when(mDeviceManager).getMostRecentlyConnectedDevice(nullable(String.class));
+        for (BluetoothDevice device : devices) {
+            when(mDeviceManager.getDeviceFromAddress(device.getAddress())).thenReturn(device);
+        }
     }
 
     static void executeRoutingAction(BluetoothRouteManager brm, int message, String
@@ -258,13 +262,19 @@
     private void resetMocks() {
         reset(mDeviceManager, mListener, mHeadsetProxy, mTimeoutsAdapter);
         when(mDeviceManager.getHeadsetService()).thenReturn(mHeadsetProxy);
-        when(mHeadsetProxy.connectAudio(nullable(String.class))).thenReturn(true);
+        when(mHeadsetProxy.connectAudio()).thenReturn(true);
+        when(mHeadsetProxy.setActiveDevice(nullable(BluetoothDevice.class))).thenReturn(true);
         when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                 nullable(ContentResolver.class))).thenReturn(100000L);
         when(mTimeoutsAdapter.getBluetoothPendingTimeoutMillis(
                 nullable(ContentResolver.class))).thenReturn(100000L);
     }
 
+    private void verifyConnectionAttempt(BluetoothDevice device, int numTimes) {
+        verify(mHeadsetProxy, times(numTimes)).setActiveDevice(device);
+        verify(mHeadsetProxy, atLeast(numTimes)).connectAudio();
+    }
+
     private static BluetoothDevice getFirstExcluding(
             BluetoothDevice[] devices, String excludeAddress) {
         for (BluetoothDevice x : devices) {
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
index 6bccd08..bf35506 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
@@ -64,10 +64,10 @@
         private BluetoothDevice initialDevice;
         private BluetoothDevice audioOnDevice;
         private int messageType;
-        private String messageDevice;
+        private BluetoothDevice messageDevice;
         private ListenerUpdate[] expectedListenerUpdates;
         private int expectedBluetoothInteraction;
-        private String expectedConnectionAddress;
+        private BluetoothDevice expectedConnectionDevice;
         private String expectedFinalStateName;
         private BluetoothDevice[] connectedDevices;
 
@@ -93,7 +93,7 @@
             return this;
         }
 
-        public BluetoothRouteTestParametersBuilder setMessageDevice(String messageDevice) {
+        public BluetoothRouteTestParametersBuilder setMessageDevice(BluetoothDevice messageDevice) {
             this.messageDevice = messageDevice;
             return this;
         }
@@ -110,9 +110,9 @@
             return this;
         }
 
-        public BluetoothRouteTestParametersBuilder setExpectedConnectionAddress(String
-                expectedConnectionAddress) {
-            this.expectedConnectionAddress = expectedConnectionAddress;
+        public BluetoothRouteTestParametersBuilder setExpectedConnectionDevice(
+                BluetoothDevice expectedConnectionDevice) {
+            this.expectedConnectionDevice = expectedConnectionDevice;
             return this;
         }
 
@@ -140,7 +140,7 @@
                     messageType,
                     expectedListenerUpdates,
                     expectedBluetoothInteraction,
-                    expectedConnectionAddress,
+                    expectedConnectionDevice,
                     expectedFinalStateName,
                     connectedDevices,
                     messageDevice,
@@ -154,18 +154,18 @@
         public BluetoothDevice initialDevice; // null if we start from AudioOff
         public BluetoothDevice audioOnDevice; // The device (if any) that is active
         public int messageType; // Any of the commands from the state machine
-        public String messageDevice; // The device that should be specified in the message.
+        public BluetoothDevice messageDevice; // The device that should be specified in the message.
         public ListenerUpdate[] expectedListenerUpdates; // what the listener should expect.
         public int expectedBluetoothInteraction; // NONE, CONNECT, or DISCONNECT
-        public String expectedConnectionAddress; // Expected device to connect to.
+        public BluetoothDevice expectedConnectionDevice; // Expected device to connect to.
         public String expectedFinalStateName; // Expected name of the final state.
         public BluetoothDevice[] connectedDevices; // array of connected devices
 
         public BluetoothRouteTestParameters(String name, String initialBluetoothState,
                 BluetoothDevice initialDevice, int messageType, ListenerUpdate[]
-                expectedListenerUpdates, int expectedBluetoothInteraction, String
-                expectedConnectionAddress, String expectedFinalStateName,
-                BluetoothDevice[] connectedDevices, String messageDevice,
+                expectedListenerUpdates, int expectedBluetoothInteraction, BluetoothDevice
+                expectedConnectionDevice, String expectedFinalStateName,
+                BluetoothDevice[] connectedDevices, BluetoothDevice messageDevice,
                 BluetoothDevice audioOnDevice) {
             this.name = name;
             this.initialBluetoothState = initialBluetoothState;
@@ -173,7 +173,7 @@
             this.messageType = messageType;
             this.expectedListenerUpdates = expectedListenerUpdates;
             this.expectedBluetoothInteraction = expectedBluetoothInteraction;
-            this.expectedConnectionAddress = expectedConnectionAddress;
+            this.expectedConnectionDevice = expectedConnectionDevice;
             this.expectedFinalStateName = expectedFinalStateName;
             this.connectedDevices = connectedDevices;
             this.messageDevice = messageDevice;
@@ -190,7 +190,7 @@
                     ", messageDevice='" + messageDevice + '\'' +
                     ", expectedListenerUpdate=" + expectedListenerUpdates +
                     ", expectedBluetoothInteraction=" + expectedBluetoothInteraction +
-                    ", expectedConnectionAddress='" + expectedConnectionAddress + '\'' +
+                    ", expectedConnectionDevice='" + expectedConnectionDevice + '\'' +
                     ", expectedFinalStateName='" + expectedFinalStateName + '\'' +
                     ", connectedDevices=" + Arrays.toString(connectedDevices) +
                     '}';
@@ -229,11 +229,12 @@
 
         // Go through the utility methods for these two messages
         if (mParams.messageType == BluetoothRouteManager.NEW_DEVICE_CONNECTED) {
-            sm.onDeviceAdded(mParams.messageDevice);
+            sm.onDeviceAdded(mParams.messageDevice.getAddress());
         } else if (mParams.messageType == BluetoothRouteManager.LOST_DEVICE) {
-            sm.onDeviceLost(mParams.messageDevice);
+            sm.onDeviceLost(mParams.messageDevice.getAddress());
         } else {
-            executeRoutingAction(sm, mParams.messageType, mParams.messageDevice);
+            executeRoutingAction(sm, mParams.messageType,
+                    mParams.messageDevice == null ? null : mParams.messageDevice.getAddress());
         }
 
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
@@ -261,15 +262,18 @@
 
         switch (mParams.expectedBluetoothInteraction) {
             case NONE:
-                verify(mHeadsetProxy, never()).connectAudio(nullable(String.class));
+                verify(mHeadsetProxy, never()).connectAudio();
+                verify(mHeadsetProxy, never()).setActiveDevice(nullable(BluetoothDevice.class));
                 verify(mHeadsetProxy, never()).disconnectAudio();
                 break;
             case CONNECT:
-                verify(mHeadsetProxy).connectAudio(mParams.expectedConnectionAddress);
+                verify(mHeadsetProxy).connectAudio();
+                verify(mHeadsetProxy).setActiveDevice(mParams.expectedConnectionDevice);
                 verify(mHeadsetProxy, never()).disconnectAudio();
                 break;
             case DISCONNECT:
-                verify(mHeadsetProxy, never()).connectAudio(nullable(String.class));
+                verify(mHeadsetProxy, never()).connectAudio();
+                verify(mHeadsetProxy, never()).setActiveDevice(nullable(BluetoothDevice.class));
                 verify(mHeadsetProxy).disconnectAudio();
                 break;
         }
@@ -290,6 +294,9 @@
                     (String) invocation.getArguments()[0]);
             return first == null ? null : first.getAddress();
         }).when(mDeviceManager).getMostRecentlyConnectedDevice(nullable(String.class));
+        for (BluetoothDevice device : devices) {
+            when(mDeviceManager.getDeviceFromAddress(device.getAddress())).thenReturn(device);
+        }
     }
 
     private BluetoothRouteManager setupStateMachine(String initialState,
@@ -307,7 +314,8 @@
     private void resetMocks() {
         reset(mDeviceManager, mListener, mHeadsetProxy, mTimeoutsAdapter);
         when(mDeviceManager.getHeadsetService()).thenReturn(mHeadsetProxy);
-        when(mHeadsetProxy.connectAudio(nullable(String.class))).thenReturn(true);
+        when(mHeadsetProxy.connectAudio()).thenReturn(true);
+        when(mHeadsetProxy.setActiveDevice(nullable(BluetoothDevice.class))).thenReturn(true);
         when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                 nullable(ContentResolver.class))).thenReturn(100000L);
         when(mTimeoutsAdapter.getBluetoothPendingTimeoutMillis(
@@ -333,10 +341,10 @@
                 .setInitialDevice(null)
                 .setConnectedDevices(DEVICE1)
                 .setMessageType(BluetoothRouteManager.NEW_DEVICE_CONNECTED)
-                .setMessageDevice(DEVICE1.getAddress())
+                .setMessageDevice(DEVICE1)
                 .setExpectedListenerUpdates(ListenerUpdate.DEVICE_AVAILABLE)
                 .setExpectedBluetoothInteraction(NONE)
-                .setExpectedConnectionAddress(null)
+                .setExpectedConnectionDevice(null)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
                 .build());
 
@@ -348,9 +356,9 @@
                 .setMessageType(BluetoothRouteManager.CONNECT_HFP)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(CONNECT)
-                .setExpectedConnectionAddress(DEVICE2.getAddress())
+                .setExpectedConnectionDevice(DEVICE2)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
-                        + ":" + DEVICE2.getAddress())
+                        + ":" + DEVICE2)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
@@ -360,12 +368,12 @@
                 .setAudioOnDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2, DEVICE1)
                 .setMessageType(BluetoothRouteManager.HFP_IS_ON)
-                .setMessageDevice(DEVICE2.getAddress())
+                .setMessageDevice(DEVICE2)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(NONE)
-                .setExpectedConnectionAddress(null)
+                .setExpectedConnectionDevice(null)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
-                        + ":" + DEVICE2.getAddress())
+                        + ":" + DEVICE2)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
@@ -374,10 +382,10 @@
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2)
                 .setMessageType(BluetoothRouteManager.HFP_LOST)
-                .setMessageDevice(DEVICE2.getAddress())
+                .setMessageDevice(DEVICE2)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED)
                 .setExpectedBluetoothInteraction(NONE)
-                .setExpectedConnectionAddress(null)
+                .setExpectedConnectionDevice(null)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
                 .build());
 
@@ -387,12 +395,12 @@
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3)
                 .setMessageType(BluetoothRouteManager.HFP_LOST)
-                .setMessageDevice(DEVICE2.getAddress())
+                .setMessageDevice(DEVICE2)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(CONNECT)
-                .setExpectedConnectionAddress(DEVICE1.getAddress())
+                .setExpectedConnectionDevice(DEVICE1)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
-                        + ":" + DEVICE1.getAddress())
+                        + ":" + DEVICE1)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
@@ -401,12 +409,12 @@
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3)
                 .setMessageType(BluetoothRouteManager.CONNECT_HFP)
-                .setMessageDevice(DEVICE3.getAddress())
+                .setMessageDevice(DEVICE3)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(CONNECT)
-                .setExpectedConnectionAddress(DEVICE3.getAddress())
+                .setExpectedConnectionDevice(DEVICE3)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
-                        + ":" + DEVICE3.getAddress())
+                        + ":" + DEVICE3)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
@@ -415,12 +423,12 @@
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3)
                 .setMessageType(BluetoothRouteManager.CONNECT_HFP)
-                .setMessageDevice(DEVICE3.getAddress())
+                .setMessageDevice(DEVICE3)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(CONNECT)
-                .setExpectedConnectionAddress(DEVICE3.getAddress())
+                .setExpectedConnectionDevice(DEVICE3)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
-                        + ":" + DEVICE3.getAddress())
+                        + ":" + DEVICE3)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
@@ -429,11 +437,11 @@
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices()
                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
-                .setMessageDevice(DEVICE2.getAddress())
+                .setMessageDevice(DEVICE2)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
                         ListenerUpdate.DEVICE_LIST_CHANGED, ListenerUpdate.DEVICE_UNAVAILABLE)
                 .setExpectedBluetoothInteraction(NONE)
-                .setExpectedConnectionAddress(null)
+                .setExpectedConnectionDevice(null)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
                 .build());
 
@@ -443,13 +451,13 @@
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE3)
                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
-                .setMessageDevice(DEVICE2.getAddress())
+                .setMessageDevice(DEVICE2)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED,
                         ListenerUpdate.DEVICE_LIST_CHANGED)
                 .setExpectedBluetoothInteraction(CONNECT)
-                .setExpectedConnectionAddress(DEVICE3.getAddress())
+                .setExpectedConnectionDevice(DEVICE3)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
-                        + ":" + DEVICE3.getAddress())
+                        + ":" + DEVICE3)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
@@ -462,7 +470,7 @@
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(NONE)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
-                        + ":" + DEVICE1.getAddress())
+                        + ":" + DEVICE1)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
@@ -472,11 +480,11 @@
                 .setConnectedDevices(DEVICE2, DEVICE1)
                 .setAudioOnDevice(DEVICE1)
                 .setMessageType(BluetoothRouteManager.HFP_IS_ON)
-                .setMessageDevice(DEVICE1.getAddress())
+                .setMessageDevice(DEVICE1)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(NONE)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
-                        + ":" + DEVICE1.getAddress())
+                        + ":" + DEVICE1)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
@@ -485,13 +493,13 @@
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE3)
                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
-                .setMessageDevice(DEVICE2.getAddress())
+                .setMessageDevice(DEVICE2)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED,
                         ListenerUpdate.DEVICE_LIST_CHANGED)
                 .setExpectedBluetoothInteraction(CONNECT)
-                .setExpectedConnectionAddress(DEVICE3.getAddress())
+                .setExpectedConnectionDevice(DEVICE3)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
-                        + ":" + DEVICE3.getAddress())
+                        + ":" + DEVICE3)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
@@ -500,7 +508,7 @@
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices()
                 .setMessageType(BluetoothRouteManager.LOST_DEVICE)
-                .setMessageDevice(DEVICE2.getAddress())
+                .setMessageDevice(DEVICE2)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
                         ListenerUpdate.DEVICE_LIST_CHANGED)
                 .setExpectedBluetoothInteraction(NONE)
@@ -535,11 +543,11 @@
                 .setInitialDevice(null)
                 .setConnectedDevices(DEVICE2, DEVICE3)
                 .setMessageType(BluetoothRouteManager.HFP_IS_ON)
-                .setMessageDevice(DEVICE3.getAddress())
+                .setMessageDevice(DEVICE3)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(NONE)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
-                        + ":" + DEVICE3.getAddress())
+                        + ":" + DEVICE3)
                 .build());
 
         return result;