1df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev/*
2df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * Copyright (C) 2016 The Android Open Source Project
3df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev *
4df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * Licensed under the Apache License, Version 2.0 (the "License");
5df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * you may not use this file except in compliance with the License.
6df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * You may obtain a copy of the License at
7df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev *
8df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev *      http://www.apache.org/licenses/LICENSE-2.0
9df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev *
10df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * Unless required by applicable law or agreed to in writing, software
11df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * distributed under the License is distributed on an "AS IS" BASIS,
12df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * See the License for the specific language governing permissions and
14df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * limitations under the License.
15df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev */
16df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevpackage com.android.car.cluster.sample;
17df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
18df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport static com.android.car.cluster.sample.DebugUtil.DEBUG;
19df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
20df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport android.content.Context;
21df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport android.media.MediaMetadata;
22df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport android.media.session.MediaController;
23df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport android.media.session.MediaSessionManager;
24df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
25df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport android.media.session.PlaybackState;
26df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport android.util.Log;
27df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
28df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport java.lang.ref.WeakReference;
29df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevimport java.util.List;
30df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
31df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev/**
32df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev * Reports current media status to instrument cluster renderer through {@link MediaStateListener}
33df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev */
34df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsevpublic class MediaStateMonitor {
35df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
36df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private final static String TAG = DebugUtil.getTag(MediaStateMonitor.class);
37df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
38df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private final Context mContext;
39df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private final MediaListener mMediaListener;
40df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private MediaController mPrimaryMediaController;
41df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private OnActiveSessionsChangedListener mActiveSessionsChangedListener;
42df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private MediaSessionManager mMediaSessionManager;
43df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private MediaStateListener mListener;
44df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
45df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    public MediaStateMonitor(Context context, MediaStateListener listener) {
46df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mListener = listener;
47df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mContext = context;
48df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mMediaListener = new MediaListener(this);
49df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mActiveSessionsChangedListener = controllers -> onActiveSessionsChanged(controllers);
50df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class);
51df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mMediaSessionManager.addOnActiveSessionsChangedListener(
52df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                mActiveSessionsChangedListener, null);
53df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
54df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        onActiveSessionsChanged(mMediaSessionManager.getActiveSessions(null));
55df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    }
56df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
57df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private void onActiveSessionsChanged(List<MediaController> controllers) {
58df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        if (DEBUG) {
59df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            Log.d(TAG, "onActiveSessionsChanged, controllers found:  " + controllers.size());
60df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        }
61df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        MediaController newPrimaryController = null;
62df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        if (!controllers.isEmpty()) {
63df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            newPrimaryController = controllers.get(0);
64df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            if (mPrimaryMediaController == newPrimaryController) {
65df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                // Primary media controller has not been changed.
66df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                return;
67df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            }
68df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        }
69df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
70df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        releasePrimaryMediaController();
71df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
72df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        if (newPrimaryController != null) {
73df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            mPrimaryMediaController = newPrimaryController;
74df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            mPrimaryMediaController.registerCallback(mMediaListener);
75df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            mListener.onMediaAppChanged(
76df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                    new MediaAppInfo(mContext, mPrimaryMediaController.getPackageName()));
77df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        }
78df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        updateRendererMediaStatusIfAvailable();
79df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    }
80df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
81df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    public void release() {
82df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        releasePrimaryMediaController();
83df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        if (mActiveSessionsChangedListener != null) {
84df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            mMediaSessionManager.removeOnActiveSessionsChangedListener(
85df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                    mActiveSessionsChangedListener);
86df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            mActiveSessionsChangedListener = null;
87df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        }
88df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mMediaSessionManager = null;
89df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    }
90df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
91df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private void releasePrimaryMediaController() {
92df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        if (mPrimaryMediaController != null) {
93df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            mPrimaryMediaController.unregisterCallback(mMediaListener);
94df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            mPrimaryMediaController = null;
95df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        }
96df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    }
97df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
98df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private void updateRendererMediaStatusIfAvailable() {
99df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mListener.onMetadataChanged(
100df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                mPrimaryMediaController == null ? null : mPrimaryMediaController.getMetadata());
101df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mListener.onPlaybackStateChanged(
102df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                mPrimaryMediaController == null
103df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                ? null : mPrimaryMediaController.getPlaybackState());
104df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    }
105df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
106df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private void onPlaybackStateChanged(PlaybackState state) {
107df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mListener.onPlaybackStateChanged(state);
108df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    }
109df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
110df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private void onMetadataChanged(MediaMetadata metadata) {
111df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        mListener.onMetadataChanged(metadata);
112df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    }
113df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
114df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    public interface MediaStateListener {
115df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        void onPlaybackStateChanged(PlaybackState playbackState);
116df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        void onMetadataChanged(MediaMetadata metadata);
117df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        void onMediaAppChanged(MediaAppInfo mediaAppPackage);
118df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    }
119df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
120df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    private static class MediaListener extends MediaController.Callback {
121df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        private final WeakReference<MediaStateMonitor> mServiceRef;
122df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
123df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        MediaListener(MediaStateMonitor service) {
124df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            mServiceRef = new WeakReference<>(service);
125df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        }
126df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
127df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        @Override
128df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        public void onPlaybackStateChanged(PlaybackState state) {
129df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            MediaStateMonitor service = mServiceRef.get();
130df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            if (service != null) {
131df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                service.onPlaybackStateChanged(state);
132df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            }
133df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        }
134df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev
135df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        @Override
136df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        public void onMetadataChanged(MediaMetadata metadata) {
137df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            MediaStateMonitor service = mServiceRef.get();
138df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            if (service != null) {
139df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev                service.onMetadataChanged(metadata);
140df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev            }
141df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev        }
142df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev    }
143df4db1d3efb85be01f0973067c9e104b5f93f205Pavel Maltsev}
144