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