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