1/*
2 * Copyright (C) 2016 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 */
16package android.car.cluster.demorenderer;
17
18import android.content.Context;
19import android.media.MediaMetadata;
20import android.media.session.MediaController;
21import android.media.session.MediaSessionManager;
22import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
23import android.media.session.PlaybackState;
24import android.util.Log;
25
26import java.lang.ref.WeakReference;
27import java.util.List;
28
29/**
30 * Reports current media status to instrument cluster renderer.
31 */
32public class MediaStateMonitor {
33
34    private final static String TAG = MediaStateMonitor.class.getSimpleName();
35
36    private final Context mContext;
37    private final MediaListener mMediaListener;
38    private MediaController mPrimaryMediaController;
39    private OnActiveSessionsChangedListener mActiveSessionsChangedListener;
40    private MediaSessionManager mMediaSessionManager;
41    private MediaStateListener mListener;
42
43    public MediaStateMonitor(Context context, MediaStateListener listener) {
44        mListener = listener;
45        mContext = context;
46        mMediaListener = new MediaListener(this);
47        mActiveSessionsChangedListener = controllers -> onActiveSessionsChanged(controllers);
48        mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
49        mMediaSessionManager.addOnActiveSessionsChangedListener(
50                mActiveSessionsChangedListener, null);
51
52        onActiveSessionsChanged(mMediaSessionManager.getActiveSessions(null));
53    }
54
55    private void onActiveSessionsChanged(List<MediaController> controllers) {
56        Log.d(TAG, "onActiveSessionsChanged, controllers found:  " + controllers.size());
57        MediaController newPrimaryController = null;
58        if (controllers.size() > 0) {
59            newPrimaryController = controllers.get(0);
60            if (mPrimaryMediaController == newPrimaryController) {
61                // Primary media controller has not been changed.
62                return;
63            }
64        }
65
66        releasePrimaryMediaController();
67
68        if (newPrimaryController != null) {
69            mPrimaryMediaController = newPrimaryController;
70            mPrimaryMediaController.registerCallback(mMediaListener);
71        }
72        updateRendererMediaStatusIfAvailable();
73
74        for (MediaController m : controllers) {
75            Log.d(TAG, m + ": " + m.getPackageName());
76        }
77    }
78
79    public void release() {
80        releasePrimaryMediaController();
81        if (mActiveSessionsChangedListener != null) {
82            mMediaSessionManager.removeOnActiveSessionsChangedListener(
83                    mActiveSessionsChangedListener);
84            mActiveSessionsChangedListener = null;
85        }
86        mMediaSessionManager = null;
87    }
88
89    private void releasePrimaryMediaController() {
90        if (mPrimaryMediaController != null) {
91            mPrimaryMediaController.unregisterCallback(mMediaListener);
92            mPrimaryMediaController = null;
93        }
94    }
95
96    private void updateRendererMediaStatusIfAvailable() {
97        mListener.onMetadataChanged(
98                mPrimaryMediaController == null ? null : mPrimaryMediaController.getMetadata());
99        mListener.onPlaybackStateChanged(
100                mPrimaryMediaController == null
101                ? null : mPrimaryMediaController.getPlaybackState());
102    }
103
104    private void onPlaybackStateChanged(PlaybackState state) {
105        mListener.onPlaybackStateChanged(state);
106    }
107
108    private void onMetadataChanged(MediaMetadata metadata) {
109        mListener.onMetadataChanged(metadata);
110    }
111
112    public interface MediaStateListener {
113        void onPlaybackStateChanged(PlaybackState playbackState);
114        void onMetadataChanged(MediaMetadata metadata);
115    }
116
117
118    private static class MediaListener extends MediaController.Callback {
119        private final WeakReference<MediaStateMonitor> mServiceRef;
120
121        MediaListener(MediaStateMonitor service) {
122            mServiceRef = new WeakReference<>(service);
123        }
124
125        @Override
126        public void onPlaybackStateChanged(PlaybackState state) {
127            MediaStateMonitor service = mServiceRef.get();
128            if (service != null) {
129                service.onPlaybackStateChanged(state);
130            }
131        }
132
133        @Override
134        public void onMetadataChanged(MediaMetadata metadata) {
135            MediaStateMonitor service = mServiceRef.get();
136            if (service != null) {
137                service.onMetadataChanged(metadata);
138            }
139        }
140    }
141}
142