Merge "Implement selectRoute in AudioPoliciesDeviceRouteController" into udc-dev
This commit is contained in:
@@ -62,7 +62,11 @@ import java.util.Objects;
|
|||||||
private final AudioRoutesObserver mAudioRoutesObserver = new AudioRoutesObserver();
|
private final AudioRoutesObserver mAudioRoutesObserver = new AudioRoutesObserver();
|
||||||
|
|
||||||
private int mDeviceVolume;
|
private int mDeviceVolume;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
private MediaRoute2Info mDeviceRoute;
|
private MediaRoute2Info mDeviceRoute;
|
||||||
|
@Nullable
|
||||||
|
private MediaRoute2Info mSelectedRoute;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
/* package */ AudioPoliciesDeviceRouteController(@NonNull Context context,
|
/* package */ AudioPoliciesDeviceRouteController(@NonNull Context context,
|
||||||
@@ -91,14 +95,26 @@ import java.util.Objects;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean selectRoute(@Nullable Integer type) {
|
public synchronized boolean selectRoute(@Nullable Integer type) {
|
||||||
// No-op as the controller does not support selection from the outside of the class.
|
if (type == null) {
|
||||||
|
mSelectedRoute = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isDeviceRouteType(type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mSelectedRoute = createRouteFromAudioInfo(type);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NonNull
|
@NonNull
|
||||||
public synchronized MediaRoute2Info getDeviceRoute() {
|
public synchronized MediaRoute2Info getDeviceRoute() {
|
||||||
|
if (mSelectedRoute != null) {
|
||||||
|
return mSelectedRoute;
|
||||||
|
}
|
||||||
return mDeviceRoute;
|
return mDeviceRoute;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +125,13 @@ import java.util.Objects;
|
|||||||
}
|
}
|
||||||
|
|
||||||
mDeviceVolume = volume;
|
mDeviceVolume = volume;
|
||||||
|
|
||||||
|
if (mSelectedRoute != null) {
|
||||||
|
mSelectedRoute = new MediaRoute2Info.Builder(mSelectedRoute)
|
||||||
|
.setVolume(volume)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute)
|
mDeviceRoute = new MediaRoute2Info.Builder(mDeviceRoute)
|
||||||
.setVolume(volume)
|
.setVolume(volume)
|
||||||
.build();
|
.build();
|
||||||
@@ -116,29 +139,47 @@ import java.util.Objects;
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
private MediaRoute2Info createRouteFromAudioInfo(@Nullable AudioRoutesInfo newRoutes) {
|
private MediaRoute2Info createRouteFromAudioInfo(@Nullable AudioRoutesInfo newRoutes) {
|
||||||
int name = R.string.default_audio_route_name;
|
|
||||||
int type = TYPE_BUILTIN_SPEAKER;
|
int type = TYPE_BUILTIN_SPEAKER;
|
||||||
|
|
||||||
if (newRoutes != null) {
|
if (newRoutes != null) {
|
||||||
if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0) {
|
if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0) {
|
||||||
type = TYPE_WIRED_HEADPHONES;
|
type = TYPE_WIRED_HEADPHONES;
|
||||||
name = R.string.default_audio_route_name_headphones;
|
|
||||||
} else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
|
} else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
|
||||||
type = TYPE_WIRED_HEADSET;
|
type = TYPE_WIRED_HEADSET;
|
||||||
name = R.string.default_audio_route_name_headphones;
|
|
||||||
} else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
|
} else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
|
||||||
type = TYPE_DOCK;
|
type = TYPE_DOCK;
|
||||||
name = R.string.default_audio_route_name_dock_speakers;
|
|
||||||
} else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
|
} else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
|
||||||
type = TYPE_HDMI;
|
type = TYPE_HDMI;
|
||||||
name = R.string.default_audio_route_name_external_device;
|
|
||||||
} else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) {
|
} else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_USB) != 0) {
|
||||||
type = TYPE_USB_DEVICE;
|
type = TYPE_USB_DEVICE;
|
||||||
name = R.string.default_audio_route_name_usb;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return createRouteFromAudioInfo(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private MediaRoute2Info createRouteFromAudioInfo(@MediaRoute2Info.Type int type) {
|
||||||
|
int name = R.string.default_audio_route_name;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case TYPE_WIRED_HEADPHONES:
|
||||||
|
case TYPE_WIRED_HEADSET:
|
||||||
|
name = R.string.default_audio_route_name_headphones;
|
||||||
|
break;
|
||||||
|
case TYPE_DOCK:
|
||||||
|
name = R.string.default_audio_route_name_dock_speakers;
|
||||||
|
break;
|
||||||
|
case TYPE_HDMI:
|
||||||
|
name = R.string.default_audio_route_name_external_device;
|
||||||
|
break;
|
||||||
|
case TYPE_USB_DEVICE:
|
||||||
|
name = R.string.default_audio_route_name_usb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
return new MediaRoute2Info.Builder(
|
return new MediaRoute2Info.Builder(
|
||||||
DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString())
|
DEVICE_ROUTE_ID, mContext.getResources().getText(name).toString())
|
||||||
@@ -156,19 +197,43 @@ import java.util.Objects;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyDeviceRouteUpdate(@NonNull MediaRoute2Info deviceRoute) {
|
/**
|
||||||
mOnDeviceRouteChangedListener.onDeviceRouteChanged(deviceRoute);
|
* Checks if the given type is a device route.
|
||||||
|
*
|
||||||
|
* <p>Device route means a route which is either built-in or wired to the current device.
|
||||||
|
*
|
||||||
|
* @param type specifies the type of the device.
|
||||||
|
* @return {@code true} if the device is wired or built-in and {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
private boolean isDeviceRouteType(@MediaRoute2Info.Type int type) {
|
||||||
|
switch (type) {
|
||||||
|
case TYPE_BUILTIN_SPEAKER:
|
||||||
|
case TYPE_WIRED_HEADPHONES:
|
||||||
|
case TYPE_WIRED_HEADSET:
|
||||||
|
case TYPE_DOCK:
|
||||||
|
case TYPE_HDMI:
|
||||||
|
case TYPE_USB_DEVICE:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AudioRoutesObserver extends IAudioRoutesObserver.Stub {
|
private class AudioRoutesObserver extends IAudioRoutesObserver.Stub {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispatchAudioRoutesChanged(AudioRoutesInfo newAudioRoutes) {
|
public void dispatchAudioRoutesChanged(AudioRoutesInfo newAudioRoutes) {
|
||||||
|
boolean isDeviceRouteChanged;
|
||||||
MediaRoute2Info deviceRoute = createRouteFromAudioInfo(newAudioRoutes);
|
MediaRoute2Info deviceRoute = createRouteFromAudioInfo(newAudioRoutes);
|
||||||
|
|
||||||
synchronized (AudioPoliciesDeviceRouteController.this) {
|
synchronized (AudioPoliciesDeviceRouteController.this) {
|
||||||
mDeviceRoute = deviceRoute;
|
mDeviceRoute = deviceRoute;
|
||||||
|
isDeviceRouteChanged = mSelectedRoute == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDeviceRouteChanged) {
|
||||||
|
mOnDeviceRouteChangedListener.onDeviceRouteChanged(deviceRoute);
|
||||||
}
|
}
|
||||||
notifyDeviceRouteUpdate(deviceRoute);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.server.media;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.common.truth.Truth.assertWithMessage;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.anyInt;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.AudioRoutesInfo;
|
||||||
|
import android.media.IAudioRoutesObserver;
|
||||||
|
import android.media.MediaRoute2Info;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
import com.android.server.audio.AudioService;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.JUnit4;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@RunWith(JUnit4.class)
|
||||||
|
public class AudioPoliciesDeviceRouteControllerTest {
|
||||||
|
|
||||||
|
private static final String ROUTE_NAME_DEFAULT = "default";
|
||||||
|
private static final String ROUTE_NAME_DOCK = "dock";
|
||||||
|
private static final String ROUTE_NAME_HEADPHONES = "headphones";
|
||||||
|
|
||||||
|
private static final int VOLUME_SAMPLE_1 = 25;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Context mContext;
|
||||||
|
@Mock
|
||||||
|
private Resources mResources;
|
||||||
|
@Mock
|
||||||
|
private AudioManager mAudioManager;
|
||||||
|
@Mock
|
||||||
|
private AudioService mAudioService;
|
||||||
|
@Mock
|
||||||
|
private DeviceRouteController.OnDeviceRouteChangedListener mOnDeviceRouteChangedListener;
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<IAudioRoutesObserver.Stub> mAudioRoutesObserverCaptor;
|
||||||
|
|
||||||
|
private AudioPoliciesDeviceRouteController mController;
|
||||||
|
|
||||||
|
private IAudioRoutesObserver.Stub mAudioRoutesObserver;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
when(mContext.getResources()).thenReturn(mResources);
|
||||||
|
when(mResources.getText(anyInt())).thenReturn(ROUTE_NAME_DEFAULT);
|
||||||
|
|
||||||
|
// Setting built-in speaker as default speaker.
|
||||||
|
AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
|
||||||
|
audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_SPEAKER;
|
||||||
|
when(mAudioService.startWatchingRoutes(mAudioRoutesObserverCaptor.capture()))
|
||||||
|
.thenReturn(audioRoutesInfo);
|
||||||
|
|
||||||
|
mController = new AudioPoliciesDeviceRouteController(
|
||||||
|
mContext, mAudioManager, mAudioService, mOnDeviceRouteChangedListener);
|
||||||
|
|
||||||
|
mAudioRoutesObserver = mAudioRoutesObserverCaptor.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDeviceRoute_noSelectedRoutes_returnsDefaultDevice() {
|
||||||
|
MediaRoute2Info route2Info = mController.getDeviceRoute();
|
||||||
|
|
||||||
|
assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DEFAULT);
|
||||||
|
assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_BUILTIN_SPEAKER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDeviceRoute_audioRouteHasChanged_returnsRouteFromAudioService() {
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_headphones))
|
||||||
|
.thenReturn(ROUTE_NAME_HEADPHONES);
|
||||||
|
|
||||||
|
AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
|
||||||
|
audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
|
||||||
|
callAudioRoutesObserver(audioRoutesInfo);
|
||||||
|
|
||||||
|
MediaRoute2Info route2Info = mController.getDeviceRoute();
|
||||||
|
assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES);
|
||||||
|
assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDeviceRoute_selectDevice_returnsSelectedRoute() {
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_dock_speakers))
|
||||||
|
.thenReturn(ROUTE_NAME_DOCK);
|
||||||
|
|
||||||
|
mController.selectRoute(MediaRoute2Info.TYPE_DOCK);
|
||||||
|
|
||||||
|
MediaRoute2Info route2Info = mController.getDeviceRoute();
|
||||||
|
assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DOCK);
|
||||||
|
assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDeviceRoute_hasSelectedAndAudioServiceRoutes_returnsSelectedRoute() {
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_headphones))
|
||||||
|
.thenReturn(ROUTE_NAME_HEADPHONES);
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_dock_speakers))
|
||||||
|
.thenReturn(ROUTE_NAME_DOCK);
|
||||||
|
|
||||||
|
AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
|
||||||
|
audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
|
||||||
|
callAudioRoutesObserver(audioRoutesInfo);
|
||||||
|
|
||||||
|
mController.selectRoute(MediaRoute2Info.TYPE_DOCK);
|
||||||
|
|
||||||
|
MediaRoute2Info route2Info = mController.getDeviceRoute();
|
||||||
|
assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_DOCK);
|
||||||
|
assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDeviceRoute_unselectRoute_returnsAudioServiceRoute() {
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_headphones))
|
||||||
|
.thenReturn(ROUTE_NAME_HEADPHONES);
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_dock_speakers))
|
||||||
|
.thenReturn(ROUTE_NAME_DOCK);
|
||||||
|
|
||||||
|
mController.selectRoute(MediaRoute2Info.TYPE_DOCK);
|
||||||
|
|
||||||
|
AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
|
||||||
|
audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
|
||||||
|
callAudioRoutesObserver(audioRoutesInfo);
|
||||||
|
|
||||||
|
mController.selectRoute(null);
|
||||||
|
|
||||||
|
MediaRoute2Info route2Info = mController.getDeviceRoute();
|
||||||
|
assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES);
|
||||||
|
assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDeviceRoute_selectRouteFails_returnsAudioServiceRoute() {
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_headphones))
|
||||||
|
.thenReturn(ROUTE_NAME_HEADPHONES);
|
||||||
|
|
||||||
|
AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
|
||||||
|
audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
|
||||||
|
callAudioRoutesObserver(audioRoutesInfo);
|
||||||
|
|
||||||
|
mController.selectRoute(MediaRoute2Info.TYPE_BLUETOOTH_A2DP);
|
||||||
|
|
||||||
|
MediaRoute2Info route2Info = mController.getDeviceRoute();
|
||||||
|
assertThat(route2Info.getName()).isEqualTo(ROUTE_NAME_HEADPHONES);
|
||||||
|
assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void selectRoute_selectWiredRoute_returnsTrue() {
|
||||||
|
assertThat(mController.selectRoute(MediaRoute2Info.TYPE_HDMI)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void selectRoute_selectBluetoothRoute_returnsFalse() {
|
||||||
|
assertThat(mController.selectRoute(MediaRoute2Info.TYPE_BLUETOOTH_A2DP)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void selectRoute_unselectRoute_returnsTrue() {
|
||||||
|
assertThat(mController.selectRoute(null)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateVolume_noSelectedRoute_deviceRouteVolumeChanged() {
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_headphones))
|
||||||
|
.thenReturn(ROUTE_NAME_HEADPHONES);
|
||||||
|
|
||||||
|
AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
|
||||||
|
audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
|
||||||
|
callAudioRoutesObserver(audioRoutesInfo);
|
||||||
|
|
||||||
|
mController.updateVolume(VOLUME_SAMPLE_1);
|
||||||
|
|
||||||
|
MediaRoute2Info route2Info = mController.getDeviceRoute();
|
||||||
|
assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_WIRED_HEADPHONES);
|
||||||
|
assertThat(route2Info.getVolume()).isEqualTo(VOLUME_SAMPLE_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateVolume_connectSelectedRouteLater_selectedRouteVolumeChanged() {
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_headphones))
|
||||||
|
.thenReturn(ROUTE_NAME_HEADPHONES);
|
||||||
|
when(mResources.getText(R.string.default_audio_route_name_dock_speakers))
|
||||||
|
.thenReturn(ROUTE_NAME_DOCK);
|
||||||
|
|
||||||
|
AudioRoutesInfo audioRoutesInfo = new AudioRoutesInfo();
|
||||||
|
audioRoutesInfo.mainType = AudioRoutesInfo.MAIN_HEADPHONES;
|
||||||
|
callAudioRoutesObserver(audioRoutesInfo);
|
||||||
|
|
||||||
|
mController.updateVolume(VOLUME_SAMPLE_1);
|
||||||
|
|
||||||
|
mController.selectRoute(MediaRoute2Info.TYPE_DOCK);
|
||||||
|
|
||||||
|
MediaRoute2Info route2Info = mController.getDeviceRoute();
|
||||||
|
assertThat(route2Info.getType()).isEqualTo(MediaRoute2Info.TYPE_DOCK);
|
||||||
|
assertThat(route2Info.getVolume()).isEqualTo(VOLUME_SAMPLE_1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates {@link IAudioRoutesObserver.Stub#dispatchAudioRoutesChanged(AudioRoutesInfo)}
|
||||||
|
* from {@link AudioService}. This happens when there is a wired route change,
|
||||||
|
* like a wired headset being connected.
|
||||||
|
*
|
||||||
|
* @param audioRoutesInfo updated state of connected wired device
|
||||||
|
*/
|
||||||
|
private void callAudioRoutesObserver(AudioRoutesInfo audioRoutesInfo) {
|
||||||
|
try {
|
||||||
|
// this is a captured observer implementation
|
||||||
|
// from WiredRoutesController's AudioService#startWatchingRoutes call
|
||||||
|
mAudioRoutesObserver.dispatchAudioRoutesChanged(audioRoutesInfo);
|
||||||
|
} catch (RemoteException exception) {
|
||||||
|
// Should not happen since the object is mocked.
|
||||||
|
assertWithMessage("An unexpected RemoteException happened.").fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user