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 36 /** 37 * Provide a mockable interface in order to test classes that use MediaController. 38 * We need this class due to the fact that the MediaController class is marked as final and 39 * there is no way to currently mock final classes in Android. Once this is possible this class 40 * 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 /** 69 * Wrapper for MediaController.dispatchMediaButtonEvent(KeyEvent keyEvent) 70 */ dispatchMediaButtonEvent(@onNull KeyEvent keyEvent)71 public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) { 72 return mDelegate.dispatchMediaButtonEvent(keyEvent); 73 } 74 75 /** 76 * Wrapper for MediaController.getPlaybackState() 77 */ 78 @Nullable getPlaybackState()79 public PlaybackState getPlaybackState() { 80 return mDelegate.getPlaybackState(); 81 } 82 83 84 /** 85 * Wrapper for MediaController.getMetadata() 86 */ 87 @Nullable getMetadata()88 public MediaMetadata getMetadata() { 89 return mDelegate.getMetadata(); 90 } 91 92 /** 93 * Wrapper for MediaController.getQueue() 94 */ 95 @Nullable getQueue()96 public List<MediaSession.QueueItem> getQueue() { 97 return mDelegate.getQueue(); 98 } 99 100 /** 101 * Wrapper for MediaController.getQueueTitle() 102 */ 103 @Nullable getQueueTitle()104 public CharSequence getQueueTitle() { 105 return mDelegate.getQueueTitle(); 106 } 107 108 /** 109 * Wrapper for MediaController.getExtras() 110 */ 111 @Nullable getExtras()112 public Bundle getExtras() { 113 return mDelegate.getExtras(); 114 } 115 116 /** 117 * Wrapper for MediaController.getRatingType() 118 */ getRatingType()119 public int getRatingType() { 120 return mDelegate.getRatingType(); 121 } 122 123 /** 124 * Wrapper for MediaController.getFlags() 125 */ getFlags()126 public long getFlags() { 127 return mDelegate.getFlags(); 128 } 129 130 /** 131 * Wrapper for MediaController.getPlaybackInfo() 132 */ 133 @Nullable getPlaybackInfo()134 public android.media.session.MediaController.PlaybackInfo getPlaybackInfo() { 135 return mDelegate.getPlaybackInfo(); 136 } 137 138 139 /** 140 * Wrapper for MediaController.getSessionActivity() 141 */ 142 @Nullable getSessionActivity()143 public PendingIntent getSessionActivity() { 144 return mDelegate.getSessionActivity(); 145 } 146 147 /** 148 * Wrapper for MediaController.getSessionToken() 149 */ 150 @NonNull getSessionToken()151 public MediaSession.Token getSessionToken() { 152 return mDelegate.getSessionToken(); 153 } 154 155 /** 156 * Wrapper for MediaController.setVolumeTo(int value, int flags) 157 */ setVolumeTo(int value, int flags)158 public void setVolumeTo(int value, int flags) { 159 mDelegate.setVolumeTo(value, flags); 160 } 161 162 /** 163 * Wrapper for MediaController.adjustVolume(int direction, int flags) 164 */ adjustVolume(int direction, int flags)165 public void adjustVolume(int direction, int flags) { 166 mDelegate.adjustVolume(direction, flags); 167 } 168 169 /** 170 * Wrapper for MediaController.registerCallback(Callback callback) 171 */ registerCallback(@onNull Callback callback)172 public void registerCallback(@NonNull Callback callback) { 173 //TODO(apanicke): Add custom callback struct to be able to analyze and 174 // delegate callbacks 175 mDelegate.registerCallback(callback); 176 } 177 178 /** 179 * Wrapper for MediaController.registerCallback(Callback callback, Handler handler) 180 */ registerCallback(@onNull Callback callback, @Nullable Handler handler)181 public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) { 182 mDelegate.registerCallback(callback, handler); 183 } 184 185 /** 186 * Wrapper for MediaController.unregisterCallback(Callback callback) 187 */ unregisterCallback(@onNull Callback callback)188 public void unregisterCallback(@NonNull Callback callback) { 189 mDelegate.unregisterCallback(callback); 190 } 191 192 /** 193 * Wrapper for MediaController.sendCommand(String command, Bundle args, ResultReceiver cb) 194 */ sendCommand(@onNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb)195 public void sendCommand(@NonNull String command, @Nullable Bundle args, 196 @Nullable ResultReceiver cb) { 197 mDelegate.sendCommand(command, args, cb); 198 } 199 200 /** 201 * Wrapper for MediaController.getPackageName() 202 */ getPackageName()203 public String getPackageName() { 204 return mDelegate.getPackageName(); 205 } 206 207 /** 208 * Wrapper for MediaController.getTag() 209 */ getTag()210 public String getTag() { 211 return mDelegate.getTag(); 212 } 213 214 /** 215 * Wrapper for MediaController.controlsSameSession(MediaController other) 216 */ controlsSameSession(MediaController other)217 public boolean controlsSameSession(MediaController other) { 218 return mDelegate.getSessionToken().equals(other.getWrappedInstance().getSessionToken()); 219 } 220 221 /** 222 * Wrapper for MediaController.controlsSameSession(MediaController other) 223 */ controlsSameSession(android.media.session.MediaController other)224 public boolean controlsSameSession(android.media.session.MediaController other) { 225 return mDelegate.getSessionToken().equals(other.getSessionToken()); 226 } 227 228 /** 229 * Wrapper for MediaController.equals(Object other) 230 */ 231 @Override equals(Object o)232 public boolean equals(Object o) { 233 if (o instanceof android.media.session.MediaController) { 234 return mDelegate.equals(o); 235 } else if (o instanceof MediaController) { 236 MediaController other = (MediaController) o; 237 return mDelegate.equals(other.mDelegate); 238 } 239 return false; 240 } 241 242 /** 243 * Wrapper for MediaController.toString() 244 */ 245 @Override toString()246 public String toString() { 247 MediaMetadata data = getMetadata(); 248 MediaDescription desc = (data == null) ? null : data.getDescription(); 249 return "MediaController (" + getPackageName() + "@" + Integer.toHexString( 250 mDelegate.hashCode()) + ") " + desc; 251 } 252 253 /** 254 * Wrapper for MediaController.Callback 255 */ 256 public abstract static class Callback extends android.media.session.MediaController.Callback {} 257 258 /** 259 * Wrapper for MediaController.TransportControls 260 */ 261 public class TransportControls { 262 263 /** 264 * Wrapper for MediaController.TransportControls.prepare() 265 */ prepare()266 public void prepare() { 267 mTransportDelegate.prepare(); 268 } 269 270 /** 271 * Wrapper for MediaController.TransportControls.prepareFromMediaId() 272 */ prepareFromMediaId(String mediaId, Bundle extras)273 public void prepareFromMediaId(String mediaId, Bundle extras) { 274 mTransportDelegate.prepareFromMediaId(mediaId, extras); 275 } 276 277 /** 278 * Wrapper for MediaController.TransportControls.prepareFromSearch() 279 */ prepareFromSearch(String query, Bundle extras)280 public void prepareFromSearch(String query, Bundle extras) { 281 mTransportDelegate.prepareFromSearch(query, extras); 282 } 283 284 /** 285 * Wrapper for MediaController.TransportControls.prepareFromUri() 286 */ prepareFromUri(Uri uri, Bundle extras)287 public void prepareFromUri(Uri uri, Bundle extras) { 288 mTransportDelegate.prepareFromUri(uri, extras); 289 } 290 291 /** 292 * Wrapper for MediaController.TransportControls.play() 293 */ play()294 public void play() { 295 mTransportDelegate.play(); 296 } 297 298 /** 299 * Wrapper for MediaController.TransportControls.playFromMediaId() 300 */ playFromMediaId(String mediaId, Bundle extras)301 public void playFromMediaId(String mediaId, Bundle extras) { 302 mTransportDelegate.playFromMediaId(mediaId, extras); 303 } 304 305 /** 306 * Wrapper for MediaController.TransportControls.playFromSearch() 307 */ playFromSearch(String query, Bundle extras)308 public void playFromSearch(String query, Bundle extras) { 309 mTransportDelegate.playFromSearch(query, extras); 310 } 311 312 /** 313 * Wrapper for MediaController.TransportControls.playFromUri() 314 */ playFromUri(Uri uri, Bundle extras)315 public void playFromUri(Uri uri, Bundle extras) { 316 mTransportDelegate.playFromUri(uri, extras); 317 } 318 319 /** 320 * Wrapper for MediaController.TransportControls.skipToQueueItem() 321 */ skipToQueueItem(long id)322 public void skipToQueueItem(long id) { 323 mTransportDelegate.skipToQueueItem(id); 324 } 325 326 /** 327 * Wrapper for MediaController.TransportControls.pause() 328 */ pause()329 public void pause() { 330 mTransportDelegate.pause(); 331 } 332 333 /** 334 * Wrapper for MediaController.TransportControls.stop() 335 */ stop()336 public void stop() { 337 mTransportDelegate.stop(); 338 } 339 340 /** 341 * Wrapper for MediaController.TransportControls.seekTo() 342 */ seekTo(long pos)343 public void seekTo(long pos) { 344 mTransportDelegate.seekTo(pos); 345 } 346 347 /** 348 * Wrapper for MediaController.TransportControls.fastForward() 349 */ fastForward()350 public void fastForward() { 351 mTransportDelegate.fastForward(); 352 } 353 354 /** 355 * Wrapper for MediaController.TransportControls.skipToNext() 356 */ skipToNext()357 public void skipToNext() { 358 mTransportDelegate.skipToNext(); 359 } 360 361 /** 362 * Wrapper for MediaController.TransportControls.rewind() 363 */ rewind()364 public void rewind() { 365 mTransportDelegate.rewind(); 366 } 367 368 /** 369 * Wrapper for MediaController.TransportControls.skipToPrevious() 370 */ skipToPrevious()371 public void skipToPrevious() { 372 mTransportDelegate.skipToPrevious(); 373 } 374 375 /** 376 * Wrapper for MediaController.TransportControls.setRating() 377 */ setRating(Rating rating)378 public void setRating(Rating rating) { 379 mTransportDelegate.setRating(rating); 380 } 381 382 /** 383 * Wrapper for MediaController.TransportControls.sendCustomAction() 384 */ sendCustomAction(@onNull PlaybackState.CustomAction customAction, @Nullable Bundle args)385 public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction, 386 @Nullable Bundle args) { 387 mTransportDelegate.sendCustomAction(customAction, args); 388 } 389 390 /** 391 * Wrapper for MediaController.TransportControls.sendCustomAction() 392 */ sendCustomAction(@onNull String action, @Nullable Bundle args)393 public void sendCustomAction(@NonNull String action, @Nullable Bundle args) { 394 mTransportDelegate.sendCustomAction(action, args); 395 } 396 } 397 } 398 399