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