RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 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 | |
| 17 | package com.android.server.media; |
| 18 | |
RoboErik | d2b8c94 | 2014-08-19 11:23:40 -0700 | [diff] [blame] | 19 | import android.media.session.MediaController.PlaybackInfo; |
RoboErik | 42ea7ee | 2014-05-16 16:27:35 -0700 | [diff] [blame] | 20 | import android.media.session.MediaSession; |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 21 | import android.media.session.PlaybackState; |
| 22 | import android.os.Debug; |
RoboErik | a5b0232 | 2014-05-07 17:05:49 -0700 | [diff] [blame] | 23 | import android.os.UserHandle; |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 24 | import android.util.IntArray; |
| 25 | import android.util.Log; |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 26 | import android.util.SparseArray; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 27 | |
| 28 | import java.io.PrintWriter; |
| 29 | import java.util.ArrayList; |
Insun Kang | 30be970a | 2015-11-26 15:35:44 +0900 | [diff] [blame] | 30 | import java.util.List; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 31 | |
| 32 | /** |
| 33 | * Keeps track of media sessions and their priority for notifications, media |
Jeff Brown | 01a500e | 2014-07-10 22:50:50 -0700 | [diff] [blame] | 34 | * button dispatch, etc. |
Jaewan Kim | a7dce19 | 2017-02-16 17:10:54 +0900 | [diff] [blame] | 35 | * <p>This class isn't thread-safe. The caller should take care of the synchronization. |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 36 | */ |
Jaewan Kim | 8f72908 | 2016-06-21 12:36:26 +0900 | [diff] [blame] | 37 | class MediaSessionStack { |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 38 | private static final boolean DEBUG = MediaSessionService.DEBUG; |
| 39 | private static final String TAG = "MediaSessionStack"; |
| 40 | |
| 41 | /** |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 42 | * Listen the change in the media button session. |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 43 | */ |
| 44 | interface OnMediaButtonSessionChangedListener { |
| 45 | /** |
| 46 | * Called when the media button session is changed. |
| 47 | */ |
| 48 | void onMediaButtonSessionChanged(MediaSessionRecord oldMediaButtonSession, |
| 49 | MediaSessionRecord newMediaButtonSession); |
| 50 | } |
| 51 | |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 52 | /** |
| 53 | * These are states that usually indicate the user took an action and should |
| 54 | * bump priority regardless of the old state. |
| 55 | */ |
| 56 | private static final int[] ALWAYS_PRIORITY_STATES = { |
RoboErik | 79fa463 | 2014-05-27 16:49:09 -0700 | [diff] [blame] | 57 | PlaybackState.STATE_FAST_FORWARDING, |
| 58 | PlaybackState.STATE_REWINDING, |
| 59 | PlaybackState.STATE_SKIPPING_TO_PREVIOUS, |
| 60 | PlaybackState.STATE_SKIPPING_TO_NEXT }; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 61 | /** |
| 62 | * These are states that usually indicate the user took an action if they |
| 63 | * were entered from a non-priority state. |
| 64 | */ |
| 65 | private static final int[] TRANSITION_PRIORITY_STATES = { |
RoboErik | 79fa463 | 2014-05-27 16:49:09 -0700 | [diff] [blame] | 66 | PlaybackState.STATE_BUFFERING, |
| 67 | PlaybackState.STATE_CONNECTING, |
| 68 | PlaybackState.STATE_PLAYING }; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 69 | |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 70 | /** |
| 71 | * Sorted list of the media sessions. |
| 72 | * The session of which PlaybackState is changed to ALWAYS_PRIORITY_STATES or |
| 73 | * TRANSITION_PRIORITY_STATES comes first. |
| 74 | * @see #shouldUpdatePriority |
| 75 | */ |
| 76 | private final List<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>(); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 77 | |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 78 | private final AudioPlaybackMonitor mAudioPlaybackMonitor; |
| 79 | private final OnMediaButtonSessionChangedListener mOnMediaButtonSessionChangedListener; |
| 80 | |
| 81 | /** |
| 82 | * The media button session which receives media key events. |
| 83 | * It could be null if the previous media buttion session is released. |
| 84 | */ |
| 85 | private MediaSessionRecord mMediaButtonSession; |
| 86 | |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 87 | private MediaSessionRecord mCachedDefault; |
RoboErik | b69ffd4 | 2014-05-30 14:57:59 -0700 | [diff] [blame] | 88 | private MediaSessionRecord mCachedVolumeDefault; |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 89 | |
| 90 | /** |
| 91 | * Cache the result of the {@link #getActiveSessions} per user. |
| 92 | */ |
| 93 | private final SparseArray<ArrayList<MediaSessionRecord>> mCachedActiveLists = |
| 94 | new SparseArray<>(); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 95 | |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 96 | MediaSessionStack(AudioPlaybackMonitor monitor, OnMediaButtonSessionChangedListener listener) { |
| 97 | mAudioPlaybackMonitor = monitor; |
| 98 | mOnMediaButtonSessionChangedListener = listener; |
Insun Kang | 30be970a | 2015-11-26 15:35:44 +0900 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | /** |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 102 | * Add a record to the priority tracker. |
| 103 | * |
| 104 | * @param record The record to add. |
| 105 | */ |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 106 | public void addSession(MediaSessionRecord record) { |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 107 | mSessions.add(record); |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 108 | clearCache(record.getUserId()); |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 109 | |
| 110 | // Update the media button session. |
| 111 | // The added session could be the session from the package with the audio playback. |
| 112 | // This can happen if an app starts audio playback before creating media session. |
| 113 | updateMediaButtonSessionIfNeeded(); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 114 | } |
| 115 | |
| 116 | /** |
| 117 | * Remove a record from the priority tracker. |
| 118 | * |
| 119 | * @param record The record to remove. |
| 120 | */ |
| 121 | public void removeSession(MediaSessionRecord record) { |
| 122 | mSessions.remove(record); |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 123 | if (mMediaButtonSession == record) { |
Jaewan Kim | fc1f7ab | 2017-03-30 03:22:03 +0900 | [diff] [blame] | 124 | // When the media button session is removed, nullify the media button session and do not |
| 125 | // search for the alternative media session within the app. It's because the alternative |
| 126 | // media session might be a dummy which isn't able to handle the media key events. |
Jaewan Kim | 98e4aaf | 2017-05-12 17:06:47 +0900 | [diff] [blame^] | 127 | updateMediaButtonSession(null); |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 128 | } |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 129 | clearCache(record.getUserId()); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | /** |
Jaewan Kim | a7dce19 | 2017-02-16 17:10:54 +0900 | [diff] [blame] | 133 | * Return if the record exists in the priority tracker. |
| 134 | */ |
| 135 | public boolean contains(MediaSessionRecord record) { |
| 136 | return mSessions.contains(record); |
| 137 | } |
| 138 | |
| 139 | /** |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 140 | * Notify the priority tracker that a session's playback state changed. |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 141 | * |
| 142 | * @param record The record that changed. |
| 143 | * @param oldState Its old playback state. |
| 144 | * @param newState Its new playback state. |
| 145 | */ |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 146 | public void onPlaystateChanged(MediaSessionRecord record, int oldState, int newState) { |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 147 | if (shouldUpdatePriority(oldState, newState)) { |
| 148 | mSessions.remove(record); |
| 149 | mSessions.add(0, record); |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 150 | clearCache(record.getUserId()); |
RoboErik | 23b1135 | 2014-09-24 09:24:54 -0700 | [diff] [blame] | 151 | } else if (!MediaSession.isActiveState(newState)) { |
| 152 | // Just clear the volume cache when a state goes inactive |
RoboErik | b69ffd4 | 2014-05-30 14:57:59 -0700 | [diff] [blame] | 153 | mCachedVolumeDefault = null; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 154 | } |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 155 | |
| 156 | // In most cases, playback state isn't needed for finding media buttion session, |
| 157 | // but we only use it as a hint if an app has multiple local media sessions. |
| 158 | // In that case, we pick the media session whose PlaybackState matches |
| 159 | // the audio playback configuration. |
| 160 | if (mMediaButtonSession != null && mMediaButtonSession.getUid() == record.getUid()) { |
Jaewan Kim | fc1f7ab | 2017-03-30 03:22:03 +0900 | [diff] [blame] | 161 | MediaSessionRecord newMediaButtonSession = |
| 162 | findMediaButtonSession(mMediaButtonSession.getUid()); |
| 163 | if (newMediaButtonSession != mMediaButtonSession) { |
Jaewan Kim | 98e4aaf | 2017-05-12 17:06:47 +0900 | [diff] [blame^] | 164 | updateMediaButtonSession(newMediaButtonSession); |
Jaewan Kim | fc1f7ab | 2017-03-30 03:22:03 +0900 | [diff] [blame] | 165 | } |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 166 | } |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | /** |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 170 | * Handle the change in activeness for a session. |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 171 | * |
| 172 | * @param record The record that changed. |
| 173 | */ |
| 174 | public void onSessionStateChange(MediaSessionRecord record) { |
| 175 | // For now just clear the cache. Eventually we'll selectively clear |
| 176 | // depending on what changed. |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 177 | clearCache(record.getUserId()); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 178 | } |
| 179 | |
| 180 | /** |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 181 | * Update the media button session if needed. |
| 182 | * <p>The media button session is the session that will receive the media button events. |
| 183 | * <p>We send the media button events to the lastly played app. If the app has the media |
| 184 | * session, the session will receive the media button events. |
| 185 | */ |
| 186 | public void updateMediaButtonSessionIfNeeded() { |
| 187 | if (DEBUG) { |
| 188 | Log.d(TAG, "updateMediaButtonSessionIfNeeded, callers=" + Debug.getCallers(2)); |
| 189 | } |
| 190 | IntArray audioPlaybackUids = mAudioPlaybackMonitor.getSortedAudioPlaybackClientUids(); |
| 191 | for (int i = 0; i < audioPlaybackUids.size(); i++) { |
| 192 | MediaSessionRecord mediaButtonSession = |
| 193 | findMediaButtonSession(audioPlaybackUids.get(i)); |
| 194 | if (mediaButtonSession != null) { |
| 195 | // Found the media button session. |
| 196 | mAudioPlaybackMonitor.cleanUpAudioPlaybackUids(mediaButtonSession.getUid()); |
| 197 | if (mMediaButtonSession != mediaButtonSession) { |
Jaewan Kim | 98e4aaf | 2017-05-12 17:06:47 +0900 | [diff] [blame^] | 198 | updateMediaButtonSession(mediaButtonSession); |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 199 | } |
| 200 | return; |
| 201 | } |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | /** |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 206 | * Find the media button session with the given {@param uid}. |
| 207 | * If the app has multiple media sessions, the media session matches the audio playback state |
| 208 | * becomes the media button session. |
| 209 | * |
| 210 | * @return The media button session. Returns {@code null} if the app doesn't have a media |
| 211 | * session. |
| 212 | */ |
| 213 | private MediaSessionRecord findMediaButtonSession(int uid) { |
| 214 | MediaSessionRecord mediaButtonSession = null; |
| 215 | for (MediaSessionRecord session : mSessions) { |
Jaewan Kim | 745e28c | 2017-05-10 20:14:35 +0900 | [diff] [blame] | 216 | if (uid == session.getUid()) { |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 217 | if (session.isPlaybackActive() == |
| 218 | mAudioPlaybackMonitor.isPlaybackActive(session.getUid())) { |
| 219 | // If there's a media session whose PlaybackState matches |
| 220 | // the audio playback state, return it immediately. |
| 221 | return session; |
| 222 | } |
| 223 | if (mediaButtonSession == null) { |
| 224 | // Among the media sessions whose PlaybackState doesn't match |
| 225 | // the audio playback state, pick the top priority. |
| 226 | mediaButtonSession = session; |
| 227 | } |
| 228 | } |
| 229 | } |
| 230 | return mediaButtonSession; |
| 231 | } |
| 232 | |
| 233 | /** |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 234 | * Get the current priority sorted list of active sessions. The most |
| 235 | * important session is at index 0 and the least important at size - 1. |
| 236 | * |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 237 | * @param userId The user to check. It can be {@link UserHandle#USER_ALL} to get all sessions |
| 238 | * for all users in this {@link MediaSessionStack}. |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 239 | * @return All the active sessions in priority order. |
| 240 | */ |
RoboErik | a5b0232 | 2014-05-07 17:05:49 -0700 | [diff] [blame] | 241 | public ArrayList<MediaSessionRecord> getActiveSessions(int userId) { |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 242 | ArrayList<MediaSessionRecord> cachedActiveList = mCachedActiveLists.get(userId); |
| 243 | if (cachedActiveList == null) { |
| 244 | cachedActiveList = getPriorityList(true, userId); |
| 245 | mCachedActiveLists.put(userId, cachedActiveList); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 246 | } |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 247 | return cachedActiveList; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 248 | } |
| 249 | |
| 250 | /** |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 251 | * Get the media button session which receives the media button events. |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 252 | * |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 253 | * @return The media button session or null. |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 254 | */ |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 255 | public MediaSessionRecord getMediaButtonSession() { |
| 256 | return mMediaButtonSession; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 257 | } |
| 258 | |
Jaewan Kim | 98e4aaf | 2017-05-12 17:06:47 +0900 | [diff] [blame^] | 259 | private void updateMediaButtonSession(MediaSessionRecord newMediaButtonSession) { |
| 260 | MediaSessionRecord oldMediaButtonSession = mMediaButtonSession; |
| 261 | mMediaButtonSession = newMediaButtonSession; |
| 262 | mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged( |
| 263 | oldMediaButtonSession, newMediaButtonSession); |
| 264 | } |
| 265 | |
Jaewan Kim | a7dce19 | 2017-02-16 17:10:54 +0900 | [diff] [blame] | 266 | public MediaSessionRecord getDefaultVolumeSession() { |
RoboErik | b69ffd4 | 2014-05-30 14:57:59 -0700 | [diff] [blame] | 267 | if (mCachedVolumeDefault != null) { |
| 268 | return mCachedVolumeDefault; |
| 269 | } |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 270 | ArrayList<MediaSessionRecord> records = getPriorityList(true, UserHandle.USER_ALL); |
RoboErik | b69ffd4 | 2014-05-30 14:57:59 -0700 | [diff] [blame] | 271 | int size = records.size(); |
| 272 | for (int i = 0; i < size; i++) { |
| 273 | MediaSessionRecord record = records.get(i); |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 274 | if (record.isPlaybackActive()) { |
RoboErik | b69ffd4 | 2014-05-30 14:57:59 -0700 | [diff] [blame] | 275 | mCachedVolumeDefault = record; |
| 276 | return record; |
| 277 | } |
| 278 | } |
| 279 | return null; |
| 280 | } |
| 281 | |
RoboErik | 19c9518 | 2014-06-23 15:38:48 -0700 | [diff] [blame] | 282 | public MediaSessionRecord getDefaultRemoteSession(int userId) { |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 283 | ArrayList<MediaSessionRecord> records = getPriorityList(true, userId); |
RoboErik | 19c9518 | 2014-06-23 15:38:48 -0700 | [diff] [blame] | 284 | |
| 285 | int size = records.size(); |
| 286 | for (int i = 0; i < size; i++) { |
| 287 | MediaSessionRecord record = records.get(i); |
RoboErik | d2b8c94 | 2014-08-19 11:23:40 -0700 | [diff] [blame] | 288 | if (record.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE) { |
RoboErik | 19c9518 | 2014-06-23 15:38:48 -0700 | [diff] [blame] | 289 | return record; |
| 290 | } |
| 291 | } |
| 292 | return null; |
| 293 | } |
| 294 | |
RoboErik | a5b0232 | 2014-05-07 17:05:49 -0700 | [diff] [blame] | 295 | public void dump(PrintWriter pw, String prefix) { |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 296 | ArrayList<MediaSessionRecord> sortedSessions = getPriorityList(false, |
RoboErik | a5b0232 | 2014-05-07 17:05:49 -0700 | [diff] [blame] | 297 | UserHandle.USER_ALL); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 298 | int count = sortedSessions.size(); |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 299 | pw.println(prefix + "Media button session is " + mMediaButtonSession); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 300 | pw.println(prefix + "Sessions Stack - have " + count + " sessions:"); |
| 301 | String indent = prefix + " "; |
| 302 | for (int i = 0; i < count; i++) { |
| 303 | MediaSessionRecord record = sortedSessions.get(i); |
| 304 | record.dump(pw, indent); |
| 305 | pw.println(); |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | /** |
| 310 | * Get a priority sorted list of sessions. Can filter to only return active |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 311 | * sessions or sessions. |
| 312 | * <p>Here's the priority order. |
| 313 | * <li>System priority session (session with FLAG_EXCLUSIVE_GLOBAL_PRIORITY)</li> |
| 314 | * <li>Active sessions whose PlaybackState is active</li> |
| 315 | * <li>Active sessions whose PlaybackState is inactive</li> |
| 316 | * <li>Inactive sessions</li> |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 317 | * |
| 318 | * @param activeOnly True to only return active sessions, false to return |
| 319 | * all sessions. |
Jaewan Kim | a7dce19 | 2017-02-16 17:10:54 +0900 | [diff] [blame] | 320 | * @param userId The user to get sessions for. {@link UserHandle#USER_ALL} |
RoboErik | a5b0232 | 2014-05-07 17:05:49 -0700 | [diff] [blame] | 321 | * will return sessions for all users. |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 322 | * @return The priority sorted list of sessions. |
| 323 | */ |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 324 | public ArrayList<MediaSessionRecord> getPriorityList(boolean activeOnly, int userId) { |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 325 | ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>(); |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 326 | int lastPlaybackActiveIndex = 0; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 327 | int lastActiveIndex = 0; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 328 | |
| 329 | int size = mSessions.size(); |
| 330 | for (int i = 0; i < size; i++) { |
| 331 | final MediaSessionRecord session = mSessions.get(i); |
| 332 | |
Jaewan Kim | a7dce19 | 2017-02-16 17:10:54 +0900 | [diff] [blame] | 333 | if (userId != UserHandle.USER_ALL && userId != session.getUserId()) { |
RoboErik | a5b0232 | 2014-05-07 17:05:49 -0700 | [diff] [blame] | 334 | // Filter out sessions for the wrong user |
| 335 | continue; |
| 336 | } |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 337 | |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 338 | if (!session.isActive()) { |
| 339 | if (!activeOnly) { |
| 340 | // If we're getting unpublished as well always put them at |
| 341 | // the end |
| 342 | result.add(session); |
| 343 | } |
| 344 | continue; |
| 345 | } |
| 346 | |
| 347 | if (session.isSystemPriority()) { |
| 348 | // System priority sessions are special and always go at the |
| 349 | // front. We expect there to only be one of these at a time. |
| 350 | result.add(0, session); |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 351 | lastPlaybackActiveIndex++; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 352 | lastActiveIndex++; |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 353 | } else if (session.isPlaybackActive()) { |
| 354 | result.add(lastPlaybackActiveIndex++, session); |
| 355 | lastActiveIndex++; |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 356 | } else { |
Jaewan Kim | 92dea33 | 2017-02-02 11:52:08 +0900 | [diff] [blame] | 357 | result.add(lastActiveIndex++, session); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 358 | } |
| 359 | } |
| 360 | |
| 361 | return result; |
| 362 | } |
| 363 | |
| 364 | private boolean shouldUpdatePriority(int oldState, int newState) { |
| 365 | if (containsState(newState, ALWAYS_PRIORITY_STATES)) { |
| 366 | return true; |
| 367 | } |
| 368 | if (!containsState(oldState, TRANSITION_PRIORITY_STATES) |
| 369 | && containsState(newState, TRANSITION_PRIORITY_STATES)) { |
| 370 | return true; |
| 371 | } |
| 372 | return false; |
| 373 | } |
| 374 | |
| 375 | private boolean containsState(int state, int[] states) { |
| 376 | for (int i = 0; i < states.length; i++) { |
| 377 | if (states[i] == state) { |
| 378 | return true; |
| 379 | } |
| 380 | } |
| 381 | return false; |
| 382 | } |
| 383 | |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 384 | private void clearCache(int userId) { |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 385 | mCachedDefault = null; |
RoboErik | b69ffd4 | 2014-05-30 14:57:59 -0700 | [diff] [blame] | 386 | mCachedVolumeDefault = null; |
Jaewan Kim | aceef91 | 2017-03-30 03:05:06 +0900 | [diff] [blame] | 387 | mCachedActiveLists.remove(userId); |
| 388 | // mCachedActiveLists may also include the list of sessions for UserHandle.USER_ALL, |
| 389 | // so they also need to be cleared. |
| 390 | mCachedActiveLists.remove(UserHandle.USER_ALL); |
RoboErik | a8f9514 | 2014-05-05 14:23:49 -0700 | [diff] [blame] | 391 | } |
| 392 | } |