• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.systemui.car.ndo;
18 
19 import android.content.Context;
20 import android.media.session.MediaController;
21 import android.media.session.MediaSessionManager;
22 import android.media.session.PlaybackState;
23 import android.os.UserHandle;
24 
25 import androidx.annotation.Nullable;
26 import androidx.annotation.VisibleForTesting;
27 import androidx.lifecycle.LiveData;
28 import androidx.lifecycle.MutableLiveData;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.concurrent.Executor;
33 
34 /**
35  * Class that handles listening to and returning active media sessions.
36  */
37 public class MediaSessionHelper extends MediaController.Callback {
38 
39     private final MutableLiveData<List<MediaController>> mLiveData = new MutableLiveData<>();
40     private final MediaSessionManager mMediaSessionManager;
41     private final UserHandle mUserHandle;
42     @VisibleForTesting
43     final List<MediaController> mMediaControllersList = new ArrayList<>();
44     private final Executor mExecutor;
45 
46     private final MediaSessionManager.OnActiveSessionsChangedListener mChangedListener =
47             this::onMediaSessionChange;
48 
MediaSessionHelper(Context context, UserHandle userHandle)49     public MediaSessionHelper(Context context, UserHandle userHandle) {
50         mMediaSessionManager = context.getSystemService(MediaSessionManager.class);
51         mUserHandle = userHandle;
52         mExecutor = context.getMainExecutor();
53         init();
54     }
55 
init()56     private void init() {
57         // Set initial data
58         onMediaSessionChange(mMediaSessionManager
59                 .getActiveSessionsForUser(/* notificationListener= */ null, mUserHandle));
60 
61         mMediaSessionManager.addOnActiveSessionsChangedListener(/* notificationListener= */ null,
62                 mUserHandle, mExecutor, mChangedListener);
63     }
64 
65     /** Returns MediaControllers of current active media sessions */
getActiveMediaSessions()66     public LiveData<List<MediaController>> getActiveMediaSessions() {
67         return mLiveData;
68     }
69 
70     /** Performs cleanup when MediaSessionHelper should no longer be used. */
cleanup()71     public void cleanup() {
72         mMediaSessionManager.removeOnActiveSessionsChangedListener(mChangedListener);
73         unregisterPlaybackChanges();
74     }
75 
76     @Override
onPlaybackStateChanged(@ullable PlaybackState state)77     public void onPlaybackStateChanged(@Nullable PlaybackState state) {
78         if (isPausedOrActive(state)) {
79             onMediaSessionChange(mMediaSessionManager
80                     .getActiveSessionsForUser(/* notificationListener= */ null, mUserHandle));
81         }
82     }
83 
onMediaSessionChange(List<MediaController> mediaControllers)84     private void onMediaSessionChange(List<MediaController> mediaControllers) {
85         unregisterPlaybackChanges();
86         if (mediaControllers == null || mediaControllers.isEmpty()) {
87             return;
88         }
89 
90         List<MediaController> activeMediaControllers = new ArrayList<>();
91 
92         for (MediaController mediaController : mediaControllers) {
93             if (isPausedOrActive(mediaController.getPlaybackState())) {
94                 activeMediaControllers.add(mediaController);
95             } else {
96                 // Since playback state changes don't trigger an active media session change, we
97                 // need to listen to the other media sessions in case another one becomes active.
98                 registerForPlaybackChanges(mediaController);
99             }
100         }
101         mLiveData.setValue(activeMediaControllers);
102     }
103 
104     /** Returns whether the MediaController is paused active */
isPausedOrActive(PlaybackState playbackState)105     private boolean isPausedOrActive(PlaybackState playbackState) {
106         if (playbackState == null) {
107             return false;
108         }
109         return playbackState.isActive() || playbackState.getState() == PlaybackState.STATE_PAUSED;
110     }
111 
registerForPlaybackChanges(MediaController controller)112     private void registerForPlaybackChanges(MediaController controller) {
113         if (mMediaControllersList.contains(controller)) {
114             return;
115         }
116 
117         controller.registerCallback(this);
118         mMediaControllersList.add(controller);
119     }
120 
unregisterPlaybackChanges()121     private void unregisterPlaybackChanges() {
122         for (MediaController mediaController : mMediaControllersList) {
123             if (mediaController != null) {
124                 mediaController.unregisterCallback(this);
125             }
126         }
127         mMediaControllersList.clear();
128     }
129 }
130