MediaSessionManager.java revision 01a500ed1c6ae3fff66678144ae637aa8cad0ecc
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 * Creates a new session. 68 * 69 * @param tag A short name for debugging purposes. 70 * @return A {@link MediaSession} for the new session. 71 */ 72 public @NonNull MediaSession createSession(@NonNull String tag) { 73 return createSessionAsUser(tag, UserHandle.myUserId()); 74 } 75 76 /** 77 * Creates a new session as the specified user. To create a session as a 78 * user other than your own you must hold the 79 * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} 80 * permission. 81 * 82 * @param tag A short name for debugging purposes. 83 * @param userId The user id to create the session as. 84 * @return A {@link MediaSession} for the new session. 85 * @hide 86 */ 87 public @NonNull MediaSession createSessionAsUser(@NonNull String tag, int userId) { 88 if (TextUtils.isEmpty(tag)) { 89 throw new IllegalArgumentException("tag must not be null or empty"); 90 } 91 92 try { 93 MediaSession.CallbackStub cbStub = new MediaSession.CallbackStub(); 94 MediaSession session = new MediaSession(mService 95 .createSession(mContext.getPackageName(), cbStub, tag, userId), cbStub); 96 cbStub.setMediaSession(session); 97 98 return session; 99 } catch (RemoteException e) { 100 Log.e(TAG, "Failed to create session: ", e); 101 return null; 102 } 103 } 104 105 /** 106 * Get a list of controllers for all ongoing sessions. The controllers will 107 * be provided in priority order with the most important controller at index 108 * 0. 109 * <p> 110 * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL 111 * permission be held by the calling app. You may also retrieve this list if 112 * your app is an enabled notification listener using the 113 * {@link NotificationListenerService} APIs, in which case you must pass the 114 * {@link ComponentName} of your enabled listener. 115 * 116 * @param notificationListener The enabled notification listener component. 117 * May be null. 118 * @return A list of controllers for ongoing sessions. 119 */ 120 public @NonNull List<MediaController> getActiveSessions( 121 @Nullable ComponentName notificationListener) { 122 return getActiveSessionsForUser(notificationListener, UserHandle.myUserId()); 123 } 124 125 /** 126 * Get active sessions for a specific user. To retrieve actions for a user 127 * other than your own you must hold the 128 * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission 129 * in addition to any other requirements. If you are an enabled notification 130 * listener you may only get sessions for the users you are enabled for. 131 * 132 * @param notificationListener The enabled notification listener component. 133 * May be null. 134 * @param userId The user id to fetch sessions for. 135 * @return A list of controllers for ongoing sessions. 136 * @hide 137 */ 138 public @NonNull List<MediaController> getActiveSessionsForUser( 139 @Nullable ComponentName notificationListener, int userId) { 140 ArrayList<MediaController> controllers = new ArrayList<MediaController>(); 141 try { 142 List<IBinder> binders = mService.getSessions(notificationListener, userId); 143 int size = binders.size(); 144 for (int i = 0; i < size; i++) { 145 MediaController controller = MediaController.fromBinder(ISessionController.Stub 146 .asInterface(binders.get(i))); 147 controllers.add(controller); 148 } 149 } catch (RemoteException e) { 150 Log.e(TAG, "Failed to get active sessions: ", e); 151 } 152 return controllers; 153 } 154 155 /** 156 * Add a listener to be notified when the list of active sessions 157 * changes.This requires the 158 * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by 159 * the calling app. You may also retrieve this list if your app is an 160 * enabled notification listener using the 161 * {@link NotificationListenerService} APIs, in which case you must pass the 162 * {@link ComponentName} of your enabled listener. 163 * 164 * @param sessionListener The listener to add. 165 * @param notificationListener The enabled notification listener component. 166 * May be null. 167 */ 168 public void addActiveSessionsListener(SessionListener sessionListener, 169 ComponentName notificationListener) { 170 addActiveSessionsListener(sessionListener, notificationListener, UserHandle.myUserId()); 171 } 172 173 /** 174 * Add a listener to be notified when the list of active sessions 175 * changes.This requires the 176 * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by 177 * the calling app. You may also retrieve this list if your app is an 178 * enabled notification listener using the 179 * {@link NotificationListenerService} APIs, in which case you must pass the 180 * {@link ComponentName} of your enabled listener. 181 * 182 * @param sessionListener The listener to add. 183 * @param notificationListener The enabled notification listener component. 184 * May be null. 185 * @param userId The userId to listen for changes on. 186 * @hide 187 */ 188 public void addActiveSessionsListener(@NonNull SessionListener sessionListener, 189 @Nullable ComponentName notificationListener, int userId) { 190 if (sessionListener == null) { 191 throw new IllegalArgumentException("listener may not be null"); 192 } 193 try { 194 mService.addSessionsListener(sessionListener.mStub, notificationListener, userId); 195 } catch (RemoteException e) { 196 Log.e(TAG, "Error in addActiveSessionsListener.", e); 197 } 198 } 199 200 /** 201 * Stop receiving active sessions updates on the specified listener. 202 * 203 * @param listener The listener to remove. 204 * @hide 205 */ 206 public void removeActiveSessionsListener(@NonNull SessionListener listener) { 207 if (listener == null) { 208 throw new IllegalArgumentException("listener may not be null"); 209 } 210 try { 211 mService.removeSessionsListener(listener.mStub); 212 } catch (RemoteException e) { 213 Log.e(TAG, "Error in removeActiveSessionsListener.", e); 214 } 215 } 216 217 /** 218 * Set the remote volume controller to receive volume updates on. Only for 219 * use by system UI. 220 * 221 * @param rvc The volume controller to receive updates on. 222 * @hide 223 */ 224 public void setRemoteVolumeController(IRemoteVolumeController rvc) { 225 try { 226 mService.setRemoteVolumeController(rvc); 227 } catch (RemoteException e) { 228 Log.e(TAG, "Error in setRemoteVolumeController.", e); 229 } 230 } 231 232 /** 233 * Send a media key event. The receiver will be selected automatically. 234 * 235 * @param keyEvent The KeyEvent to send. 236 * @hide 237 */ 238 public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent) { 239 dispatchMediaKeyEvent(keyEvent, false); 240 } 241 242 /** 243 * Send a media key event. The receiver will be selected automatically. 244 * 245 * @param keyEvent The KeyEvent to send. 246 * @param needWakeLock True if a wake lock should be held while sending the key. 247 * @hide 248 */ 249 public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent, boolean needWakeLock) { 250 try { 251 mService.dispatchMediaKeyEvent(keyEvent, needWakeLock); 252 } catch (RemoteException e) { 253 Log.e(TAG, "Failed to send key event.", e); 254 } 255 } 256 257 /** 258 * Dispatch an adjust volume request to the system. It will be sent to the 259 * most relevant audio stream or media session. 260 * 261 * @param suggestedStream The stream to fall back to if there isn't a 262 * relevant stream 263 * @param delta The amount to adjust the volume by. 264 * @param flags Any flags to include with the volume change. 265 * @hide 266 */ 267 public void dispatchAdjustVolumeBy(int suggestedStream, int delta, int flags) { 268 try { 269 mService.dispatchAdjustVolumeBy(suggestedStream, delta, flags); 270 } catch (RemoteException e) { 271 Log.e(TAG, "Failed to send adjust volume.", e); 272 } 273 } 274 275 /** 276 * Listens for changes to the list of active sessions. This can be added 277 * using {@link #addActiveSessionsListener}. 278 */ 279 public static abstract class SessionListener { 280 /** 281 * Called when the list of active sessions has changed. This can be due 282 * to a session being added or removed or the order of sessions 283 * changing. The controllers will be provided in priority order with the 284 * most important controller at index 0. 285 * 286 * @param controllers The updated list of controllers for the user that 287 * changed. 288 */ 289 public abstract void onActiveSessionsChanged( 290 @Nullable List<MediaController> controllers); 291 292 private final IActiveSessionsListener.Stub mStub = new IActiveSessionsListener.Stub() { 293 @Override 294 public void onActiveSessionsChanged(List<MediaSession.Token> tokens) { 295 ArrayList<MediaController> controllers = new ArrayList<MediaController>(); 296 int size = tokens.size(); 297 for (int i = 0; i < size; i++) { 298 controllers.add(MediaController.fromToken(tokens.get(i))); 299 } 300 SessionListener.this.onActiveSessionsChanged(controllers); 301 } 302 }; 303 } 304} 305