1 /*
2  * Copyright (C) 2014 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 android.support.v4.media.session;
18 
19 import android.app.PendingIntent;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.media.AudioAttributes;
23 import android.media.MediaDescription;
24 import android.media.MediaMetadata;
25 import android.media.Rating;
26 import android.media.VolumeProvider;
27 import android.media.session.MediaSession;
28 import android.media.session.PlaybackState;
29 import android.os.Bundle;
30 import android.os.Handler;
31 import android.os.Parcelable;
32 import android.os.ResultReceiver;
33 import android.util.Log;
34 
35 import androidx.annotation.RequiresApi;
36 
37 import java.lang.reflect.Field;
38 import java.util.ArrayList;
39 import java.util.List;
40 
41 @RequiresApi(21)
42 class MediaSessionCompatApi21 {
43     static final String TAG = "MediaSessionCompatApi21";
44 
createSession(Context context, String tag)45     public static Object createSession(Context context, String tag) {
46         return new MediaSession(context, tag);
47     }
48 
verifySession(Object mediaSession)49     public static Object verifySession(Object mediaSession) {
50         if (mediaSession instanceof MediaSession) {
51             return mediaSession;
52         }
53         throw new IllegalArgumentException("mediaSession is not a valid MediaSession object");
54     }
55 
verifyToken(Object token)56     public static Object verifyToken(Object token) {
57         if (token instanceof MediaSession.Token) {
58             return token;
59         }
60         throw new IllegalArgumentException("token is not a valid MediaSession.Token object");
61     }
62 
createCallback(Callback callback)63     public static Object createCallback(Callback callback) {
64         return new CallbackProxy<Callback>(callback);
65     }
66 
setCallback(Object sessionObj, Object callbackObj, Handler handler)67     public static void setCallback(Object sessionObj, Object callbackObj, Handler handler) {
68         ((MediaSession) sessionObj).setCallback((MediaSession.Callback) callbackObj, handler);
69     }
70 
setFlags(Object sessionObj, int flags)71     public static void setFlags(Object sessionObj, int flags) {
72         ((MediaSession)sessionObj).setFlags(flags);
73     }
74 
setPlaybackToLocal(Object sessionObj, int stream)75     public static void setPlaybackToLocal(Object sessionObj, int stream) {
76         // TODO update APIs to use support version of AudioAttributes
77         AudioAttributes.Builder bob = new AudioAttributes.Builder();
78         bob.setLegacyStreamType(stream);
79         ((MediaSession) sessionObj).setPlaybackToLocal(bob.build());
80     }
81 
setPlaybackToRemote(Object sessionObj, Object volumeProviderObj)82     public static void setPlaybackToRemote(Object sessionObj, Object volumeProviderObj) {
83         ((MediaSession)sessionObj).setPlaybackToRemote((VolumeProvider)volumeProviderObj);
84     }
85 
setActive(Object sessionObj, boolean active)86     public static void setActive(Object sessionObj, boolean active) {
87         ((MediaSession)sessionObj).setActive(active);
88     }
89 
isActive(Object sessionObj)90     public static boolean isActive(Object sessionObj) {
91         return ((MediaSession)sessionObj).isActive();
92     }
93 
sendSessionEvent(Object sessionObj, String event, Bundle extras)94     public static void sendSessionEvent(Object sessionObj, String event, Bundle extras) {
95         ((MediaSession)sessionObj).sendSessionEvent(event, extras);
96     }
97 
release(Object sessionObj)98     public static void release(Object sessionObj) {
99         ((MediaSession)sessionObj).release();
100     }
101 
getSessionToken(Object sessionObj)102     public static Parcelable getSessionToken(Object sessionObj) {
103         return ((MediaSession)sessionObj).getSessionToken();
104     }
105 
setPlaybackState(Object sessionObj, Object stateObj)106     public static void setPlaybackState(Object sessionObj, Object stateObj) {
107         ((MediaSession)sessionObj).setPlaybackState((PlaybackState)stateObj);
108     }
109 
setMetadata(Object sessionObj, Object metadataObj)110     public static void setMetadata(Object sessionObj, Object metadataObj) {
111         ((MediaSession)sessionObj).setMetadata((MediaMetadata)metadataObj);
112     }
113 
setSessionActivity(Object sessionObj, PendingIntent pi)114     public static void setSessionActivity(Object sessionObj, PendingIntent pi) {
115         ((MediaSession) sessionObj).setSessionActivity(pi);
116     }
117 
setMediaButtonReceiver(Object sessionObj, PendingIntent pi)118     public static void setMediaButtonReceiver(Object sessionObj, PendingIntent pi) {
119         ((MediaSession) sessionObj).setMediaButtonReceiver(pi);
120     }
121 
setQueue(Object sessionObj, List<Object> queueObjs)122     public static void setQueue(Object sessionObj, List<Object> queueObjs) {
123         if (queueObjs == null) {
124             ((MediaSession) sessionObj).setQueue(null);
125             return;
126         }
127         ArrayList<MediaSession.QueueItem> queue = new ArrayList<MediaSession.QueueItem>();
128         for (Object itemObj : queueObjs) {
129             queue.add((MediaSession.QueueItem) itemObj);
130         }
131         ((MediaSession) sessionObj).setQueue(queue);
132     }
133 
setQueueTitle(Object sessionObj, CharSequence title)134     public static void setQueueTitle(Object sessionObj, CharSequence title) {
135         ((MediaSession) sessionObj).setQueueTitle(title);
136     }
137 
setExtras(Object sessionObj, Bundle extras)138     public static void setExtras(Object sessionObj, Bundle extras) {
139         ((MediaSession) sessionObj).setExtras(extras);
140     }
141 
hasCallback(Object sessionObj)142     public static boolean hasCallback(Object sessionObj) {
143         Field callbackField = null;
144         try {
145             callbackField = sessionObj.getClass().getDeclaredField("mCallback");
146             if (callbackField != null) {
147                 callbackField.setAccessible(true);
148                 return callbackField.get(sessionObj) != null;
149             }
150         } catch (NoSuchFieldException | IllegalAccessException e) {
151             Log.w(TAG, "Failed to get mCallback object.");
152         }
153         return false;
154     }
155 
156     interface Callback {
onCommand(String command, Bundle extras, ResultReceiver cb)157         void onCommand(String command, Bundle extras, ResultReceiver cb);
onMediaButtonEvent(Intent mediaButtonIntent)158         boolean onMediaButtonEvent(Intent mediaButtonIntent);
onPlay()159         void onPlay();
onPlayFromMediaId(String mediaId, Bundle extras)160         void onPlayFromMediaId(String mediaId, Bundle extras);
onPlayFromSearch(String search, Bundle extras)161         void onPlayFromSearch(String search, Bundle extras);
onSkipToQueueItem(long id)162         void onSkipToQueueItem(long id);
onPause()163         void onPause();
onSkipToNext()164         void onSkipToNext();
onSkipToPrevious()165         void onSkipToPrevious();
onFastForward()166         void onFastForward();
onRewind()167         void onRewind();
onStop()168         void onStop();
onSeekTo(long position)169         void onSeekTo(long position);
onSetRating(Object ratingObject)170         void onSetRating(Object ratingObject);
onSetRating(Object ratingObject, Bundle extras)171         void onSetRating(Object ratingObject, Bundle extras);
onCustomAction(String action, Bundle extras)172         void onCustomAction(String action, Bundle extras);
173     }
174 
175     static class CallbackProxy<T extends Callback> extends MediaSession.Callback {
176         protected final T mCallback;
177 
CallbackProxy(T callback)178         public CallbackProxy(T callback) {
179             mCallback = callback;
180         }
181 
182         @Override
onCommand(String command, Bundle args, ResultReceiver cb)183         public void onCommand(String command, Bundle args, ResultReceiver cb) {
184             mCallback.onCommand(command, args, cb);
185         }
186 
187         @Override
onMediaButtonEvent(Intent mediaButtonIntent)188         public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
189             return mCallback.onMediaButtonEvent(mediaButtonIntent)
190                     || super.onMediaButtonEvent(mediaButtonIntent);
191         }
192 
193         @Override
onPlay()194         public void onPlay() {
195             mCallback.onPlay();
196         }
197 
198         @Override
onPlayFromMediaId(String mediaId, Bundle extras)199         public void onPlayFromMediaId(String mediaId, Bundle extras) {
200             mCallback.onPlayFromMediaId(mediaId, extras);
201         }
202 
203         @Override
onPlayFromSearch(String search, Bundle extras)204         public void onPlayFromSearch(String search, Bundle extras) {
205             mCallback.onPlayFromSearch(search, extras);
206         }
207 
208         @Override
onSkipToQueueItem(long id)209         public void onSkipToQueueItem(long id) {
210             mCallback.onSkipToQueueItem(id);
211         }
212 
213         @Override
onPause()214         public void onPause() {
215             mCallback.onPause();
216         }
217 
218         @Override
onSkipToNext()219         public void onSkipToNext() {
220             mCallback.onSkipToNext();
221         }
222 
223         @Override
onSkipToPrevious()224         public void onSkipToPrevious() {
225             mCallback.onSkipToPrevious();
226         }
227 
228         @Override
onFastForward()229         public void onFastForward() {
230             mCallback.onFastForward();
231         }
232 
233         @Override
onRewind()234         public void onRewind() {
235             mCallback.onRewind();
236         }
237 
238         @Override
onStop()239         public void onStop() {
240             mCallback.onStop();
241         }
242 
243         @Override
onSeekTo(long pos)244         public void onSeekTo(long pos) {
245             mCallback.onSeekTo(pos);
246         }
247 
248         @Override
onSetRating(Rating rating)249         public void onSetRating(Rating rating) {
250             mCallback.onSetRating(rating);
251         }
252 
253         @Override
onCustomAction(String action, Bundle extras)254         public void onCustomAction(String action, Bundle extras) {
255             mCallback.onCustomAction(action, extras);
256         }
257     }
258 
259     static class QueueItem {
260 
createItem(Object mediaDescription, long id)261         public static Object createItem(Object mediaDescription, long id) {
262             return new MediaSession.QueueItem((MediaDescription) mediaDescription, id);
263         }
264 
getDescription(Object queueItem)265         public static Object getDescription(Object queueItem) {
266             return ((MediaSession.QueueItem) queueItem).getDescription();
267         }
268 
getQueueId(Object queueItem)269         public static long getQueueId(Object queueItem) {
270             return ((MediaSession.QueueItem) queueItem).getQueueId();
271         }
272 
QueueItem()273         private QueueItem() {
274         }
275     }
276 
MediaSessionCompatApi21()277     private MediaSessionCompatApi21() {
278     }
279 }
280