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 17package com.android.bluetooth.avrcp; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.app.PendingIntent; 22import android.content.Context; 23import android.media.MediaDescription; 24import android.media.MediaMetadata; 25import android.media.Rating; 26import android.media.session.MediaSession; 27import android.media.session.PlaybackState; 28import android.net.Uri; 29import android.os.Bundle; 30import android.os.Handler; 31import android.os.ResultReceiver; 32import android.view.KeyEvent; 33 34import 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 */ 42public class MediaController { 43 @NonNull public android.media.session.MediaController mDelegate; 44 public android.media.session.MediaController.TransportControls mTransportDelegate; 45 public TransportControls mTransportControls; 46 47 public MediaController(@NonNull android.media.session.MediaController delegate) { 48 mDelegate = delegate; 49 mTransportDelegate = delegate.getTransportControls(); 50 mTransportControls = new TransportControls(); 51 } 52 53 public 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 59 public android.media.session.MediaController getWrappedInstance() { 60 return mDelegate; 61 } 62 63 @NonNull 64 public TransportControls getTransportControls() { 65 return mTransportControls; 66 } 67 68 public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) { 69 return mDelegate.dispatchMediaButtonEvent(keyEvent); 70 } 71 72 @Nullable 73 public PlaybackState getPlaybackState() { 74 return mDelegate.getPlaybackState(); 75 } 76 77 @Nullable 78 public MediaMetadata getMetadata() { 79 return mDelegate.getMetadata(); 80 } 81 82 @Nullable 83 public List<MediaSession.QueueItem> getQueue() { 84 return mDelegate.getQueue(); 85 } 86 87 @Nullable 88 public CharSequence getQueueTitle() { 89 return mDelegate.getQueueTitle(); 90 } 91 92 @Nullable 93 public Bundle getExtras() { 94 return mDelegate.getExtras(); 95 } 96 97 public int getRatingType() { 98 return mDelegate.getRatingType(); 99 } 100 101 public long getFlags() { 102 return mDelegate.getFlags(); 103 } 104 105 @Nullable 106 public android.media.session.MediaController.PlaybackInfo getPlaybackInfo() { 107 return mDelegate.getPlaybackInfo(); 108 } 109 110 @Nullable 111 public PendingIntent getSessionActivity() { 112 return mDelegate.getSessionActivity(); 113 } 114 115 @NonNull 116 public MediaSession.Token getSessionToken() { 117 return mDelegate.getSessionToken(); 118 } 119 120 public void setVolumeTo(int value, int flags) { 121 mDelegate.setVolumeTo(value, flags); 122 } 123 124 public void adjustVolume(int direction, int flags) { 125 mDelegate.adjustVolume(direction, flags); 126 } 127 128 public void registerCallback(@NonNull Callback callback) { 129 //TODO(apanicke): Add custom callback struct to be able to analyze and 130 // delegate callbacks 131 mDelegate.registerCallback(callback); 132 } 133 134 public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) { 135 mDelegate.registerCallback(callback, handler); 136 } 137 138 public void unregisterCallback(@NonNull Callback callback) { 139 mDelegate.unregisterCallback(callback); 140 } 141 142 public void sendCommand(@NonNull String command, @Nullable Bundle args, 143 @Nullable ResultReceiver cb) { 144 mDelegate.sendCommand(command, args, cb); 145 } 146 147 public String getPackageName() { 148 return mDelegate.getPackageName(); 149 } 150 151 public String getTag() { 152 return mDelegate.getTag(); 153 } 154 155 public boolean controlsSameSession(MediaController other) { 156 return mDelegate.controlsSameSession(other.getWrappedInstance()); 157 } 158 159 public boolean controlsSameSession(android.media.session.MediaController other) { 160 return mDelegate.controlsSameSession(other); 161 } 162 163 @Override 164 public boolean equals(Object o) { 165 if (o instanceof android.media.session.MediaController) { 166 return mDelegate.equals(o); 167 } else if (o instanceof MediaController) { 168 MediaController other = (MediaController) o; 169 return mDelegate.equals(other.mDelegate); 170 } 171 return false; 172 } 173 174 @Override 175 public String toString() { 176 MediaMetadata data = getMetadata(); 177 MediaDescription desc = (data == null) ? null : data.getDescription(); 178 return "MediaController (" + getPackageName() + "@" + Integer.toHexString( 179 mDelegate.hashCode()) + ") " + desc; 180 } 181 182 public abstract static class Callback extends android.media.session.MediaController.Callback {} 183 184 public class TransportControls { 185 186 public void prepare() { 187 mTransportDelegate.prepare(); 188 } 189 190 public void prepareFromMediaId(String mediaId, Bundle extras) { 191 mTransportDelegate.prepareFromMediaId(mediaId, extras); 192 } 193 194 public void prepareFromSearch(String query, Bundle extras) { 195 mTransportDelegate.prepareFromSearch(query, extras); 196 } 197 198 public void prepareFromUri(Uri uri, Bundle extras) { 199 mTransportDelegate.prepareFromUri(uri, extras); 200 } 201 202 public void play() { 203 mTransportDelegate.play(); 204 } 205 206 public void playFromMediaId(String mediaId, Bundle extras) { 207 mTransportDelegate.playFromMediaId(mediaId, extras); 208 } 209 210 public void playFromSearch(String query, Bundle extras) { 211 mTransportDelegate.playFromSearch(query, extras); 212 } 213 214 public void playFromUri(Uri uri, Bundle extras) { 215 mTransportDelegate.playFromUri(uri, extras); 216 } 217 218 public void skipToQueueItem(long id) { 219 mTransportDelegate.skipToQueueItem(id); 220 } 221 222 public void pause() { 223 mTransportDelegate.pause(); 224 } 225 226 public void stop() { 227 mTransportDelegate.stop(); 228 } 229 230 public void seekTo(long pos) { 231 mTransportDelegate.seekTo(pos); 232 } 233 234 public void fastForward() { 235 mTransportDelegate.fastForward(); 236 } 237 238 public void skipToNext() { 239 mTransportDelegate.skipToNext(); 240 } 241 242 public void rewind() { 243 mTransportDelegate.rewind(); 244 } 245 246 public void skipToPrevious() { 247 mTransportDelegate.skipToPrevious(); 248 } 249 250 public void setRating(Rating rating) { 251 mTransportDelegate.setRating(rating); 252 } 253 254 public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction, 255 @Nullable Bundle args) { 256 mTransportDelegate.sendCustomAction(customAction, args); 257 } 258 259 public void sendCustomAction(@NonNull String action, @Nullable Bundle args) { 260 mTransportDelegate.sendCustomAction(action, args); 261 } 262 } 263} 264 265