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