Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 068369c2 authored by Sergey Nikolaienkov's avatar Sergey Nikolaienkov
Browse files

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
parent bfc66041
Loading
Loading
Loading
Loading
+9 −19
Original line number Diff line number Diff line
@@ -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,
+87 −18
Original line number Diff line number Diff line
@@ -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();
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -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
+2 −2
Original line number Diff line number Diff line
@@ -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) {
+13 −13
Original line number Diff line number Diff line
@@ -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);
    }
}