MediaSessionStack.java revision d2b8c947ddfc6349a3ae6c3968b422b9cf50d7ed
11a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton/*
21a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton * Copyright (C) 2014 The Android Open Source Project
31a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton *
41a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton * Licensed under the Apache License, Version 2.0 (the "License");
51a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton * you may not use this file except in compliance with the License.
61a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton * You may obtain a copy of the License at
71a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton *
81a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton *      http://www.apache.org/licenses/LICENSE-2.0
91a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton *
101a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton * Unless required by applicable law or agreed to in writing, software
111a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton * distributed under the License is distributed on an "AS IS" BASIS,
121a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton * See the License for the specific language governing permissions and
141a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton * limitations under the License.
15777707be8445b7d2f9cb235cd040cd1994dd2996Robert Phillips */
161a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton
171a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Daltonpackage com.android.server.media;
18383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton
19383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Daltonimport android.media.session.MediaController.PlaybackInfo;
20383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Daltonimport android.media.session.PlaybackState;
21383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Daltonimport android.media.session.MediaSession;
22383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Daltonimport android.os.UserHandle;
231a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton
24a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Daltonimport java.io.PrintWriter;
25a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Daltonimport java.util.ArrayList;
26a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton
27a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton/**
28a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton * Keeps track of media sessions and their priority for notifications, media
29a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton * button dispatch, etc.
30a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton */
31a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Daltonpublic class MediaSessionStack {
32a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    /**
33a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     * These are states that usually indicate the user took an action and should
34a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     * bump priority regardless of the old state.
35a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     */
36a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    private static final int[] ALWAYS_PRIORITY_STATES = {
37a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            PlaybackState.STATE_FAST_FORWARDING,
38a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            PlaybackState.STATE_REWINDING,
391a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            PlaybackState.STATE_SKIPPING_TO_PREVIOUS,
401a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            PlaybackState.STATE_SKIPPING_TO_NEXT };
411a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton    /**
42383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     * These are states that usually indicate the user took an action if they
43383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     * were entered from a non-priority state.
441a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     */
45bdecacfbe47bc7211336bb847bb33c00ef85ea3eBrian Salomon    private static final int[] TRANSITION_PRIORITY_STATES = {
46e4679fa06a1ab57de15f20cff56911599fa2a73eChris Dalton            PlaybackState.STATE_BUFFERING,
471a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            PlaybackState.STATE_CONNECTING,
481a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            PlaybackState.STATE_PLAYING };
49383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton
50383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton    private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
51a2ac30da36c80f616c909c671a240f2d468db124Chris Dalton
52a2ac30da36c80f616c909c671a240f2d468db124Chris Dalton    private MediaSessionRecord mGlobalPrioritySession;
531a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton
541a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton    private MediaSessionRecord mCachedButtonReceiver;
55383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton    private MediaSessionRecord mCachedDefault;
56383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton    private MediaSessionRecord mCachedVolumeDefault;
57a2ac30da36c80f616c909c671a240f2d468db124Chris Dalton    private ArrayList<MediaSessionRecord> mCachedActiveList;
58a2ac30da36c80f616c909c671a240f2d468db124Chris Dalton    private ArrayList<MediaSessionRecord> mCachedTransportControlList;
59a2ac30da36c80f616c909c671a240f2d468db124Chris Dalton
60a2ac30da36c80f616c909c671a240f2d468db124Chris Dalton    /**
61383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     * Add a record to the priority tracker.
62383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     *
635ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton     * @param record The record to add.
641a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     */
651a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton    public void addSession(MediaSessionRecord record) {
661a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        mSessions.add(record);
671a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        clearCache();
685ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton    }
695ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton
705ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton    /**
715ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton     * Remove a record from the priority tracker.
72db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     *
73db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     * @param record The record to remove.
74db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     */
75db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton    public void removeSession(MediaSessionRecord record) {
76db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton        mSessions.remove(record);
77db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton        if (record == mGlobalPrioritySession) {
78db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton            mGlobalPrioritySession = null;
79db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton        }
80db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton        clearCache();
81db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton    }
82db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton
83db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton    /**
84db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     * Notify the priority tracker that a session's state changed.
85db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     *
86db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     * @param record The record that changed.
87db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     * @param oldState Its old playback state.
88db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     * @param newState Its new playback state.
89db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     * @return true if the priority order was updated, false otherwise.
90db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton     */
91db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton    public boolean onPlaystateChange(MediaSessionRecord record, int oldState, int newState) {
92db91c6e7fbfc9d1d8fd203f7e08eefb602e4a0b9Chris Dalton        if (shouldUpdatePriority(oldState, newState)) {
935ed4423090e63e4c7888d6dd44fde177adea13f3Chris Dalton            mSessions.remove(record);
941a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            mSessions.add(0, record);
951a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            clearCache();
961a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            return true;
971a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        } else if (newState == PlaybackState.STATE_PAUSED) {
981a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            // Just clear the volume cache in this case
991a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            mCachedVolumeDefault = null;
1001a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        }
1011a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        return false;
1021a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton    }
103a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton
104a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    /**
1051a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     * Handle any stack changes that need to occur in response to a session
1061a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     * state change. TODO add the old and new session state as params
1071a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     *
1081a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     * @param record The record that changed.
1091a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     */
110a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    public void onSessionStateChange(MediaSessionRecord record) {
111080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton        if ((record.getFlags() & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
1121a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            mGlobalPrioritySession = record;
113383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        }
114383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        // For now just clear the cache. Eventually we'll selectively clear
1151a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        // depending on what changed.
1161a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        clearCache();
1171a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton    }
1181a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton
119c9c97b7fd5f9ca8b95223d99dac063d4a2510a4dChris Dalton    /**
120c9c97b7fd5f9ca8b95223d99dac063d4a2510a4dChris Dalton     * Get the current priority sorted list of active sessions. The most
121a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     * important session is at index 0 and the least important at size - 1.
122a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     *
123a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     * @param userId The user to check.
124a039d3bd06be63da883fcc5ef55efb736d044f6dChris Dalton     * @return All the active sessions in priority order.
125a039d3bd06be63da883fcc5ef55efb736d044f6dChris Dalton     */
126a039d3bd06be63da883fcc5ef55efb736d044f6dChris Dalton    public ArrayList<MediaSessionRecord> getActiveSessions(int userId) {
127a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        if (mCachedActiveList == null) {
128a039d3bd06be63da883fcc5ef55efb736d044f6dChris Dalton            mCachedActiveList = getPriorityListLocked(true, 0, userId);
129a039d3bd06be63da883fcc5ef55efb736d044f6dChris Dalton        }
130a039d3bd06be63da883fcc5ef55efb736d044f6dChris Dalton        return mCachedActiveList;
131a039d3bd06be63da883fcc5ef55efb736d044f6dChris Dalton    }
132a039d3bd06be63da883fcc5ef55efb736d044f6dChris Dalton
133383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton    /**
1341a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     * Get the current priority sorted list of active sessions that use
1351a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     * transport controls. The most important session is at index 0 and the
1361a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     * least important at size -1.
1371a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     *
1381a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     * @param userId The user to check.
1391a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     * @return All the active sessions that handle transport controls in
140a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     *         priority order.
141a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     */
142080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton    public ArrayList<MediaSessionRecord> getTransportControlSessions(int userId) {
143a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        if (mCachedTransportControlList == null) {
144080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton            mCachedTransportControlList = getPriorityListLocked(true,
145080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton                    MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS, userId);
146080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton        }
147080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton        return mCachedTransportControlList;
148a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    }
149a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton
150a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    /**
151080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton     * Get the highest priority active session.
152080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton     *
153a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     * @param userId The user to check.
154080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton     * @return The current highest priority session or null.
155383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     */
156383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton    public MediaSessionRecord getDefaultSession(int userId) {
157383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        if (mCachedDefault != null) {
1581a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            return mCachedDefault;
1591a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        }
1601a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId);
161a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        if (records.size() > 0) {
1621a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            return records.get(0);
1631a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        }
164080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton        return null;
165a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    }
166a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton
167a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    /**
168a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton     * Get the highest priority session that can handle media buttons.
1691a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     *
170383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     * @param userId The user to check.
1711a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     * @return The default media button session or null.
1721a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton     */
1731a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton    public MediaSessionRecord getDefaultMediaButtonSession(int userId) {
1741a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) {
175a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            return mGlobalPrioritySession;
176080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton        }
1771a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        if (mCachedButtonReceiver != null) {
1781a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            return mCachedButtonReceiver;
1791a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        }
180383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        ArrayList<MediaSessionRecord> records = getPriorityListLocked(true,
181a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                MediaSession.FLAG_HANDLES_MEDIA_BUTTONS, userId);
1821a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        if (records.size() > 0) {
1831a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            mCachedButtonReceiver = records.get(0);
1841a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        }
185a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        return mCachedButtonReceiver;
186080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton    }
187a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton
188a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    public MediaSessionRecord getDefaultVolumeSession(int userId) {
189a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        if (mGlobalPrioritySession != null && mGlobalPrioritySession.isActive()) {
1901a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            return mGlobalPrioritySession;
1911a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        }
192a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        if (mCachedVolumeDefault != null) {
193a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            return mCachedVolumeDefault;
194a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        }
195a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId);
196a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        int size = records.size();
197a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        for (int i = 0; i < size; i++) {
198a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            MediaSessionRecord record = records.get(i);
199a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            if (record.isPlaybackActive(false)) {
200a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                mCachedVolumeDefault = record;
201a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                return record;
202a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            }
203a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        }
204383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        return null;
205777707be8445b7d2f9cb235cd040cd1994dd2996Robert Phillips    }
206777707be8445b7d2f9cb235cd040cd1994dd2996Robert Phillips
207777707be8445b7d2f9cb235cd040cd1994dd2996Robert Phillips    public MediaSessionRecord getDefaultRemoteSession(int userId) {
208383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        ArrayList<MediaSessionRecord> records = getPriorityListLocked(true, 0, userId);
209a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton
210c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton        int size = records.size();
211a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        for (int i = 0; i < size; i++) {
212c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton            MediaSessionRecord record = records.get(i);
213a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            if (record.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
214a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                return record;
215a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            }
216777707be8445b7d2f9cb235cd040cd1994dd2996Robert Phillips        }
217a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        return null;
218a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    }
219c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton
220c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton    public void dump(PrintWriter pw, String prefix) {
221a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        ArrayList<MediaSessionRecord> sortedSessions = getPriorityListLocked(false, 0,
222383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton                UserHandle.USER_ALL);
223383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        int count = sortedSessions.size();
224a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        pw.println(prefix + "Global priority session is " + mGlobalPrioritySession);
225a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        pw.println(prefix + "Sessions Stack - have " + count + " sessions:");
226777707be8445b7d2f9cb235cd040cd1994dd2996Robert Phillips        String indent = prefix + "  ";
227777707be8445b7d2f9cb235cd040cd1994dd2996Robert Phillips        for (int i = 0; i < count; i++) {
228777707be8445b7d2f9cb235cd040cd1994dd2996Robert Phillips            MediaSessionRecord record = sortedSessions.get(i);
229a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            record.dump(pw, indent);
230c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton            pw.println();
231777707be8445b7d2f9cb235cd040cd1994dd2996Robert Phillips        }
232ce5209a8a5711fde34f28c740f5cd74bdb560e21Robert Phillips    }
23394a6ce84ece51ff1c46c698753716f3f47585742Greg Daniel
23494a6ce84ece51ff1c46c698753716f3f47585742Greg Daniel    /**
23594a6ce84ece51ff1c46c698753716f3f47585742Greg Daniel     * Get a priority sorted list of sessions. Can filter to only return active
236383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     * sessions or sessions with specific flags.
237383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     *
238383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     * @param activeOnly True to only return active sessions, false to return
239383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     *            all sessions.
240383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     * @param withFlags Only return sessions with all the specified flags set. 0
241383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     *            returns all sessions.
242383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     * @param userId The user to get sessions for. {@link UserHandle#USER_ALL}
243383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     *            will return sessions for all users.
244383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     * @return The priority sorted list of sessions.
245383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton     */
246ce5209a8a5711fde34f28c740f5cd74bdb560e21Robert Phillips    private ArrayList<MediaSessionRecord> getPriorityListLocked(boolean activeOnly, int withFlags,
247ce5209a8a5711fde34f28c740f5cd74bdb560e21Robert Phillips            int userId) {
248383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        ArrayList<MediaSessionRecord> result = new ArrayList<MediaSessionRecord>();
249383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        int lastLocalIndex = 0;
250383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        int lastActiveIndex = 0;
251383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        int lastPublishedIndex = 0;
252383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton
253383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        int size = mSessions.size();
254383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        for (int i = 0; i < size; i++) {
255ce5209a8a5711fde34f28c740f5cd74bdb560e21Robert Phillips            final MediaSessionRecord session = mSessions.get(i);
256a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton
257a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            if (userId != UserHandle.USER_ALL && userId != session.getUserId()) {
258a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                // Filter out sessions for the wrong user
259a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                continue;
260a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            }
261a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            if ((session.getFlags() & withFlags) != withFlags) {
262a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                // Filter out sessions with the wrong flags
263c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton                continue;
264a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            }
265a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            if (!session.isActive()) {
266c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton                if (!activeOnly) {
267c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton                    // If we're getting unpublished as well always put them at
268a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                    // the end
269a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                    result.add(session);
270a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                }
271383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton                continue;
2721a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            }
273a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton
2741a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            if (session.isSystemPriority()) {
2751a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton                // System priority sessions are special and always go at the
2761a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton                // front. We expect there to only be one of these at a time.
2779ca27849d8259e4b35243094bdca969612efba2fChris Dalton                result.add(0, session);
2781a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton                lastLocalIndex++;
279383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton                lastActiveIndex++;
280a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                lastPublishedIndex++;
281a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            } else if (session.isPlaybackActive(true)) {
282383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton                // TODO this with real local route check
283a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                if (true) {
2841a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton                    // Active local sessions get top priority
285c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton                    result.add(lastLocalIndex, session);
2861a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton                    lastLocalIndex++;
287a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                    lastActiveIndex++;
288c9c97b7fd5f9ca8b95223d99dac063d4a2510a4dChris Dalton                    lastPublishedIndex++;
289383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton                } else {
2901a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton                    // Then active remote sessions
291a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                    result.add(lastActiveIndex, session);
292a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                    lastActiveIndex++;
293080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton                    lastPublishedIndex++;
2941a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton                }
295a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            } else {
296a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                // inactive sessions go at the end in order of whoever last did
297a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                // something.
298a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                result.add(lastPublishedIndex, session);
299a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                lastPublishedIndex++;
300a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            }
301a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        }
302080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton
303c9c97b7fd5f9ca8b95223d99dac063d4a2510a4dChris Dalton        return result;
304080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton    }
305080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton
306080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton    private boolean shouldUpdatePriority(int oldState, int newState) {
307a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        if (containsState(newState, ALWAYS_PRIORITY_STATES)) {
308a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            return true;
309a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        }
310a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        if (!containsState(oldState, TRANSITION_PRIORITY_STATES)
311a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                && containsState(newState, TRANSITION_PRIORITY_STATES)) {
312a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton            return true;
313a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        }
314a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton        return false;
315a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    }
316a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton
317080baa44c50091d4e1a15550ded245c502a9ae3aChris Dalton    private boolean containsState(int state, int[] states) {
3181a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        for (int i = 0; i < states.length; i++) {
3191a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton            if (states[i] == state) {
320a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton                return true;
321383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton            }
3221a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        }
3231a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        return false;
324a32a3c32c32e02baecffb537f6f26c0a67a1c130Chris Dalton    }
325383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton
3261a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton    private void clearCache() {
3271a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        mCachedDefault = null;
3281a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        mCachedVolumeDefault = null;
3291a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        mCachedButtonReceiver = null;
3301a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton        mCachedActiveList = null;
331383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton        mCachedTransportControlList = null;
3321a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton    }
3331a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton}
3341a325d25b941ef801b3e9b2c0342da43cf35cdbaChris Dalton