1 package org.robolectric.shadows; 2 3 import android.media.AudioRoutesInfo; 4 import android.media.MediaRouter; 5 import android.media.MediaRouter.RouteInfo; 6 import android.os.Parcel; 7 import android.text.TextUtils; 8 import javax.annotation.Nullable; 9 import org.robolectric.annotation.Implements; 10 import org.robolectric.annotation.RealObject; 11 import org.robolectric.annotation.Resetter; 12 import org.robolectric.util.ReflectionHelpers; 13 import org.robolectric.util.ReflectionHelpers.ClassParameter; 14 15 /** Shadow class for {@link android.media.MediaRouter}. */ 16 @Implements(MediaRouter.class) 17 public class ShadowMediaRouter { 18 public static final String BLUETOOTH_DEVICE_NAME = "TestBluetoothDevice"; 19 20 private @RealObject MediaRouter realObject; 21 22 /** 23 * Adds the Bluetooth A2DP route and ensures it's the selected route, simulating connecting a 24 * Bluetooth device. 25 */ addBluetoothRoute()26 public void addBluetoothRoute() { 27 updateBluetoothAudioRoute(BLUETOOTH_DEVICE_NAME); 28 29 realObject.selectRoute(MediaRouter.ROUTE_TYPE_LIVE_AUDIO, getBluetoothA2dpRoute()); 30 } 31 32 /** Removes the Bluetooth A2DP route, simulating disconnecting the Bluetooth device. */ removeBluetoothRoute()33 public void removeBluetoothRoute() { 34 // Android's AudioService passes a null Bluetooth device name to MediaRouter to signal that the 35 // A2DP route should be removed. 36 updateBluetoothAudioRoute(null); 37 } 38 39 /** Returns whether the Bluetooth A2DP route is the currently selected route. */ isBluetoothRouteSelected(int type)40 public boolean isBluetoothRouteSelected(int type) { 41 return realObject.getSelectedRoute(type).equals(getBluetoothA2dpRoute()); 42 } 43 getBluetoothA2dpRoute()44 private static RouteInfo getBluetoothA2dpRoute() { 45 return ReflectionHelpers.getField( 46 ReflectionHelpers.getStaticField(MediaRouter.class, "sStatic"), "mBluetoothA2dpRoute"); 47 } 48 49 /** 50 * Updates the MediaRouter's Bluetooth audio route. 51 * 52 * @param bluetoothDeviceName the name of the Bluetooth device or null to indicate that the 53 * already-existing Bluetooth A2DP device should be removed 54 */ updateBluetoothAudioRoute(@ullable String bluetoothDeviceName)55 private void updateBluetoothAudioRoute(@Nullable String bluetoothDeviceName) { 56 callUpdateAudioRoutes(newAudioRouteInfo(bluetoothDeviceName)); 57 } 58 59 /** 60 * Creates a new {@link AudioRoutesInfo} to be used for updating the Bluetooth audio route. 61 * 62 * @param bluetoothDeviceName the name of the Bluetooth device or null to indicate that the 63 * already-existing Bluetooth A2DP device should be removed 64 */ newAudioRouteInfo(@ullable String bluetoothDeviceName)65 private static AudioRoutesInfo newAudioRouteInfo(@Nullable String bluetoothDeviceName) { 66 Parcel p = Parcel.obtain(); 67 TextUtils.writeToParcel(bluetoothDeviceName, p, /* parcelableFlags= */ 0); 68 p.setDataPosition(0); 69 return AudioRoutesInfo.CREATOR.createFromParcel(p); 70 } 71 callUpdateAudioRoutes(AudioRoutesInfo routesInfo)72 private void callUpdateAudioRoutes(AudioRoutesInfo routesInfo) { 73 ReflectionHelpers.callInstanceMethod( 74 ReflectionHelpers.getStaticField(MediaRouter.class, "sStatic"), 75 "updateAudioRoutes", 76 ClassParameter.from(AudioRoutesInfo.class, routesInfo)); 77 } 78 79 @Resetter reset()80 public static void reset() { 81 ReflectionHelpers.setStaticField(MediaRouter.class, "sStatic", null); 82 } 83 } 84