1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.audio_util; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.PendingIntent; 22 import android.content.Context; 23 import android.media.MediaDescription; 24 import android.media.MediaMetadata; 25 import android.media.Rating; 26 import android.media.session.MediaSession; 27 import android.media.session.PlaybackState; 28 import android.net.Uri; 29 import android.os.Bundle; 30 import android.os.Handler; 31 import android.os.ResultReceiver; 32 import android.view.KeyEvent; 33 34 import java.util.List; 35 import java.util.Objects; 36 37 /** 38 * Provide a mockable interface in order to test classes that use MediaController. We need this 39 * class due to the fact that the MediaController class is marked as final and there is no way to 40 * currently mock final classes in Android. Once this is possible this class can be deleted. 41 */ 42 public class MediaController { 43 @NonNull public android.media.session.MediaController mDelegate; 44 public android.media.session.MediaController.TransportControls mTransportDelegate; 45 public TransportControls mTransportControls; 46 MediaController(@onNull android.media.session.MediaController delegate)47 MediaController(@NonNull android.media.session.MediaController delegate) { 48 mDelegate = delegate; 49 mTransportDelegate = delegate.getTransportControls(); 50 mTransportControls = new TransportControls(); 51 } 52 MediaController(Context context, MediaSession.Token token)53 MediaController(Context context, MediaSession.Token token) { 54 mDelegate = new android.media.session.MediaController(context, token); 55 mTransportDelegate = mDelegate.getTransportControls(); 56 mTransportControls = new TransportControls(); 57 } 58 getWrappedInstance()59 public android.media.session.MediaController getWrappedInstance() { 60 return mDelegate; 61 } 62 63 @NonNull getTransportControls()64 public TransportControls getTransportControls() { 65 return mTransportControls; 66 } 67 68 /** Wrapper for MediaController.dispatchMediaButtonEvent(KeyEvent keyEvent) */ dispatchMediaButtonEvent(@onNull KeyEvent keyEvent)69 public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) { 70 return mDelegate.dispatchMediaButtonEvent(keyEvent); 71 } 72 73 /** Wrapper for MediaController.getPlaybackState() */ 74 @Nullable getPlaybackState()75 public PlaybackState getPlaybackState() { 76 return mDelegate.getPlaybackState(); 77 } 78 79 /** Wrapper for MediaController.getMetadata() */ 80 @Nullable getMetadata()81 public MediaMetadata getMetadata() { 82 return mDelegate.getMetadata(); 83 } 84 85 /** Wrapper for MediaController.getQueue() */ 86 @Nullable getQueue()87 public List<MediaSession.QueueItem> getQueue() { 88 return mDelegate.getQueue(); 89 } 90 91 /** Wrapper for MediaController.getQueueTitle() */ 92 @Nullable getQueueTitle()93 public CharSequence getQueueTitle() { 94 return mDelegate.getQueueTitle(); 95 } 96 97 /** Wrapper for MediaController.getExtras() */ 98 @Nullable getExtras()99 public Bundle getExtras() { 100 return mDelegate.getExtras(); 101 } 102 103 /** Wrapper for MediaController.getRatingType() */ getRatingType()104 public int getRatingType() { 105 return mDelegate.getRatingType(); 106 } 107 108 /** Wrapper for MediaController.getFlags() */ getFlags()109 public long getFlags() { 110 return mDelegate.getFlags(); 111 } 112 113 /** Wrapper for MediaController.getPlaybackInfo() */ 114 @Nullable getPlaybackInfo()115 public android.media.session.MediaController.PlaybackInfo getPlaybackInfo() { 116 return mDelegate.getPlaybackInfo(); 117 } 118 119 /** Wrapper for MediaController.getSessionActivity() */ 120 @Nullable getSessionActivity()121 public PendingIntent getSessionActivity() { 122 return mDelegate.getSessionActivity(); 123 } 124 125 /** Wrapper for MediaController.getSessionToken() */ 126 @NonNull getSessionToken()127 public MediaSession.Token getSessionToken() { 128 return mDelegate.getSessionToken(); 129 } 130 131 /** Wrapper for MediaController.setVolumeTo(int value, int flags) */ setVolumeTo(int value, int flags)132 public void setVolumeTo(int value, int flags) { 133 mDelegate.setVolumeTo(value, flags); 134 } 135 136 /** Wrapper for MediaController.adjustVolume(int direction, int flags) */ adjustVolume(int direction, int flags)137 public void adjustVolume(int direction, int flags) { 138 mDelegate.adjustVolume(direction, flags); 139 } 140 141 /** Wrapper for MediaController.registerCallback(Callback callback) */ registerCallback(@onNull Callback callback)142 public void registerCallback(@NonNull Callback callback) { 143 // TODO(apanicke): Add custom callback struct to be able to analyze and 144 // delegate callbacks 145 mDelegate.registerCallback(callback); 146 } 147 148 /** Wrapper for MediaController.registerCallback(Callback callback, Handler handler) */ registerCallback(@onNull Callback callback, @Nullable Handler handler)149 public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) { 150 mDelegate.registerCallback(callback, handler); 151 } 152 153 /** Wrapper for MediaController.unregisterCallback(Callback callback) */ unregisterCallback(@onNull Callback callback)154 public void unregisterCallback(@NonNull Callback callback) { 155 mDelegate.unregisterCallback(callback); 156 } 157 158 /** Wrapper for MediaController.sendCommand(String command, Bundle args, ResultReceiver cb) */ sendCommand( @onNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb)159 public void sendCommand( 160 @NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) { 161 mDelegate.sendCommand(command, args, cb); 162 } 163 164 /** Wrapper for MediaController.getPackageName() */ getPackageName()165 public String getPackageName() { 166 return mDelegate.getPackageName(); 167 } 168 169 /** Wrapper for MediaController.getTag() */ getTag()170 public String getTag() { 171 return mDelegate.getTag(); 172 } 173 174 /** Wrapper for MediaController.controlsSameSession(MediaController other) */ controlsSameSession(MediaController other)175 public boolean controlsSameSession(MediaController other) { 176 return mDelegate.getSessionToken().equals(other.getWrappedInstance().getSessionToken()); 177 } 178 179 /** Wrapper for MediaController.controlsSameSession(MediaController other) */ controlsSameSession(android.media.session.MediaController other)180 public boolean controlsSameSession(android.media.session.MediaController other) { 181 return mDelegate.getSessionToken().equals(other.getSessionToken()); 182 } 183 184 /** Wrapper for MediaController.equals(Object other) */ 185 @Override equals(Object o)186 public boolean equals(Object o) { 187 if (o instanceof android.media.session.MediaController) { 188 return mDelegate.equals(o); 189 } else if (o instanceof MediaController) { 190 MediaController other = (MediaController) o; 191 return mDelegate.equals(other.mDelegate); 192 } 193 return false; 194 } 195 196 /** Wrapper for MediaController.hashCode() */ 197 @Override hashCode()198 public int hashCode() { 199 return Objects.hash(mDelegate); 200 } 201 202 /** Wrapper for MediaController.toString() */ 203 @Override toString()204 public String toString() { 205 MediaMetadata data = getMetadata(); 206 MediaDescription desc = (data == null) ? null : data.getDescription(); 207 return "MediaController (" 208 + getPackageName() 209 + "@" 210 + Integer.toHexString(mDelegate.hashCode()) 211 + ") " 212 + desc; 213 } 214 215 /** Wrapper for MediaController.Callback */ 216 public abstract static class Callback extends android.media.session.MediaController.Callback {} 217 218 /** Wrapper for MediaController.TransportControls */ 219 public class TransportControls { 220 221 /** Wrapper for MediaController.TransportControls.prepare() */ prepare()222 public void prepare() { 223 mTransportDelegate.prepare(); 224 } 225 226 /** Wrapper for MediaController.TransportControls.prepareFromMediaId() */ prepareFromMediaId(String mediaId, Bundle extras)227 public void prepareFromMediaId(String mediaId, Bundle extras) { 228 mTransportDelegate.prepareFromMediaId(mediaId, extras); 229 } 230 231 /** Wrapper for MediaController.TransportControls.prepareFromSearch() */ prepareFromSearch(String query, Bundle extras)232 public void prepareFromSearch(String query, Bundle extras) { 233 mTransportDelegate.prepareFromSearch(query, extras); 234 } 235 236 /** Wrapper for MediaController.TransportControls.prepareFromUri() */ prepareFromUri(Uri uri, Bundle extras)237 public void prepareFromUri(Uri uri, Bundle extras) { 238 mTransportDelegate.prepareFromUri(uri, extras); 239 } 240 241 /** Wrapper for MediaController.TransportControls.play() */ play()242 public void play() { 243 mTransportDelegate.play(); 244 } 245 246 /** Wrapper for MediaController.TransportControls.playFromMediaId() */ playFromMediaId(String mediaId, Bundle extras)247 public void playFromMediaId(String mediaId, Bundle extras) { 248 mTransportDelegate.playFromMediaId(mediaId, extras); 249 } 250 251 /** Wrapper for MediaController.TransportControls.playFromSearch() */ playFromSearch(String query, Bundle extras)252 public void playFromSearch(String query, Bundle extras) { 253 mTransportDelegate.playFromSearch(query, extras); 254 } 255 256 /** Wrapper for MediaController.TransportControls.playFromUri() */ playFromUri(Uri uri, Bundle extras)257 public void playFromUri(Uri uri, Bundle extras) { 258 mTransportDelegate.playFromUri(uri, extras); 259 } 260 261 /** Wrapper for MediaController.TransportControls.skipToQueueItem() */ skipToQueueItem(long id)262 public void skipToQueueItem(long id) { 263 mTransportDelegate.skipToQueueItem(id); 264 } 265 266 /** Wrapper for MediaController.TransportControls.pause() */ pause()267 public void pause() { 268 mTransportDelegate.pause(); 269 } 270 271 /** Wrapper for MediaController.TransportControls.stop() */ stop()272 public void stop() { 273 mTransportDelegate.stop(); 274 } 275 276 /** Wrapper for MediaController.TransportControls.seekTo() */ seekTo(long pos)277 public void seekTo(long pos) { 278 mTransportDelegate.seekTo(pos); 279 } 280 281 /** Wrapper for MediaController.TransportControls.fastForward() */ fastForward()282 public void fastForward() { 283 mTransportDelegate.fastForward(); 284 } 285 286 /** Wrapper for MediaController.TransportControls.skipToNext() */ skipToNext()287 public void skipToNext() { 288 mTransportDelegate.skipToNext(); 289 } 290 291 /** Wrapper for MediaController.TransportControls.rewind() */ rewind()292 public void rewind() { 293 mTransportDelegate.rewind(); 294 } 295 296 /** Wrapper for MediaController.TransportControls.skipToPrevious() */ skipToPrevious()297 public void skipToPrevious() { 298 mTransportDelegate.skipToPrevious(); 299 } 300 301 /** Wrapper for MediaController.TransportControls.setRating() */ setRating(Rating rating)302 public void setRating(Rating rating) { 303 mTransportDelegate.setRating(rating); 304 } 305 306 /** Wrapper for MediaController.TransportControls.setPlaybackSpeed(float speed) */ setPlaybackSpeed(float speed)307 public void setPlaybackSpeed(float speed) { 308 mTransportDelegate.setPlaybackSpeed(speed); 309 } 310 311 /** Wrapper for MediaController.TransportControls.sendCustomAction() */ sendCustomAction( @onNull PlaybackState.CustomAction customAction, @Nullable Bundle args)312 public void sendCustomAction( 313 @NonNull PlaybackState.CustomAction customAction, @Nullable Bundle args) { 314 mTransportDelegate.sendCustomAction(customAction, args); 315 } 316 317 /** Wrapper for MediaController.TransportControls.sendCustomAction() */ sendCustomAction(@onNull String action, @Nullable Bundle args)318 public void sendCustomAction(@NonNull String action, @Nullable Bundle args) { 319 mTransportDelegate.sendCustomAction(action, args); 320 } 321 } 322 } 323