From 63a37a3a29861d66c9bf9e643f0218b0b4f0a6a2 Mon Sep 17 00:00:00 2001 From: Sergey Nikolaienkov Date: Wed, 28 Oct 2020 08:03:45 +0000 Subject: [PATCH] Use PipMediaController in .tv.PipController Make .tv.PipController rely on PipMediaController for media session monitoring and managering. Refactor .tv.PipControlsViewController to use PipMediaController to retrieve the media buttons. Make .tv.PipNotification subscribe to PipMediaController to receive callbacks about media metadata updates. Bug: 169575409 Bug: 165795012 Test: make WindowManager-Shell; make SystemUI Change-Id: I397f93eb4433116ba4f476bda7374b07d97e082d --- .../Shell/res/layout/tv_pip_controls.xml | 10 - .../src/com/android/wm/shell/pip/Pip.java | 13 - .../wm/shell/pip/tv/PipController.java | 114 +------ .../wm/shell/pip/tv/PipControlsView.java | 8 +- .../pip/tv/PipControlsViewController.java | 308 ++++++------------ .../wm/shell/pip/tv/PipMenuActivity.java | 5 +- .../wm/shell/pip/tv/PipNotification.java | 105 ++---- .../android/systemui/wmshell/TvPipModule.java | 11 +- 8 files changed, 157 insertions(+), 417 deletions(-) diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml index d2f235e273d57..9157f63ce1b31 100644 --- a/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml +++ b/libs/WindowManager/Shell/res/layout/tv_pip_controls.xml @@ -16,7 +16,6 @@ --> - - - diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java index 59c79bafd46ce..8d5da1a5ffcbc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java @@ -24,7 +24,6 @@ import android.content.pm.ActivityInfo; import android.graphics.Rect; import com.android.wm.shell.pip.phone.PipTouchHandler; -import com.android.wm.shell.pip.tv.PipController; import java.io.PrintWriter; import java.util.function.Consumer; @@ -33,12 +32,6 @@ import java.util.function.Consumer; * Interface to engage picture in picture feature. */ public interface Pip { - /** - * Registers a {@link PipController.MediaListener} to PipController. - */ - default void addMediaListener(PipController.MediaListener listener) { - } - /** * Closes PIP (PIPed activity and PIP system UI). */ @@ -144,12 +137,6 @@ public interface Pip { default void onTaskStackChanged() { } - /** - * Removes a {@link PipController.MediaListener} from PipController. - */ - default void removeMediaListener(PipController.MediaListener listener) { - } - /** * Resize the Pip to the appropriate size for the input state. * diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java index 8e9bf7434b3c5..7b710553b67d5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipController.java @@ -38,9 +38,6 @@ import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Rect; -import android.media.session.MediaController; -import android.media.session.MediaSessionManager; -import android.media.session.PlaybackState; import android.os.Debug; import android.os.Handler; import android.os.RemoteException; @@ -55,6 +52,7 @@ import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipBoundsHandler; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipTaskOrganizer; import java.util.ArrayList; @@ -110,22 +108,19 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac private final PipBoundsState mPipBoundsState; private final PipBoundsHandler mPipBoundsHandler; private final PipTaskOrganizer mPipTaskOrganizer; + private final PipMediaController mPipMediaController; private IActivityTaskManager mActivityTaskManager; - private MediaSessionManager mMediaSessionManager; private int mState = STATE_NO_PIP; private int mResumeResizePinnedStackRunnableState = STATE_NO_PIP; private final Handler mHandler = new Handler(); private List mListeners = new ArrayList<>(); - private List mMediaListeners = new ArrayList<>(); private Rect mPipBounds; private Rect mDefaultPipBounds = new Rect(); private Rect mMenuModePipBounds; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; private int mPipTaskId = TASK_ID_NO_PIP; private int mPinnedStackId = INVALID_STACK_ID; - private ComponentName mPipComponentName; - private MediaController mPipMediaController; private String[] mLastPackagesResourceGranted; private PipNotification mPipNotification; private ParceledListSlice mCustomActions; @@ -168,17 +163,13 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac } } }; - private final MediaSessionManager.OnActiveSessionsChangedListener mActiveMediaSessionListener = - controllers -> updateMediaController(controllers); + private final PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener = new PipControllerPinnedStackListener(); @Override public void registerSessionListenerForCurrentUser() { - // TODO Need confirm if TV have to re-registers when switch user - mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveMediaSessionListener); - mMediaSessionManager.addOnActiveSessionsChangedListener(mActiveMediaSessionListener, null, - UserHandle.USER_CURRENT, null); + mPipMediaController.registerSessionListenerForCurrentUser(); } /** @@ -232,12 +223,13 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac PipBoundsState pipBoundsState, PipBoundsHandler pipBoundsHandler, PipTaskOrganizer pipTaskOrganizer, - WindowManagerShellWrapper windowManagerShellWrapper - ) { + PipMediaController pipMediaController, + WindowManagerShellWrapper windowManagerShellWrapper) { mContext = context; mPipBoundsState = pipBoundsState; mPipNotification = new PipNotification(context, this); mPipBoundsHandler = pipBoundsHandler; + mPipMediaController = pipMediaController; // Ensure that we have the display info in case we get calls to update the bounds // before the listener calls back final DisplayInfo displayInfo = new DisplayInfo(); @@ -261,7 +253,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mLastOrientation = initialConfig.orientation; loadConfigurationsAndApply(initialConfig); - mMediaSessionManager = mContext.getSystemService(MediaSessionManager.class); mWindowManagerShellWrapper = windowManagerShellWrapper; try { mWindowManagerShellWrapper.addPinnedStackListener(mPinnedStackListener); @@ -329,8 +320,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mState = STATE_NO_PIP; mPipTaskId = TASK_ID_NO_PIP; - mPipMediaController = null; - mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveMediaSessionListener); if (removePipStack) { try { mActivityTaskManager.removeTask(mPinnedStackId); @@ -371,13 +360,9 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac if (DEBUG) Log.d(TAG, "PINNED_STACK:" + taskInfo); mPinnedStackId = taskInfo.taskId; mPipTaskId = taskInfo.childTaskIds[taskInfo.childTaskIds.length - 1]; - mPipComponentName = ComponentName.unflattenFromString( - taskInfo.childTaskNames[taskInfo.childTaskNames.length - 1]); // Set state to STATE_PIP so we show it when the pinned stack animation ends. mState = STATE_PIP; - mMediaSessionManager.addOnActiveSessionsChangedListener( - mActiveMediaSessionListener, null); - updateMediaController(mMediaSessionManager.getActiveSessions(null)); + mPipMediaController.onActivityPinned(); for (int i = mListeners.size() - 1; i >= 0; i--) { mListeners.get(i).onPipEntered(packageName); } @@ -553,20 +538,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mListeners.remove(listener); } - /** - * Adds a {@link MediaListener} to PipController. - */ - public void addMediaListener(MediaListener listener) { - mMediaListeners.add(listener); - } - - /** - * Removes a {@link MediaListener} from PipController. - */ - public void removeMediaListener(MediaListener listener) { - mMediaListeners.remove(listener); - } - /** * Returns {@code true} if PIP is shown. */ @@ -608,69 +579,12 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac } } - private void updateMediaController(List controllers) { - MediaController mediaController = null; - if (controllers != null && getState() != STATE_NO_PIP && mPipComponentName != null) { - for (int i = controllers.size() - 1; i >= 0; i--) { - MediaController controller = controllers.get(i); - // We assumes that an app with PIPable activity - // keeps the single instance of media controller especially when PIP is on. - if (controller.getPackageName().equals(mPipComponentName.getPackageName())) { - mediaController = controller; - break; - } - } - } - if (mPipMediaController != mediaController) { - mPipMediaController = mediaController; - for (int i = mMediaListeners.size() - 1; i >= 0; i--) { - mMediaListeners.get(i).onMediaControllerChanged(); - } - if (mPipMediaController == null) { - mHandler.postDelayed(mClosePipRunnable, - CLOSE_PIP_WHEN_MEDIA_SESSION_GONE_TIMEOUT_MS); - } else { - mHandler.removeCallbacks(mClosePipRunnable); - } - } - } - - /** - * Gets the {@link android.media.session.MediaController} for the PIPed activity. - */ - MediaController getMediaController() { - return mPipMediaController; - } - @Override public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) { - } - /** - * Returns the PIPed activity's playback state. - * This returns one of {@link #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED}, - * or {@link #PLAYBACK_STATE_UNAVAILABLE}. - */ - int getPlaybackState() { - if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) { - return PLAYBACK_STATE_UNAVAILABLE; - } - int state = mPipMediaController.getPlaybackState().getState(); - boolean isPlaying = (state == PlaybackState.STATE_BUFFERING - || state == PlaybackState.STATE_CONNECTING - || state == PlaybackState.STATE_PLAYING - || state == PlaybackState.STATE_FAST_FORWARDING - || state == PlaybackState.STATE_REWINDING - || state == PlaybackState.STATE_SKIPPING_TO_PREVIOUS - || state == PlaybackState.STATE_SKIPPING_TO_NEXT); - long actions = mPipMediaController.getPlaybackState().getActions(); - if (!isPlaying && ((actions & PlaybackState.ACTION_PLAY) != 0)) { - return PLAYBACK_STATE_PAUSED; - } else if (isPlaying && ((actions & PlaybackState.ACTION_PAUSE) != 0)) { - return PLAYBACK_STATE_PLAYING; - } - return PLAYBACK_STATE_UNAVAILABLE; + PipMediaController getPipMediaController() { + return mPipMediaController; } @Override @@ -718,14 +632,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac void onPipResizeAboutToStart(); } - /** - * A listener interface to receive change in PIP's media controller - */ - public interface MediaListener { - /** Invoked when the MediaController on PIPed activity is changed. */ - void onMediaControllerChanged(); - } - private String getStateDescription() { if (mSuspendPipResizingReason == 0) { return stateToName(mState); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java index 14960c38fd432..95d9b77c513ef 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsView.java @@ -51,15 +51,11 @@ public class PipControlsView extends LinearLayout { setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); } - PipControlButtonView getFullButtonView() { + PipControlButtonView getFullscreenButton() { return findViewById(R.id.full_button); } - PipControlButtonView getCloseButtonView() { + PipControlButtonView getCloseButton() { return findViewById(R.id.close_button); } - - PipControlButtonView getPlayPauseButtonView() { - return findViewById(R.id.play_pause_button); - } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java index f66e9025a9ed8..5265e7705ed92 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipControlsViewController.java @@ -18,10 +18,10 @@ package com.android.wm.shell.pip.tv; import android.app.PendingIntent; import android.app.RemoteAction; +import android.content.Context; import android.graphics.Color; -import android.media.session.MediaController; -import android.media.session.PlaybackState; import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -29,9 +29,8 @@ import android.view.View; import com.android.wm.shell.R; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; /** @@ -42,213 +41,118 @@ public class PipControlsViewController { private static final float DISABLED_ACTION_ALPHA = 0.54f; - private final PipControlsView mView; - private final LayoutInflater mLayoutInflater; - private final Handler mHandler; private final PipController mPipController; - private final PipControlButtonView mPlayPauseButtonView; - private MediaController mMediaController; - private PipControlButtonView mFocusedChild; - private Listener mListener; - private ArrayList mCustomButtonViews = new ArrayList<>(); - private List mCustomActions = new ArrayList<>(); - public PipControlsView getView() { + private final Context mContext; + private final Handler mUiThreadHandler; + private final PipControlsView mView; + private final List mAdditionalButtons = new ArrayList<>(); + + private final List mCustomActions = new ArrayList<>(); + private final List mMediaActions = new ArrayList<>(); + + public PipControlsViewController(PipControlsView view, PipController pipController) { + mContext = view.getContext(); + mUiThreadHandler = new Handler(Looper.getMainLooper()); + mPipController = pipController; + mView = view; + + mView.getFullscreenButton().setOnClickListener(v -> mPipController.movePipToFullscreen()); + mView.getCloseButton().setOnClickListener(v -> mPipController.closePip()); + + mPipController.getPipMediaController().addActionListener(this::onMediaActionsChanged); + } + + PipControlsView getView() { return mView; } - /** - * An interface to listen user action. - */ - public interface Listener { - /** - * Called when a user clicks close PIP button. - */ - void onClosed(); - } - - private View.OnAttachStateChangeListener - mOnAttachStateChangeListener = - new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - updateMediaController(); - mPipController.addMediaListener(mPipMediaListener); - } - - @Override - public void onViewDetachedFromWindow(View v) { - mPipController.removeMediaListener(mPipMediaListener); - } - }; - - private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() { - @Override - public void onPlaybackStateChanged(PlaybackState state) { - updateUserActions(); - } - }; - - private final PipController.MediaListener mPipMediaListener = this::updateMediaController; - - private final View.OnFocusChangeListener - mFocusChangeListener = - new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View view, boolean hasFocus) { - if (hasFocus) { - mFocusedChild = (PipControlButtonView) view; - } else if (mFocusedChild == view) { - mFocusedChild = null; - } - } - }; - - public PipControlsViewController(PipControlsView view, PipController pipController, - LayoutInflater layoutInflater, Handler handler) { - super(); - mView = view; - mPipController = pipController; - mLayoutInflater = layoutInflater; - mHandler = handler; - - mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); - if (mView.isAttachedToWindow()) { - mOnAttachStateChangeListener.onViewAttachedToWindow(mView); - } - - View fullButtonView = mView.getFullButtonView(); - fullButtonView.setOnFocusChangeListener(mFocusChangeListener); - fullButtonView.setOnClickListener(mView -> mPipController.movePipToFullscreen()); - - View closeButtonView = mView.getCloseButtonView(); - closeButtonView.setOnFocusChangeListener(mFocusChangeListener); - closeButtonView.setOnClickListener(v -> { - mPipController.closePip(); - if (mListener != null) { - mListener.onClosed(); - } - }); - - mPlayPauseButtonView = mView.getPlayPauseButtonView(); - mPlayPauseButtonView.setOnFocusChangeListener(mFocusChangeListener); - mPlayPauseButtonView.setOnClickListener(v -> { - if (mMediaController == null || mMediaController.getPlaybackState() == null) { - return; - } - final int playbackState = mPipController.getPlaybackState(); - if (playbackState == PipController.PLAYBACK_STATE_PAUSED) { - mMediaController.getTransportControls().play(); - } else if (playbackState == PipController.PLAYBACK_STATE_PLAYING) { - mMediaController.getTransportControls().pause(); - } - - // View will be updated later in {@link mMediaControllerCallback} - }); - } - - private void updateMediaController() { - AtomicReference newController = new AtomicReference<>(); - newController.set(mPipController.getMediaController()); - - if (newController.get() == null || mMediaController == newController.get()) { - return; - } - if (mMediaController != null) { - mMediaController.unregisterCallback(mMediaControllerCallback); - } - mMediaController = newController.get(); - if (mMediaController != null) { - mMediaController.registerCallback(mMediaControllerCallback); - } - updateUserActions(); - } - - /** - * Updates the actions for the PIP. If there are no custom actions, then the media session - * actions are shown. - */ - private void updateUserActions() { - if (!mCustomActions.isEmpty()) { - // Ensure we have as many buttons as actions - while (mCustomButtonViews.size() < mCustomActions.size()) { - PipControlButtonView buttonView = (PipControlButtonView) mLayoutInflater.inflate( - R.layout.tv_pip_custom_control, mView, false); - mView.addView(buttonView); - mCustomButtonViews.add(buttonView); - } - - // Update the visibility of all views - for (int i = 0; i < mCustomButtonViews.size(); i++) { - mCustomButtonViews.get(i).setVisibility( - i < mCustomActions.size() ? View.VISIBLE : View.GONE); - } - - // Update the state and visibility of the action buttons, and hide the rest - for (int i = 0; i < mCustomActions.size(); i++) { - final RemoteAction action = mCustomActions.get(i); - PipControlButtonView actionView = mCustomButtonViews.get(i); - - // TODO: Check if the action drawable has changed before we reload it - action.getIcon().loadDrawableAsync(mView.getContext(), d -> { - d.setTint(Color.WHITE); - actionView.setImageDrawable(d); - }, mHandler); - actionView.setText(action.getContentDescription()); - if (action.isEnabled()) { - actionView.setOnClickListener(v -> { - try { - action.getActionIntent().send(); - } catch (PendingIntent.CanceledException e) { - Log.w(TAG, "Failed to send action", e); - } - }); - } - actionView.setEnabled(action.isEnabled()); - actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA); - } - - // Hide the media session buttons - mPlayPauseButtonView.setVisibility(View.GONE); - } else { - AtomicInteger state = new AtomicInteger(PipController.STATE_UNKNOWN); - state.set(mPipController.getPlaybackState()); - if (state.get() == PipController.STATE_UNKNOWN - || state.get() == PipController.PLAYBACK_STATE_UNAVAILABLE) { - mPlayPauseButtonView.setVisibility(View.GONE); - } else { - mPlayPauseButtonView.setVisibility(View.VISIBLE); - if (state.get() == PipController.PLAYBACK_STATE_PLAYING) { - mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_pause_white); - mPlayPauseButtonView.setText(R.string.pip_pause); - } else { - mPlayPauseButtonView.setImageResource(R.drawable.pip_ic_play_arrow_white); - mPlayPauseButtonView.setText(R.string.pip_play); - } - } - - // Hide all the custom action buttons - for (int i = 0; i < mCustomButtonViews.size(); i++) { - mCustomButtonViews.get(i).setVisibility(View.GONE); - } - } - } - - - /** - * Sets the {@link Listener} to listen user actions. - */ - public void setListener(Listener listener) { - mListener = listener; - } - - /** * Updates the set of activity-defined actions. */ - public void setActions(List actions) { + void setCustomActions(List actions) { + if (mCustomActions.isEmpty() && actions.isEmpty()) { + // Nothing changed - return early. + return; + } mCustomActions.clear(); mCustomActions.addAll(actions); - updateUserActions(); + updateAdditionalActions(); + } + + private void onMediaActionsChanged(List actions) { + if (mMediaActions.isEmpty() && actions.isEmpty()) { + // Nothing changed - return early. + return; + } + mMediaActions.clear(); + mMediaActions.addAll(actions); + + // Update the view only if there are no custom actions (media actions are only shown when + // there no custom actions). + if (mCustomActions.isEmpty()) { + updateAdditionalActions(); + } + } + + private void updateAdditionalActions() { + final List actionsToDisplay; + if (!mCustomActions.isEmpty()) { + // If there are custom actions: show them. + actionsToDisplay = mCustomActions; + } else if (!mMediaActions.isEmpty()) { + // If there are no custom actions, but there media actions: show them. + actionsToDisplay = mMediaActions; + } else { + // If there no custom actions and no media actions: clean up all the additional buttons. + actionsToDisplay = Collections.emptyList(); + } + + // Make sure we exactly as many additional buttons as we have actions to display. + final int actionsNumber = actionsToDisplay.size(); + int buttonsNumber = mAdditionalButtons.size(); + if (actionsNumber > buttonsNumber) { + final LayoutInflater layoutInflater = LayoutInflater.from(mContext); + // Add buttons until we have enough to display all of the actions. + while (actionsNumber > buttonsNumber) { + final PipControlButtonView button = (PipControlButtonView) layoutInflater.inflate( + R.layout.tv_pip_custom_control, mView, false); + mView.addView(button); + mAdditionalButtons.add(button); + + buttonsNumber++; + } + } else if (actionsNumber < buttonsNumber) { + // Hide buttons until we as many as the actions. + while (actionsNumber < buttonsNumber) { + final View button = mAdditionalButtons.get(buttonsNumber - 1); + button.setVisibility(View.GONE); + button.setOnClickListener(null); + + buttonsNumber--; + } + } + + // "Assign" actions to the buttons. + for (int index = 0; index < actionsNumber; index++) { + final RemoteAction action = actionsToDisplay.get(index); + final PipControlButtonView button = mAdditionalButtons.get(index); + button.setVisibility(View.VISIBLE); // Ensure the button is visible. + button.setText(action.getContentDescription()); + button.setEnabled(action.isEnabled()); + button.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA); + button.setOnClickListener(v -> { + try { + action.getActionIntent().send(); + } catch (PendingIntent.CanceledException e) { + Log.w(TAG, "Failed to send action", e); + } + }); + + action.getIcon().loadDrawableAsync(mContext, drawable -> { + drawable.setTint(Color.WHITE); + button.setImageDrawable(drawable); + }, mUiThreadHandler); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java index e185a96044496..d2270c2781619 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipMenuActivity.java @@ -56,8 +56,7 @@ public class PipMenuActivity extends Activity implements PipController.Listener } setContentView(R.layout.tv_pip_menu); mPipControlsViewController = new PipControlsViewController( - findViewById(R.id.pip_controls), sPipController, - getLayoutInflater(), getApplicationContext().getMainThreadHandler()); + findViewById(R.id.pip_controls), sPipController); sPipController.addListener(this); mRestorePipSizeWhenClose = true; mFadeInAnimation = AnimatorInflater.loadAnimator( @@ -141,7 +140,7 @@ public class PipMenuActivity extends Activity implements PipController.Listener if (DEBUG) Log.d(TAG, "onPipMenuActionsChanged()"); boolean hasCustomActions = actions != null && !actions.getList().isEmpty(); - mPipControlsViewController.setActions( + mPipControlsViewController.setCustomActions( hasCustomActions ? actions.getList() : Collections.emptyList()); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java index f5bbd23fa1d6f..d6368ea837712 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java @@ -28,36 +28,32 @@ import android.content.pm.ParceledListSlice; import android.content.res.Resources; import android.graphics.Bitmap; import android.media.MediaMetadata; -import android.media.session.MediaController; -import android.media.session.PlaybackState; import android.text.TextUtils; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.wm.shell.R; +import java.util.Objects; + /** * A notification that informs users that PIP is running and also provides PIP controls. *

Once it's created, it will manage the PIP notification UI by itself except for handling * configuration changes. */ public class PipNotification { - private static final String TAG = "PipNotification"; - private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName(); private static final boolean DEBUG = PipController.DEBUG; + private static final String TAG = "PipNotification"; + + private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName(); + public static final String NOTIFICATION_CHANNEL_TVPIP = "TPP"; static final String ACTION_MENU = "PipNotification.menu"; static final String ACTION_CLOSE = "PipNotification.close"; - public static final String NOTIFICATION_CHANNEL_TVPIP = "TPP"; - private final PackageManager mPackageManager; - - private final PipController mPipController; - private final NotificationManager mNotificationManager; private final Notification.Builder mNotificationBuilder; - private MediaController mMediaController; private String mDefaultTitle; private int mDefaultIconResId; @@ -71,7 +67,6 @@ public class PipNotification { @Override public void onPipEntered(String packageName) { mPackageName = packageName; - updateMediaControllerMetadata(); notifyPipNotification(); } @@ -103,51 +98,9 @@ public class PipNotification { } }; - private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() { - @Override - public void onPlaybackStateChanged(PlaybackState state) { - if (updateMediaControllerMetadata() && mNotified) { - // update notification - notifyPipNotification(); - } - } - - @Override - public void onMetadataChanged(MediaMetadata metadata) { - if (updateMediaControllerMetadata() && mNotified) { - // update notification - notifyPipNotification(); - } - } - }; - - private final PipController.MediaListener mPipMediaListener = - new PipController.MediaListener() { - @Override - public void onMediaControllerChanged() { - MediaController newController = mPipController.getMediaController(); - if (newController == null || mMediaController == newController) { - return; - } - if (mMediaController != null) { - mMediaController.unregisterCallback(mMediaControllerCallback); - } - mMediaController = newController; - if (mMediaController != null) { - mMediaController.registerCallback(mMediaControllerCallback); - } - if (updateMediaControllerMetadata() && mNotified) { - // update notification - notifyPipNotification(); - } - } - }; - public PipNotification(Context context, PipController pipController) { mPackageManager = context.getPackageManager(); - - mNotificationManager = (NotificationManager) context.getSystemService( - Context.NOTIFICATION_SERVICE); + mNotificationManager = context.getSystemService(NotificationManager.class); mNotificationBuilder = new Notification.Builder(context, NOTIFICATION_CHANNEL_TVPIP) .setLocalOnly(true) @@ -157,13 +110,19 @@ public class PipNotification { .setContentIntent(createPendingIntent(context, ACTION_MENU)) .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE))); - mPipController = pipController; pipController.addListener(mPipListener); - pipController.addMediaListener(mPipMediaListener); + pipController.getPipMediaController().addMetadataListener(this::onMediaMetadataChanged); onConfigurationChanged(context); } + private void onMediaMetadataChanged(MediaMetadata metadata) { + if (updateMediaControllerMetadata(metadata) && mNotified) { + // update notification + notifyPipNotification(); + } + } + /** * Called by {@link PipController} when the configuration is changed. */ @@ -199,28 +158,28 @@ public class PipNotification { mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP); } - private boolean updateMediaControllerMetadata() { + private boolean updateMediaControllerMetadata(MediaMetadata metadata) { String title = null; Bitmap art = null; - if (mPipController.getMediaController() != null) { - MediaMetadata metadata = mPipController.getMediaController().getMetadata(); - if (metadata != null) { - title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE); - if (TextUtils.isEmpty(title)) { - title = metadata.getString(MediaMetadata.METADATA_KEY_TITLE); - } - art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); - if (art == null) { - art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART); - } + if (metadata != null) { + title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE); + if (TextUtils.isEmpty(title)) { + title = metadata.getString(MediaMetadata.METADATA_KEY_TITLE); + } + art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); + if (art == null) { + art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART); } } - if (!TextUtils.equals(title, mMediaTitle) || art != mArt) { - mMediaTitle = title; - mArt = art; - return true; + + if (TextUtils.equals(title, mMediaTitle) && Objects.equals(art, mArt)) { + return false; } - return false; + + mMediaTitle = title; + mArt = art; + + return true; } diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java index 6bedd392ef3ab..9701b40a06a66 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java @@ -17,8 +17,6 @@ package com.android.systemui.wmshell; import android.content.Context; -import android.os.Handler; -import android.view.LayoutInflater; import com.android.systemui.dagger.WMSingleton; import com.android.wm.shell.ShellTaskOrganizer; @@ -27,6 +25,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipBoundsHandler; import com.android.wm.shell.pip.PipBoundsState; +import com.android.wm.shell.pip.PipMediaController; import com.android.wm.shell.pip.PipSurfaceTransactionHelper; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipUiEventLogger; @@ -53,6 +52,7 @@ public abstract class TvPipModule { PipBoundsState pipBoundsState, PipBoundsHandler pipBoundsHandler, PipTaskOrganizer pipTaskOrganizer, + PipMediaController pipMediaController, WindowManagerShellWrapper windowManagerShellWrapper) { return Optional.of( new PipController( @@ -60,16 +60,15 @@ public abstract class TvPipModule { pipBoundsState, pipBoundsHandler, pipTaskOrganizer, + pipMediaController, windowManagerShellWrapper)); } @WMSingleton @Provides static PipControlsViewController providePipControlsViewController( - PipControlsView pipControlsView, PipController pipController, - LayoutInflater layoutInflater, Handler handler) { - return new PipControlsViewController(pipControlsView, pipController, layoutInflater, - handler); + PipControlsView pipControlsView, PipController pipController) { + return new PipControlsViewController(pipControlsView, pipController); } @WMSingleton