Refactor .tv.PipNotification

Make TvPipNotificationController (formerly PipNotification) responsible
for handling broadcasts sent from the Pip StatusBarNotification.
Previouslt TV PipContoller was in charge of that.
Also, as mentioned above, rename PipNotification to
TvPipNotificationController.

Bug: 153784643
Test: atest WMShellFlickerTests:TvPipNotificationTests
Change-Id: Iabdf5ee9d464653e233aee9044ac8cbb26478dea
This commit is contained in:
Sergey Nikolaienkov
2020-12-23 09:45:18 +00:00
parent bfc6604163
commit 068369c26a
5 changed files with 112 additions and 53 deletions

View File

@@ -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,

View File

@@ -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;
* <p>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();
}
}

View File

@@ -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
tag == "TvPip" && title == expectedTitle

View File

@@ -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) {

View File

@@ -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<LegacySplitScreen> splitScreenOptional, DisplayController displayController,
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
tvMenuController, pipSurfaceTransactionHelper, splitScreenOptional,
tvPipMenuController, pipSurfaceTransactionHelper, splitScreenOptional,
displayController, pipUiEventLogger, shellTaskOrganizer);
}
}