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 ffa6c9921d97e..5f59f5135179a 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 @@ -21,9 +21,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.Intent.ACTION_MEDIA_RESOURCE_GRANTED; -import static com.android.wm.shell.pip.tv.PipNotification.ACTION_CLOSE; -import static com.android.wm.shell.pip.tv.PipNotification.ACTION_MENU; - import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.ActivityTaskManager.RootTaskInfo; @@ -61,7 +58,7 @@ import java.util.Objects; * Manages the picture-in-picture (PIP) UI and states. */ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallback, - TvPipMenuController.Delegate { + TvPipMenuController.Delegate, TvPipNotificationController.Delegate { private static final String TAG = "TvPipController"; static final boolean DEBUG = false; @@ -91,7 +88,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac private final PipTaskOrganizer mPipTaskOrganizer; private final PipMediaController mPipMediaController; private final TvPipMenuController mTvPipMenuController; - private final PipNotification mPipNotification; + private final TvPipNotificationController mPipNotificationController; private IActivityTaskManager mActivityTaskManager; private int mState = STATE_NO_PIP; @@ -120,12 +117,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac Log.d(TAG, "mBroadcastReceiver, action: " + intent.getAction()); } switch (intent.getAction()) { - case ACTION_MENU: - showPictureInPictureMenu(); - break; - case ACTION_CLOSE: - closePip(); - break; case ACTION_MEDIA_RESOURCE_GRANTED: String[] packageNames = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); int resourceType = intent.getIntExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE, @@ -190,12 +181,13 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac PipTaskOrganizer pipTaskOrganizer, TvPipMenuController tvPipMenuController, PipMediaController pipMediaController, - PipNotification pipNotification, + TvPipNotificationController tvPipNotificationController, TaskStackListenerImpl taskStackListener, WindowManagerShellWrapper windowManagerShellWrapper) { mContext = context; mPipBoundsState = pipBoundsState; - mPipNotification = pipNotification; + mPipNotificationController = tvPipNotificationController; + mPipNotificationController.setDelegate(this); mPipBoundsAlgorithm = pipBoundsAlgorithm; mPipMediaController = pipMediaController; mTvPipMenuController = tvPipMenuController; @@ -213,8 +205,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mActivityTaskManager = ActivityTaskManager.getService(); final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ACTION_CLOSE); - intentFilter.addAction(ACTION_MENU); intentFilter.addAction(ACTION_MEDIA_RESOURCE_GRANTED); mContext.registerReceiver(mBroadcastReceiver, intentFilter, UserHandle.USER_ALL); @@ -273,7 +263,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac @Override public void onConfigurationChanged(Configuration newConfig) { loadConfigurationsAndApply(newConfig); - mPipNotification.onConfigurationChanged(mContext); + mPipNotificationController.onConfigurationChanged(mContext); } /** @@ -315,7 +305,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mPinnedStackId = INVALID_STACK_ID; } } - mPipNotification.dismiss(); + mPipNotificationController.dismiss(); mTvPipMenuController.hideMenu(); mHandler.removeCallbacks(mClosePipRunnable); } @@ -334,7 +324,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac mPipTaskId = TASK_ID_NO_PIP; mTvPipMenuController.hideMenu(); - mPipNotification.dismiss(); + mPipNotificationController.dismiss(); resizePinnedStack(STATE_NO_PIP); } @@ -359,7 +349,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac // Set state to STATE_PIP so we show it when the pinned stack animation ends. mState = STATE_PIP; mPipMediaController.onActivityPinned(); - mPipNotification.show(packageName); + mPipNotificationController.show(packageName); } private void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, 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/TvPipNotificationController.java similarity index 63% rename from libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/PipNotification.java rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipNotificationController.java index 5716c7fc71624..a2675431fdddc 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/TvPipNotificationController.java @@ -19,14 +19,17 @@ package com.android.wm.shell.pip.tv; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.graphics.Bitmap; import android.media.MediaMetadata; +import android.os.UserHandle; import android.text.TextUtils; +import android.util.Log; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.wm.shell.R; @@ -39,22 +42,27 @@ import java.util.Objects; *

Once it's created, it will manage the PIP notification UI by itself except for handling * configuration changes. */ -public class PipNotification { +public class TvPipNotificationController { + private static final String TAG = "TvPipNotification"; 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"; + // Referenced in com.android.systemui.util.NotificationChannels. + public static final String NOTIFICATION_CHANNEL = "TVPIP"; + private static final String NOTIFICATION_TAG = "TvPip"; - static final String ACTION_MENU = "PipNotification.menu"; - static final String ACTION_CLOSE = "PipNotification.close"; + private static final String ACTION_SHOW_PIP_MENU = + "com.android.wm.shell.pip.tv.notification.action.SHOW_PIP_MENU"; + private static final String ACTION_CLOSE_PIP = + "com.android.wm.shell.pip.tv.notification.action.CLOSE_PIP"; + private final Context mContext; private final PackageManager mPackageManager; private final NotificationManager mNotificationManager; private final Notification.Builder mNotificationBuilder; + private final ActionBroadcastReceiver mActionBroadcastReceiver; + private Delegate mDelegate; private String mDefaultTitle; - private int mDefaultIconResId; /** Package name for the application that owns PiP window. */ private String mPackageName; @@ -62,32 +70,56 @@ public class PipNotification { private String mMediaTitle; private Bitmap mArt; - public PipNotification(Context context, PipMediaController pipMediaController) { + public TvPipNotificationController(Context context, PipMediaController pipMediaController) { + mContext = context; mPackageManager = context.getPackageManager(); mNotificationManager = context.getSystemService(NotificationManager.class); - mNotificationBuilder = new Notification.Builder(context, NOTIFICATION_CHANNEL_TVPIP) + mNotificationBuilder = new Notification.Builder(context, NOTIFICATION_CHANNEL) .setLocalOnly(true) .setOngoing(false) .setCategory(Notification.CATEGORY_SYSTEM) + .setShowWhen(true) + .setSmallIcon(R.drawable.pip_icon) .extend(new Notification.TvExtender() - .setContentIntent(createPendingIntent(context, ACTION_MENU)) - .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE))); + .setContentIntent(createPendingIntent(context, ACTION_SHOW_PIP_MENU)) + .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE_PIP))); + + mActionBroadcastReceiver = new ActionBroadcastReceiver(); pipMediaController.addMetadataListener(this::onMediaMetadataChanged); onConfigurationChanged(context); } + void setDelegate(Delegate delegate) { + if (DEBUG) Log.d(TAG, "setDelegate(), delegate=" + delegate); + if (mDelegate != null) { + throw new IllegalStateException( + "The delegate has already been set and should not change."); + } + if (delegate == null) { + throw new IllegalArgumentException("The delegate must not be null."); + } + + mDelegate = delegate; + } + void show(String packageName) { + if (mDelegate == null) { + throw new IllegalStateException("Delegate is not set."); + } + mPackageName = packageName; update(); + mActionBroadcastReceiver.register(); } void dismiss() { mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP); mNotified = false; mPackageName = null; + mActionBroadcastReceiver.unregister(); } private void onMediaMetadataChanged(MediaMetadata metadata) { @@ -101,11 +133,9 @@ public class PipNotification { * Called by {@link PipController} when the configuration is changed. */ void onConfigurationChanged(Context context) { - Resources res = context.getResources(); - mDefaultTitle = res.getString(R.string.pip_notification_unknown_title); - mDefaultIconResId = R.drawable.pip_icon; + mDefaultTitle = context.getResources().getString(R.string.pip_notification_unknown_title); if (mNotified) { - // update notification + // Update the notification. update(); } } @@ -113,9 +143,7 @@ public class PipNotification { private void update() { mNotified = true; mNotificationBuilder - .setShowWhen(true) .setWhen(System.currentTimeMillis()) - .setSmallIcon(mDefaultIconResId) .setContentTitle(getNotificationTitle()); if (mArt != null) { mNotificationBuilder.setStyle(new Notification.BigPictureStyle() @@ -178,4 +206,45 @@ public class PipNotification { return PendingIntent.getBroadcast(context, 0, new Intent(action), PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); } + + private class ActionBroadcastReceiver extends BroadcastReceiver { + final IntentFilter mIntentFilter; + { + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(ACTION_CLOSE_PIP); + mIntentFilter.addAction(ACTION_SHOW_PIP_MENU); + } + boolean mRegistered = false; + + void register() { + if (mRegistered) return; + + mContext.registerReceiver(this, mIntentFilter, UserHandle.USER_ALL); + mRegistered = true; + } + + void unregister() { + if (!mRegistered) return; + + mContext.unregisterReceiver(this); + mRegistered = false; + } + + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (DEBUG) Log.d(TAG, "on(Broadcast)Receive(), action=" + action); + + if (ACTION_SHOW_PIP_MENU.equals(action)) { + mDelegate.showPictureInPictureMenu(); + } else if (ACTION_CLOSE_PIP.equals(action)) { + mDelegate.closePip(); + } + } + } + + interface Delegate { + void showPictureInPictureMenu(); + void closePip(); + } } diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt index 75388bf2a189d..5258e90300750 100644 --- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt +++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/TvPipNotificationTests.kt @@ -171,4 +171,4 @@ private val StatusBarNotification.deleteIntent: PendingIntent? get() = tvExtensions?.getParcelable("delete_intent") private fun StatusBarNotification.isPipNotificationWithTitle(expectedTitle: String): Boolean = - tag == "PipNotification" && title == expectedTitle \ No newline at end of file + tag == "TvPip" && title == expectedTitle \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java index 0d63324966fd2..0ba072e9e72f5 100644 --- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java +++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java @@ -25,7 +25,7 @@ import android.provider.Settings; import com.android.internal.annotations.VisibleForTesting; import com.android.systemui.R; import com.android.systemui.SystemUI; -import com.android.wm.shell.pip.tv.PipNotification; +import com.android.wm.shell.pip.tv.TvPipNotificationController; import java.util.Arrays; @@ -36,7 +36,7 @@ public class NotificationChannels extends SystemUI { public static String GENERAL = "GEN"; public static String STORAGE = "DSK"; public static String BATTERY = "BAT"; - public static String TVPIP = PipNotification.NOTIFICATION_CHANNEL_TVPIP; + public static String TVPIP = TvPipNotificationController.NOTIFICATION_CHANNEL; // "TVPIP" public static String HINTS = "HNT"; public NotificationChannels(Context context) { diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java index 4d3af9c011539..438704852617b 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/TvPipModule.java @@ -33,8 +33,8 @@ import com.android.wm.shell.pip.PipSurfaceTransactionHelper; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipUiEventLogger; import com.android.wm.shell.pip.tv.PipController; -import com.android.wm.shell.pip.tv.PipNotification; import com.android.wm.shell.pip.tv.TvPipMenuController; +import com.android.wm.shell.pip.tv.TvPipNotificationController; import java.util.Optional; @@ -55,7 +55,7 @@ public abstract class TvPipModule { PipTaskOrganizer pipTaskOrganizer, TvPipMenuController tvPipMenuController, PipMediaController pipMediaController, - PipNotification pipNotification, + TvPipNotificationController tvPipNotificationController, TaskStackListenerImpl taskStackListener, WindowManagerShellWrapper windowManagerShellWrapper) { return Optional.of( @@ -66,18 +66,11 @@ public abstract class TvPipModule { pipTaskOrganizer, tvPipMenuController, pipMediaController, - pipNotification, + tvPipNotificationController, taskStackListener, windowManagerShellWrapper)); } - @WMSingleton - @Provides - static PipNotification providePipNotification(Context context, - PipMediaController pipMediaController) { - return new PipNotification(context, pipMediaController); - } - @WMSingleton @Provides static PipBoundsAlgorithm providePipBoundsHandler(Context context, @@ -93,7 +86,7 @@ public abstract class TvPipModule { @WMSingleton @Provides - static TvPipMenuController providesPipTvMenuController( + static TvPipMenuController providesTvPipMenuController( Context context, PipBoundsState pipBoundsState, SystemWindows systemWindows, @@ -101,17 +94,24 @@ public abstract class TvPipModule { return new TvPipMenuController(context, pipBoundsState, systemWindows, pipMediaController); } + @WMSingleton + @Provides + static TvPipNotificationController provideTvPipNotificationController(Context context, + PipMediaController pipMediaController) { + return new TvPipNotificationController(context, pipMediaController); + } + @WMSingleton @Provides static PipTaskOrganizer providePipTaskOrganizer(Context context, - TvPipMenuController tvMenuController, + TvPipMenuController tvPipMenuController, PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm, PipSurfaceTransactionHelper pipSurfaceTransactionHelper, Optional splitScreenOptional, DisplayController displayController, PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) { return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm, - tvMenuController, pipSurfaceTransactionHelper, splitScreenOptional, + tvPipMenuController, pipSurfaceTransactionHelper, splitScreenOptional, displayController, pipUiEventLogger, shellTaskOrganizer); } }