197a60d9d00240949b9642c28a34be118469eb727Winson Chung/*
297a60d9d00240949b9642c28a34be118469eb727Winson Chung * Copyright (C) 2017 The Android Open Source Project
397a60d9d00240949b9642c28a34be118469eb727Winson Chung *
497a60d9d00240949b9642c28a34be118469eb727Winson Chung * Licensed under the Apache License, Version 2.0 (the "License");
597a60d9d00240949b9642c28a34be118469eb727Winson Chung * you may not use this file except in compliance with the License.
697a60d9d00240949b9642c28a34be118469eb727Winson Chung * You may obtain a copy of the License at
797a60d9d00240949b9642c28a34be118469eb727Winson Chung *
897a60d9d00240949b9642c28a34be118469eb727Winson Chung *      http://www.apache.org/licenses/LICENSE-2.0
997a60d9d00240949b9642c28a34be118469eb727Winson Chung *
1097a60d9d00240949b9642c28a34be118469eb727Winson Chung * Unless required by applicable law or agreed to in writing, software
1197a60d9d00240949b9642c28a34be118469eb727Winson Chung * distributed under the License is distributed on an "AS IS" BASIS,
1297a60d9d00240949b9642c28a34be118469eb727Winson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1397a60d9d00240949b9642c28a34be118469eb727Winson Chung * See the License for the specific language governing permissions and
1497a60d9d00240949b9642c28a34be118469eb727Winson Chung * limitations under the License.
1597a60d9d00240949b9642c28a34be118469eb727Winson Chung */
1697a60d9d00240949b9642c28a34be118469eb727Winson Chung
1797a60d9d00240949b9642c28a34be118469eb727Winson Chungpackage com.android.systemui.pip.phone;
1897a60d9d00240949b9642c28a34be118469eb727Winson Chung
199c2a6867578142b3e51fa8787a39d350c147b4faWinson Chungimport static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
209c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung
2197a60d9d00240949b9642c28a34be118469eb727Winson Chungimport android.app.IActivityManager;
229c2a6867578142b3e51fa8787a39d350c147b4faWinson Chungimport android.app.PendingIntent;
2397a60d9d00240949b9642c28a34be118469eb727Winson Chungimport android.app.RemoteAction;
249c2a6867578142b3e51fa8787a39d350c147b4faWinson Chungimport android.content.BroadcastReceiver;
2597a60d9d00240949b9642c28a34be118469eb727Winson Chungimport android.content.ComponentName;
2697a60d9d00240949b9642c28a34be118469eb727Winson Chungimport android.content.Context;
279c2a6867578142b3e51fa8787a39d350c147b4faWinson Chungimport android.content.Intent;
289c2a6867578142b3e51fa8787a39d350c147b4faWinson Chungimport android.content.IntentFilter;
2997a60d9d00240949b9642c28a34be118469eb727Winson Chungimport android.graphics.drawable.Icon;
3097a60d9d00240949b9642c28a34be118469eb727Winson Chungimport android.media.session.MediaController;
3197a60d9d00240949b9642c28a34be118469eb727Winson Chungimport android.media.session.MediaSession;
3297a60d9d00240949b9642c28a34be118469eb727Winson Chungimport android.media.session.MediaSessionManager;
3397a60d9d00240949b9642c28a34be118469eb727Winson Chungimport android.media.session.PlaybackState;
349c2a6867578142b3e51fa8787a39d350c147b4faWinson Chungimport android.os.UserHandle;
3597a60d9d00240949b9642c28a34be118469eb727Winson Chung
3697a60d9d00240949b9642c28a34be118469eb727Winson Chungimport com.android.systemui.R;
3797a60d9d00240949b9642c28a34be118469eb727Winson Chung
3897a60d9d00240949b9642c28a34be118469eb727Winson Chungimport java.util.ArrayList;
3997a60d9d00240949b9642c28a34be118469eb727Winson Chungimport java.util.Collections;
4097a60d9d00240949b9642c28a34be118469eb727Winson Chungimport java.util.List;
4197a60d9d00240949b9642c28a34be118469eb727Winson Chung
4297a60d9d00240949b9642c28a34be118469eb727Winson Chung/**
4397a60d9d00240949b9642c28a34be118469eb727Winson Chung * Interfaces with the {@link MediaSessionManager} to compose the right set of actions to show (only
4497a60d9d00240949b9642c28a34be118469eb727Winson Chung * if there are no actions from the PiP activity itself). The active media controller is only set
4597a60d9d00240949b9642c28a34be118469eb727Winson Chung * when there is a media session from the top PiP activity.
4697a60d9d00240949b9642c28a34be118469eb727Winson Chung */
4797a60d9d00240949b9642c28a34be118469eb727Winson Chungpublic class PipMediaController {
4897a60d9d00240949b9642c28a34be118469eb727Winson Chung
499c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung    private static final String ACTION_PLAY = "com.android.systemui.pip.phone.PLAY";
509c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung    private static final String ACTION_PAUSE = "com.android.systemui.pip.phone.PAUSE";
5183fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung    private static final String ACTION_NEXT = "com.android.systemui.pip.phone.NEXT";
5283fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung    private static final String ACTION_PREV = "com.android.systemui.pip.phone.PREV";
539c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung
5497a60d9d00240949b9642c28a34be118469eb727Winson Chung    /**
5597a60d9d00240949b9642c28a34be118469eb727Winson Chung     * A listener interface to receive notification on changes to the media actions.
5697a60d9d00240949b9642c28a34be118469eb727Winson Chung     */
5797a60d9d00240949b9642c28a34be118469eb727Winson Chung    public interface ActionListener {
5897a60d9d00240949b9642c28a34be118469eb727Winson Chung        /**
5997a60d9d00240949b9642c28a34be118469eb727Winson Chung         * Called when the media actions changes.
6097a60d9d00240949b9642c28a34be118469eb727Winson Chung         */
6197a60d9d00240949b9642c28a34be118469eb727Winson Chung        void onMediaActionsChanged(List<RemoteAction> actions);
6297a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
6397a60d9d00240949b9642c28a34be118469eb727Winson Chung
6497a60d9d00240949b9642c28a34be118469eb727Winson Chung    private final Context mContext;
6597a60d9d00240949b9642c28a34be118469eb727Winson Chung    private final IActivityManager mActivityManager;
6697a60d9d00240949b9642c28a34be118469eb727Winson Chung
6797a60d9d00240949b9642c28a34be118469eb727Winson Chung    private final MediaSessionManager mMediaSessionManager;
6897a60d9d00240949b9642c28a34be118469eb727Winson Chung    private MediaController mMediaController;
6997a60d9d00240949b9642c28a34be118469eb727Winson Chung
7097a60d9d00240949b9642c28a34be118469eb727Winson Chung    private RemoteAction mPauseAction;
7197a60d9d00240949b9642c28a34be118469eb727Winson Chung    private RemoteAction mPlayAction;
7283fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung    private RemoteAction mNextAction;
7383fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung    private RemoteAction mPrevAction;
7497a60d9d00240949b9642c28a34be118469eb727Winson Chung
759c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung    private BroadcastReceiver mPlayPauseActionReceiver = new BroadcastReceiver() {
769c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung        @Override
779c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung        public void onReceive(Context context, Intent intent) {
789c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung            final String action = intent.getAction();
799c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung            if (action.equals(ACTION_PLAY)) {
809c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung                mMediaController.getTransportControls().play();
819c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung            } else if (action.equals(ACTION_PAUSE)) {
829c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung                mMediaController.getTransportControls().pause();
8383fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung            } else if (action.equals(ACTION_NEXT)) {
8483fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                mMediaController.getTransportControls().skipToNext();
8583fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung            } else if (action.equals(ACTION_PREV)) {
8683fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                mMediaController.getTransportControls().skipToPrevious();
879c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung            }
889c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung        }
899c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung    };
909c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung
9197a60d9d00240949b9642c28a34be118469eb727Winson Chung    private MediaController.Callback mPlaybackChangedListener = new MediaController.Callback() {
9297a60d9d00240949b9642c28a34be118469eb727Winson Chung        @Override
9397a60d9d00240949b9642c28a34be118469eb727Winson Chung        public void onPlaybackStateChanged(PlaybackState state) {
94b0103abff787f0e46ba7cf6dee877012b731565bWinson Chung            notifyActionsChanged();
9597a60d9d00240949b9642c28a34be118469eb727Winson Chung        }
9697a60d9d00240949b9642c28a34be118469eb727Winson Chung    };
9797a60d9d00240949b9642c28a34be118469eb727Winson Chung
9897a60d9d00240949b9642c28a34be118469eb727Winson Chung    private ArrayList<ActionListener> mListeners = new ArrayList<>();
9997a60d9d00240949b9642c28a34be118469eb727Winson Chung
10097a60d9d00240949b9642c28a34be118469eb727Winson Chung    public PipMediaController(Context context, IActivityManager activityManager) {
10197a60d9d00240949b9642c28a34be118469eb727Winson Chung        mContext = context;
10297a60d9d00240949b9642c28a34be118469eb727Winson Chung        mActivityManager = activityManager;
1039c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung        IntentFilter mediaControlFilter = new IntentFilter();
1049c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung        mediaControlFilter.addAction(ACTION_PLAY);
1059c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung        mediaControlFilter.addAction(ACTION_PAUSE);
10683fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        mediaControlFilter.addAction(ACTION_NEXT);
10783fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        mediaControlFilter.addAction(ACTION_PREV);
1089c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung        mContext.registerReceiver(mPlayPauseActionReceiver, mediaControlFilter);
10997a60d9d00240949b9642c28a34be118469eb727Winson Chung
11097a60d9d00240949b9642c28a34be118469eb727Winson Chung        createMediaActions();
11197a60d9d00240949b9642c28a34be118469eb727Winson Chung        mMediaSessionManager =
11297a60d9d00240949b9642c28a34be118469eb727Winson Chung                (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
11397a60d9d00240949b9642c28a34be118469eb727Winson Chung        mMediaSessionManager.addOnActiveSessionsChangedListener(controllers -> {
11497a60d9d00240949b9642c28a34be118469eb727Winson Chung            resolveActiveMediaController(controllers);
11597a60d9d00240949b9642c28a34be118469eb727Winson Chung        }, null);
11697a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
11797a60d9d00240949b9642c28a34be118469eb727Winson Chung
11897a60d9d00240949b9642c28a34be118469eb727Winson Chung    /**
11997a60d9d00240949b9642c28a34be118469eb727Winson Chung     * Handles when an activity is pinned.
12097a60d9d00240949b9642c28a34be118469eb727Winson Chung     */
12197a60d9d00240949b9642c28a34be118469eb727Winson Chung    public void onActivityPinned() {
12297a60d9d00240949b9642c28a34be118469eb727Winson Chung        // Once we enter PiP, try to find the active media controller for the top most activity
12397a60d9d00240949b9642c28a34be118469eb727Winson Chung        resolveActiveMediaController(mMediaSessionManager.getActiveSessions(null));
12497a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
12597a60d9d00240949b9642c28a34be118469eb727Winson Chung
12697a60d9d00240949b9642c28a34be118469eb727Winson Chung    /**
12797a60d9d00240949b9642c28a34be118469eb727Winson Chung     * Adds a new media action listener.
12897a60d9d00240949b9642c28a34be118469eb727Winson Chung     */
12997a60d9d00240949b9642c28a34be118469eb727Winson Chung    public void addListener(ActionListener listener) {
13097a60d9d00240949b9642c28a34be118469eb727Winson Chung        if (!mListeners.contains(listener)) {
13197a60d9d00240949b9642c28a34be118469eb727Winson Chung            mListeners.add(listener);
13297a60d9d00240949b9642c28a34be118469eb727Winson Chung            listener.onMediaActionsChanged(getMediaActions());
13397a60d9d00240949b9642c28a34be118469eb727Winson Chung        }
13497a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
13597a60d9d00240949b9642c28a34be118469eb727Winson Chung
13697a60d9d00240949b9642c28a34be118469eb727Winson Chung    /**
13797a60d9d00240949b9642c28a34be118469eb727Winson Chung     * Removes a media action listener.
13897a60d9d00240949b9642c28a34be118469eb727Winson Chung     */
13997a60d9d00240949b9642c28a34be118469eb727Winson Chung    public void removeListener(ActionListener listener) {
14097a60d9d00240949b9642c28a34be118469eb727Winson Chung        listener.onMediaActionsChanged(Collections.EMPTY_LIST);
14197a60d9d00240949b9642c28a34be118469eb727Winson Chung        mListeners.remove(listener);
14297a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
14397a60d9d00240949b9642c28a34be118469eb727Winson Chung
14497a60d9d00240949b9642c28a34be118469eb727Winson Chung    /**
14597a60d9d00240949b9642c28a34be118469eb727Winson Chung     * Gets the set of media actions currently available.
14697a60d9d00240949b9642c28a34be118469eb727Winson Chung     */
14797a60d9d00240949b9642c28a34be118469eb727Winson Chung    private List<RemoteAction> getMediaActions() {
14897a60d9d00240949b9642c28a34be118469eb727Winson Chung        if (mMediaController == null || mMediaController.getPlaybackState() == null) {
14997a60d9d00240949b9642c28a34be118469eb727Winson Chung            return Collections.EMPTY_LIST;
15097a60d9d00240949b9642c28a34be118469eb727Winson Chung        }
15197a60d9d00240949b9642c28a34be118469eb727Winson Chung
15297a60d9d00240949b9642c28a34be118469eb727Winson Chung        ArrayList<RemoteAction> mediaActions = new ArrayList<>();
15397a60d9d00240949b9642c28a34be118469eb727Winson Chung        int state = mMediaController.getPlaybackState().getState();
15497a60d9d00240949b9642c28a34be118469eb727Winson Chung        boolean isPlaying = MediaSession.isActiveState(state);
15597a60d9d00240949b9642c28a34be118469eb727Winson Chung        long actions = mMediaController.getPlaybackState().getActions();
15683fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung
15783fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        // Prev action
15883fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        mPrevAction.setEnabled((actions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0);
15983fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        mediaActions.add(mPrevAction);
16083fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung
16183fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        // Play/pause action
16297a60d9d00240949b9642c28a34be118469eb727Winson Chung        if (!isPlaying && ((actions & PlaybackState.ACTION_PLAY) != 0)) {
16397a60d9d00240949b9642c28a34be118469eb727Winson Chung            mediaActions.add(mPlayAction);
164b0103abff787f0e46ba7cf6dee877012b731565bWinson Chung        } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) {
165b0103abff787f0e46ba7cf6dee877012b731565bWinson Chung            mediaActions.add(mPauseAction);
16697a60d9d00240949b9642c28a34be118469eb727Winson Chung        }
16783fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung
16883fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        // Next action
16983fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        mNextAction.setEnabled((actions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0);
17083fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        mediaActions.add(mNextAction);
17197a60d9d00240949b9642c28a34be118469eb727Winson Chung        return mediaActions;
17297a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
17397a60d9d00240949b9642c28a34be118469eb727Winson Chung
17497a60d9d00240949b9642c28a34be118469eb727Winson Chung    /**
17597a60d9d00240949b9642c28a34be118469eb727Winson Chung     * Creates the standard media buttons that we may show.
17697a60d9d00240949b9642c28a34be118469eb727Winson Chung     */
17797a60d9d00240949b9642c28a34be118469eb727Winson Chung    private void createMediaActions() {
17897a60d9d00240949b9642c28a34be118469eb727Winson Chung        String pauseDescription = mContext.getString(R.string.pip_pause);
17997a60d9d00240949b9642c28a34be118469eb727Winson Chung        mPauseAction = new RemoteAction(Icon.createWithResource(mContext,
18083fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                R.drawable.ic_pause_white), pauseDescription, pauseDescription,
1819c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung                        PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PAUSE),
1829c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung                                FLAG_UPDATE_CURRENT));
18397a60d9d00240949b9642c28a34be118469eb727Winson Chung
18497a60d9d00240949b9642c28a34be118469eb727Winson Chung        String playDescription = mContext.getString(R.string.pip_play);
18597a60d9d00240949b9642c28a34be118469eb727Winson Chung        mPlayAction = new RemoteAction(Icon.createWithResource(mContext,
18683fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                R.drawable.ic_play_arrow_white), playDescription, playDescription,
1879c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung                        PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PLAY),
1889c2a6867578142b3e51fa8787a39d350c147b4faWinson Chung                                FLAG_UPDATE_CURRENT));
18983fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung
19083fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        String nextDescription = mContext.getString(R.string.pip_skip_to_next);
19183fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        mNextAction = new RemoteAction(Icon.createWithResource(mContext,
19283fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                R.drawable.ic_skip_next_white), nextDescription, nextDescription,
19383fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                        PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NEXT),
19483fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                                FLAG_UPDATE_CURRENT));
19583fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung
19683fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        String prevDescription = mContext.getString(R.string.pip_skip_to_prev);
19783fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung        mPrevAction = new RemoteAction(Icon.createWithResource(mContext,
19883fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                R.drawable.ic_skip_previous_white), prevDescription, prevDescription,
19983fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                        PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_PREV),
20083fbf18ced2a386dff5fd9bb30fa5d8229cb517aWinson Chung                                FLAG_UPDATE_CURRENT));
20197a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
20297a60d9d00240949b9642c28a34be118469eb727Winson Chung
20397a60d9d00240949b9642c28a34be118469eb727Winson Chung    /**
20497a60d9d00240949b9642c28a34be118469eb727Winson Chung     * Tries to find and set the active media controller for the top PiP activity.
20597a60d9d00240949b9642c28a34be118469eb727Winson Chung     */
20697a60d9d00240949b9642c28a34be118469eb727Winson Chung    private void resolveActiveMediaController(List<MediaController> controllers) {
20797a60d9d00240949b9642c28a34be118469eb727Winson Chung        if (controllers != null) {
208734c9c055657c22e2019ca77214e496442e0c52eWinson Chung            final ComponentName topActivity = PipUtils.getTopPinnedActivity(mContext,
209734c9c055657c22e2019ca77214e496442e0c52eWinson Chung                    mActivityManager);
21097a60d9d00240949b9642c28a34be118469eb727Winson Chung            if (topActivity != null) {
21197a60d9d00240949b9642c28a34be118469eb727Winson Chung                for (int i = 0; i < controllers.size(); i++) {
21297a60d9d00240949b9642c28a34be118469eb727Winson Chung                    final MediaController controller = controllers.get(i);
21397a60d9d00240949b9642c28a34be118469eb727Winson Chung                    if (controller.getPackageName().equals(topActivity.getPackageName())) {
21497a60d9d00240949b9642c28a34be118469eb727Winson Chung                        setActiveMediaController(controller);
21597a60d9d00240949b9642c28a34be118469eb727Winson Chung                        return;
21697a60d9d00240949b9642c28a34be118469eb727Winson Chung                    }
21797a60d9d00240949b9642c28a34be118469eb727Winson Chung                }
21897a60d9d00240949b9642c28a34be118469eb727Winson Chung            }
21997a60d9d00240949b9642c28a34be118469eb727Winson Chung        }
22097a60d9d00240949b9642c28a34be118469eb727Winson Chung        setActiveMediaController(null);
22197a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
22297a60d9d00240949b9642c28a34be118469eb727Winson Chung
22397a60d9d00240949b9642c28a34be118469eb727Winson Chung    /**
22497a60d9d00240949b9642c28a34be118469eb727Winson Chung     * Sets the active media controller for the top PiP activity.
22597a60d9d00240949b9642c28a34be118469eb727Winson Chung     */
22697a60d9d00240949b9642c28a34be118469eb727Winson Chung    private void setActiveMediaController(MediaController controller) {
22797a60d9d00240949b9642c28a34be118469eb727Winson Chung        if (controller != mMediaController) {
22897a60d9d00240949b9642c28a34be118469eb727Winson Chung            if (mMediaController != null) {
22997a60d9d00240949b9642c28a34be118469eb727Winson Chung                mMediaController.unregisterCallback(mPlaybackChangedListener);
23097a60d9d00240949b9642c28a34be118469eb727Winson Chung            }
23197a60d9d00240949b9642c28a34be118469eb727Winson Chung            mMediaController = controller;
23297a60d9d00240949b9642c28a34be118469eb727Winson Chung            if (controller != null) {
23397a60d9d00240949b9642c28a34be118469eb727Winson Chung                controller.registerCallback(mPlaybackChangedListener);
23497a60d9d00240949b9642c28a34be118469eb727Winson Chung            }
235b0103abff787f0e46ba7cf6dee877012b731565bWinson Chung            notifyActionsChanged();
23697a60d9d00240949b9642c28a34be118469eb727Winson Chung
23797a60d9d00240949b9642c28a34be118469eb727Winson Chung            // TODO(winsonc): Consider if we want to close the PIP after a timeout (like on TV)
23897a60d9d00240949b9642c28a34be118469eb727Winson Chung        }
23997a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
24097a60d9d00240949b9642c28a34be118469eb727Winson Chung
24197a60d9d00240949b9642c28a34be118469eb727Winson Chung    /**
24297a60d9d00240949b9642c28a34be118469eb727Winson Chung     * Notifies all listeners that the actions have changed.
24397a60d9d00240949b9642c28a34be118469eb727Winson Chung     */
244b0103abff787f0e46ba7cf6dee877012b731565bWinson Chung    private void notifyActionsChanged() {
24597a60d9d00240949b9642c28a34be118469eb727Winson Chung        if (!mListeners.isEmpty()) {
246b0103abff787f0e46ba7cf6dee877012b731565bWinson Chung            List<RemoteAction> actions = getMediaActions();
24797a60d9d00240949b9642c28a34be118469eb727Winson Chung            mListeners.forEach(l -> l.onMediaActionsChanged(actions));
24897a60d9d00240949b9642c28a34be118469eb727Winson Chung        }
24997a60d9d00240949b9642c28a34be118469eb727Winson Chung    }
25097a60d9d00240949b9642c28a34be118469eb727Winson Chung}
251