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