1 package org.robolectric.shadows; 2 3 import static org.robolectric.util.reflector.Reflector.reflector; 4 5 import android.app.PendingIntent; 6 import android.media.MediaMetadata; 7 import android.media.Rating; 8 import android.media.session.MediaController; 9 import android.media.session.MediaController.Callback; 10 import android.media.session.MediaController.PlaybackInfo; 11 import android.media.session.PlaybackState; 12 import android.os.Bundle; 13 import android.os.Handler; 14 import java.util.ArrayList; 15 import java.util.List; 16 import javax.annotation.Nonnull; 17 import javax.annotation.Nullable; 18 import org.robolectric.annotation.Implementation; 19 import org.robolectric.annotation.Implements; 20 import org.robolectric.annotation.RealObject; 21 import org.robolectric.util.ReflectionHelpers; 22 import org.robolectric.util.ReflectionHelpers.ClassParameter; 23 import org.robolectric.util.reflector.Direct; 24 import org.robolectric.util.reflector.ForType; 25 26 /** Implementation of {@link android.media.session.MediaController}. */ 27 @Implements(value = MediaController.class) 28 public class ShadowMediaController { 29 @RealObject private MediaController realMediaController; 30 private PlaybackState playbackState; 31 private PlaybackInfo playbackInfo; 32 private MediaMetadata mediaMetadata; 33 private PendingIntent sessionActivity; 34 private Bundle extras; 35 36 /** 37 * A value of RATING_NONE for ratingType indicates that rating media is not supported by the media 38 * session associated with the media controller 39 */ 40 private int ratingType = Rating.RATING_NONE; 41 42 private final List<Callback> callbacks = new ArrayList<>(); 43 44 /** Saves the package name for use inside the shadow. */ setPackageName(String packageName)45 public void setPackageName(String packageName) { 46 ReflectionHelpers.setField(realMediaController, "mPackageName", packageName); 47 } 48 49 /** 50 * Saves the playbackState to control the return value of {@link 51 * MediaController#getPlaybackState()}. 52 */ setPlaybackState(PlaybackState playbackState)53 public void setPlaybackState(PlaybackState playbackState) { 54 this.playbackState = playbackState; 55 } 56 57 /** Gets the playbackState set via {@link #setPlaybackState}. */ 58 @Implementation getPlaybackState()59 protected PlaybackState getPlaybackState() { 60 return playbackState; 61 } 62 63 /** 64 * Saves the playbackInfo to control the return value of {@link 65 * MediaController#getPlaybackInfo()}. 66 * 67 * <p>{@link PlaybackInfoBuilder} can be used to create PlaybackInfo instances. 68 */ setPlaybackInfo(PlaybackInfo playbackInfo)69 public void setPlaybackInfo(PlaybackInfo playbackInfo) { 70 this.playbackInfo = playbackInfo; 71 } 72 73 /** Gets the playbackInfo set via {@link #setPlaybackInfo}. */ 74 @Implementation getPlaybackInfo()75 protected PlaybackInfo getPlaybackInfo() { 76 return playbackInfo; 77 } 78 79 /** 80 * Saves the mediaMetadata to control the return value of {@link MediaController#getMetadata()}. 81 */ setMetadata(MediaMetadata mediaMetadata)82 public void setMetadata(MediaMetadata mediaMetadata) { 83 this.mediaMetadata = mediaMetadata; 84 } 85 86 /** Gets the mediaMetadata set via {@link #setMetadata}. */ 87 @Implementation getMetadata()88 protected MediaMetadata getMetadata() { 89 return mediaMetadata; 90 } 91 92 /** 93 * Saves the rating type to control the return value of {@link MediaController#getRatingType()}. 94 */ setRatingType(int ratingType)95 public void setRatingType(int ratingType) { 96 if (ratingType >= 0 && ratingType <= Rating.RATING_PERCENTAGE) { 97 this.ratingType = ratingType; 98 } else { 99 throw new IllegalArgumentException( 100 "Invalid RatingType value " 101 + ratingType 102 + ". The valid range is from 0 to " 103 + Rating.RATING_PERCENTAGE); 104 } 105 } 106 107 /** Gets the rating type set via {@link #setRatingType}. */ 108 @Implementation getRatingType()109 protected int getRatingType() { 110 return ratingType; 111 } 112 113 /** 114 * Saves the sessionActivity to control the return value of {@link 115 * MediaController#getSessionActivity()}. 116 */ setSessionActivity(PendingIntent sessionActivity)117 public void setSessionActivity(PendingIntent sessionActivity) { 118 this.sessionActivity = sessionActivity; 119 } 120 121 /** Gets the playbackState set via {@link #setSessionActivity}. */ 122 @Implementation getSessionActivity()123 protected PendingIntent getSessionActivity() { 124 return sessionActivity; 125 } 126 127 /** Saves the extras to control the return value of {@link MediaController#getExtras()}. */ setExtras(Bundle extras)128 public void setExtras(Bundle extras) { 129 this.extras = extras; 130 } 131 132 /** Gets the extras set via {@link #extras}. */ 133 @Implementation getExtras()134 protected Bundle getExtras() { 135 return extras; 136 } 137 138 /** 139 * Register callback and store it in the shadow to make it easier to check the state of the 140 * registered callbacks. Handler is just passed on to the real class. 141 */ 142 @Implementation registerCallback(@onnull Callback callback, @Nullable Handler handler)143 protected void registerCallback(@Nonnull Callback callback, @Nullable Handler handler) { 144 callbacks.add(callback); 145 reflector(MediaControllerReflector.class, realMediaController) 146 .registerCallback(callback, handler); 147 } 148 149 /** 150 * Unregister callback and remove it from the shadow to make it easier to check the state of the 151 * registered callbacks. 152 */ 153 @Implementation unregisterCallback(@onnull Callback callback)154 protected void unregisterCallback(@Nonnull Callback callback) { 155 callbacks.remove(callback); 156 reflector(MediaControllerReflector.class, realMediaController).unregisterCallback(callback); 157 } 158 159 /** Gets the callbacks registered to MediaController. */ getCallbacks()160 public List<Callback> getCallbacks() { 161 return callbacks; 162 } 163 164 /** Executes all registered onPlaybackStateChanged callbacks. */ executeOnPlaybackStateChanged(PlaybackState playbackState)165 public void executeOnPlaybackStateChanged(PlaybackState playbackState) { 166 setPlaybackState(playbackState); 167 168 int messageId = 169 ReflectionHelpers.getStaticField(MediaController.class, "MSG_UPDATE_PLAYBACK_STATE"); 170 ReflectionHelpers.callInstanceMethod( 171 MediaController.class, 172 realMediaController, 173 "postMessage", 174 ClassParameter.from(int.class, messageId), 175 ClassParameter.from(Object.class, playbackState), 176 ClassParameter.from(Bundle.class, new Bundle())); 177 } 178 179 /** Executes all registered onSessionDestroyed callbacks. */ executeOnSessionDestroyed()180 public void executeOnSessionDestroyed() { 181 int messageId = ReflectionHelpers.getStaticField(MediaController.class, "MSG_DESTROYED"); 182 ReflectionHelpers.callInstanceMethod( 183 MediaController.class, 184 realMediaController, 185 "postMessage", 186 ClassParameter.from(int.class, messageId), 187 ClassParameter.from(Object.class, null), 188 ClassParameter.from(Bundle.class, null)); 189 } 190 191 /** Executes all registered onMetadataChanged callbacks. */ executeOnMetadataChanged(MediaMetadata metadata)192 public void executeOnMetadataChanged(MediaMetadata metadata) { 193 setMetadata(metadata); 194 195 int messageId = ReflectionHelpers.getStaticField(MediaController.class, "MSG_UPDATE_METADATA"); 196 ReflectionHelpers.callInstanceMethod( 197 MediaController.class, 198 realMediaController, 199 "postMessage", 200 ClassParameter.from(int.class, messageId), 201 ClassParameter.from(Object.class, metadata), 202 ClassParameter.from(Bundle.class, new Bundle())); 203 } 204 205 @ForType(MediaController.class) 206 interface MediaControllerReflector { 207 208 @Direct registerCallback(@onnull Callback callback, @Nullable Handler handler)209 void registerCallback(@Nonnull Callback callback, @Nullable Handler handler); 210 211 @Direct unregisterCallback(@onnull Callback callback)212 void unregisterCallback(@Nonnull Callback callback); 213 } 214 } 215