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
17package android.support.v4.media.session;
18
19import android.app.PendingIntent;
20import android.content.Context;
21import android.content.Intent;
22import android.media.AudioAttributes;
23import android.media.MediaDescription;
24import android.media.MediaMetadata;
25import android.media.Rating;
26import android.media.VolumeProvider;
27import android.media.session.MediaSession;
28import android.media.session.PlaybackState;
29import android.os.Bundle;
30import android.os.Handler;
31import android.os.Parcelable;
32import android.os.ResultReceiver;
33import android.util.Log;
34
35import androidx.annotation.RequiresApi;
36
37import java.lang.reflect.Field;
38import java.util.ArrayList;
39import java.util.List;
40
41@RequiresApi(21)
42class MediaSessionCompatApi21 {
43    static final String TAG = "MediaSessionCompatApi21";
44
45    public static Object createSession(Context context, String tag) {
46        return new MediaSession(context, tag);
47    }
48
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
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
63    public static Object createCallback(Callback callback) {
64        return new CallbackProxy<Callback>(callback);
65    }
66
67    public static void setCallback(Object sessionObj, Object callbackObj, Handler handler) {
68        ((MediaSession) sessionObj).setCallback((MediaSession.Callback) callbackObj, handler);
69    }
70
71    public static void setFlags(Object sessionObj, int flags) {
72        ((MediaSession)sessionObj).setFlags(flags);
73    }
74
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
82    public static void setPlaybackToRemote(Object sessionObj, Object volumeProviderObj) {
83        ((MediaSession)sessionObj).setPlaybackToRemote((VolumeProvider)volumeProviderObj);
84    }
85
86    public static void setActive(Object sessionObj, boolean active) {
87        ((MediaSession)sessionObj).setActive(active);
88    }
89
90    public static boolean isActive(Object sessionObj) {
91        return ((MediaSession)sessionObj).isActive();
92    }
93
94    public static void sendSessionEvent(Object sessionObj, String event, Bundle extras) {
95        ((MediaSession)sessionObj).sendSessionEvent(event, extras);
96    }
97
98    public static void release(Object sessionObj) {
99        ((MediaSession)sessionObj).release();
100    }
101
102    public static Parcelable getSessionToken(Object sessionObj) {
103        return ((MediaSession)sessionObj).getSessionToken();
104    }
105
106    public static void setPlaybackState(Object sessionObj, Object stateObj) {
107        ((MediaSession)sessionObj).setPlaybackState((PlaybackState)stateObj);
108    }
109
110    public static void setMetadata(Object sessionObj, Object metadataObj) {
111        ((MediaSession)sessionObj).setMetadata((MediaMetadata)metadataObj);
112    }
113
114    public static void setSessionActivity(Object sessionObj, PendingIntent pi) {
115        ((MediaSession) sessionObj).setSessionActivity(pi);
116    }
117
118    public static void setMediaButtonReceiver(Object sessionObj, PendingIntent pi) {
119        ((MediaSession) sessionObj).setMediaButtonReceiver(pi);
120    }
121
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
134    public static void setQueueTitle(Object sessionObj, CharSequence title) {
135        ((MediaSession) sessionObj).setQueueTitle(title);
136    }
137
138    public static void setExtras(Object sessionObj, Bundle extras) {
139        ((MediaSession) sessionObj).setExtras(extras);
140    }
141
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 {
157        void onCommand(String command, Bundle extras, ResultReceiver cb);
158        boolean onMediaButtonEvent(Intent mediaButtonIntent);
159        void onPlay();
160        void onPlayFromMediaId(String mediaId, Bundle extras);
161        void onPlayFromSearch(String search, Bundle extras);
162        void onSkipToQueueItem(long id);
163        void onPause();
164        void onSkipToNext();
165        void onSkipToPrevious();
166        void onFastForward();
167        void onRewind();
168        void onStop();
169        void onSeekTo(long position);
170        void onSetRating(Object ratingObject);
171        void onSetRating(Object ratingObject, 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
178        public CallbackProxy(T callback) {
179            mCallback = callback;
180        }
181
182        @Override
183        public void onCommand(String command, Bundle args, ResultReceiver cb) {
184            mCallback.onCommand(command, args, cb);
185        }
186
187        @Override
188        public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
189            return mCallback.onMediaButtonEvent(mediaButtonIntent)
190                    || super.onMediaButtonEvent(mediaButtonIntent);
191        }
192
193        @Override
194        public void onPlay() {
195            mCallback.onPlay();
196        }
197
198        @Override
199        public void onPlayFromMediaId(String mediaId, Bundle extras) {
200            mCallback.onPlayFromMediaId(mediaId, extras);
201        }
202
203        @Override
204        public void onPlayFromSearch(String search, Bundle extras) {
205            mCallback.onPlayFromSearch(search, extras);
206        }
207
208        @Override
209        public void onSkipToQueueItem(long id) {
210            mCallback.onSkipToQueueItem(id);
211        }
212
213        @Override
214        public void onPause() {
215            mCallback.onPause();
216        }
217
218        @Override
219        public void onSkipToNext() {
220            mCallback.onSkipToNext();
221        }
222
223        @Override
224        public void onSkipToPrevious() {
225            mCallback.onSkipToPrevious();
226        }
227
228        @Override
229        public void onFastForward() {
230            mCallback.onFastForward();
231        }
232
233        @Override
234        public void onRewind() {
235            mCallback.onRewind();
236        }
237
238        @Override
239        public void onStop() {
240            mCallback.onStop();
241        }
242
243        @Override
244        public void onSeekTo(long pos) {
245            mCallback.onSeekTo(pos);
246        }
247
248        @Override
249        public void onSetRating(Rating rating) {
250            mCallback.onSetRating(rating);
251        }
252
253        @Override
254        public void onCustomAction(String action, Bundle extras) {
255            mCallback.onCustomAction(action, extras);
256        }
257    }
258
259    static class QueueItem {
260
261        public static Object createItem(Object mediaDescription, long id) {
262            return new MediaSession.QueueItem((MediaDescription) mediaDescription, id);
263        }
264
265        public static Object getDescription(Object queueItem) {
266            return ((MediaSession.QueueItem) queueItem).getDescription();
267        }
268
269        public static long getQueueId(Object queueItem) {
270            return ((MediaSession.QueueItem) queueItem).getQueueId();
271        }
272
273        private QueueItem() {
274        }
275    }
276
277    private MediaSessionCompatApi21() {
278    }
279}
280