MediaSessionManager.java revision 8b4bffcac996b4083e720310a09d315ca1c4a000
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.media.session;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.content.ComponentName;
22import android.content.Context;
23import android.media.IRemoteVolumeController;
24import android.media.session.ISessionManager;
25import android.os.IBinder;
26import android.os.RemoteException;
27import android.os.ServiceManager;
28import android.os.UserHandle;
29import android.service.notification.NotificationListenerService;
30import android.text.TextUtils;
31import android.util.Log;
32import android.view.KeyEvent;
33
34import java.util.ArrayList;
35import java.util.List;
36
37/**
38 * Provides support for interacting with {@link MediaSession media sessions}
39 * that applications have published to express their ongoing media playback state.
40 * <p>
41 * Use <code>Context.getSystemService(Context.MEDIA_SESSION_SERVICE)</code> to
42 * get an instance of this class.
43 * <p>
44 *
45 * @see MediaSession
46 * @see MediaController
47 */
48public final class MediaSessionManager {
49    private static final String TAG = "SessionManager";
50
51    private final ISessionManager mService;
52
53    private Context mContext;
54
55    /**
56     * @hide
57     */
58    public MediaSessionManager(Context context) {
59        // Consider rewriting like DisplayManagerGlobal
60        // Decide if we need context
61        mContext = context;
62        IBinder b = ServiceManager.getService(Context.MEDIA_SESSION_SERVICE);
63        mService = ISessionManager.Stub.asInterface(b);
64    }
65
66    /**
67     * Create a new session in the system and get the binder for it.
68     *
69     * @param tag A short name for debugging purposes.
70     * @return The binder object from the system
71     * @hide
72     */
73    public @NonNull ISession createSession(@NonNull MediaSession.CallbackStub cbStub,
74            @NonNull String tag, int userId) throws RemoteException {
75        return mService.createSession(mContext.getPackageName(), cbStub, tag, userId);
76    }
77
78    /**
79     * Get a list of controllers for all ongoing sessions. The controllers will
80     * be provided in priority order with the most important controller at index
81     * 0.
82     * <p>
83     * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL
84     * permission be held by the calling app. You may also retrieve this list if
85     * your app is an enabled notification listener using the
86     * {@link NotificationListenerService} APIs, in which case you must pass the
87     * {@link ComponentName} of your enabled listener.
88     *
89     * @param notificationListener The enabled notification listener component.
90     *            May be null.
91     * @return A list of controllers for ongoing sessions.
92     */
93    public @NonNull List<MediaController> getActiveSessions(
94            @Nullable ComponentName notificationListener) {
95        return getActiveSessionsForUser(notificationListener, UserHandle.myUserId());
96    }
97
98    /**
99     * Get active sessions for a specific user. To retrieve actions for a user
100     * other than your own you must hold the
101     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission
102     * in addition to any other requirements. If you are an enabled notification
103     * listener you may only get sessions for the users you are enabled for.
104     *
105     * @param notificationListener The enabled notification listener component.
106     *            May be null.
107     * @param userId The user id to fetch sessions for.
108     * @return A list of controllers for ongoing sessions.
109     * @hide
110     */
111    public @NonNull List<MediaController> getActiveSessionsForUser(
112            @Nullable ComponentName notificationListener, int userId) {
113        ArrayList<MediaController> controllers = new ArrayList<MediaController>();
114        try {
115            List<IBinder> binders = mService.getSessions(notificationListener, userId);
116            int size = binders.size();
117            for (int i = 0; i < size; i++) {
118                MediaController controller = new MediaController(ISessionController.Stub
119                        .asInterface(binders.get(i)));
120                controllers.add(controller);
121            }
122        } catch (RemoteException e) {
123            Log.e(TAG, "Failed to get active sessions: ", e);
124        }
125        return controllers;
126    }
127
128    /**
129     * Add a listener to be notified when the list of active sessions
130     * changes.This requires the
131     * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
132     * the calling app. You may also retrieve this list if your app is an
133     * enabled notification listener using the
134     * {@link NotificationListenerService} APIs, in which case you must pass the
135     * {@link ComponentName} of your enabled listener.
136     *
137     * @param sessionListener The listener to add.
138     * @param notificationListener The enabled notification listener component.
139     *            May be null.
140     */
141    public void addActiveSessionsListener(SessionListener sessionListener,
142            ComponentName notificationListener) {
143        addActiveSessionsListener(sessionListener, notificationListener, UserHandle.myUserId());
144    }
145
146    /**
147     * Add a listener to be notified when the list of active sessions
148     * changes.This requires the
149     * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
150     * the calling app. You may also retrieve this list if your app is an
151     * enabled notification listener using the
152     * {@link NotificationListenerService} APIs, in which case you must pass the
153     * {@link ComponentName} of your enabled listener.
154     *
155     * @param sessionListener The listener to add.
156     * @param notificationListener The enabled notification listener component.
157     *            May be null.
158     * @param userId The userId to listen for changes on.
159     * @hide
160     */
161    public void addActiveSessionsListener(@NonNull SessionListener sessionListener,
162            @Nullable ComponentName notificationListener, int userId) {
163        if (sessionListener == null) {
164            throw new IllegalArgumentException("listener may not be null");
165        }
166        try {
167            mService.addSessionsListener(sessionListener.mStub, notificationListener, userId);
168        } catch (RemoteException e) {
169            Log.e(TAG, "Error in addActiveSessionsListener.", e);
170        }
171    }
172
173    /**
174     * Stop receiving active sessions updates on the specified listener.
175     *
176     * @param listener The listener to remove.
177     * @hide
178     */
179    public void removeActiveSessionsListener(@NonNull SessionListener listener) {
180        if (listener == null) {
181            throw new IllegalArgumentException("listener may not be null");
182        }
183        try {
184            mService.removeSessionsListener(listener.mStub);
185        } catch (RemoteException e) {
186            Log.e(TAG, "Error in removeActiveSessionsListener.", e);
187        }
188    }
189
190    /**
191     * Set the remote volume controller to receive volume updates on. Only for
192     * use by system UI.
193     *
194     * @param rvc The volume controller to receive updates on.
195     * @hide
196     */
197    public void setRemoteVolumeController(IRemoteVolumeController rvc) {
198        try {
199            mService.setRemoteVolumeController(rvc);
200        } catch (RemoteException e) {
201            Log.e(TAG, "Error in setRemoteVolumeController.", e);
202        }
203    }
204
205    /**
206     * Send a media key event. The receiver will be selected automatically.
207     *
208     * @param keyEvent The KeyEvent to send.
209     * @hide
210     */
211    public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent) {
212        dispatchMediaKeyEvent(keyEvent, false);
213    }
214
215    /**
216     * Send a media key event. The receiver will be selected automatically.
217     *
218     * @param keyEvent The KeyEvent to send.
219     * @param needWakeLock True if a wake lock should be held while sending the key.
220     * @hide
221     */
222    public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent, boolean needWakeLock) {
223        try {
224            mService.dispatchMediaKeyEvent(keyEvent, needWakeLock);
225        } catch (RemoteException e) {
226            Log.e(TAG, "Failed to send key event.", e);
227        }
228    }
229
230    /**
231     * Dispatch an adjust volume request to the system. It will be sent to the
232     * most relevant audio stream or media session.
233     *
234     * @param suggestedStream The stream to fall back to if there isn't a
235     *            relevant stream
236     * @param delta The amount to adjust the volume by.
237     * @param flags Any flags to include with the volume change.
238     * @hide
239     */
240    public void dispatchAdjustVolumeBy(int suggestedStream, int delta, int flags) {
241        try {
242            mService.dispatchAdjustVolumeBy(suggestedStream, delta, flags);
243        } catch (RemoteException e) {
244            Log.e(TAG, "Failed to send adjust volume.", e);
245        }
246    }
247
248    /**
249     * Listens for changes to the list of active sessions. This can be added
250     * using {@link #addActiveSessionsListener}.
251     */
252    public static abstract class SessionListener {
253        /**
254         * Called when the list of active sessions has changed. This can be due
255         * to a session being added or removed or the order of sessions
256         * changing. The controllers will be provided in priority order with the
257         * most important controller at index 0.
258         *
259         * @param controllers The updated list of controllers for the user that
260         *            changed.
261         */
262        public abstract void onActiveSessionsChanged(
263                @Nullable List<MediaController> controllers);
264
265        private final IActiveSessionsListener.Stub mStub = new IActiveSessionsListener.Stub() {
266            @Override
267            public void onActiveSessionsChanged(List<MediaSession.Token> tokens) {
268                ArrayList<MediaController> controllers = new ArrayList<MediaController>();
269                int size = tokens.size();
270                for (int i = 0; i < size; i++) {
271                    controllers.add(new MediaController(tokens.get(i)));
272                }
273                SessionListener.this.onActiveSessionsChanged(controllers);
274            }
275        };
276    }
277}
278