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

Commit ff26a354 authored by Jacqueline Bronger's avatar Jacqueline Bronger
Browse files

Unify TvPipAction execution code path.

Instead of routing the system actions through the TvPipMenuController
and the broadcasts through the TvPipNotificationController, move the
BroadcastReceiver into the TvPipController and decide on what system
actions to do in there.

Bug: 258653494
Test: manual
Change-Id: I2b616125cd1b77e333a69b6875337abd5cd0fdf4
parent 5e56e0c0
Loading
Loading
Loading
Loading
+5 −18
Original line number Diff line number Diff line
@@ -39,7 +39,6 @@ import com.android.wm.shell.pip.PipTaskOrganizer;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.pip.PipUiEventLogger;
import com.android.wm.shell.pip.tv.TvPipActionsProvider;
import com.android.wm.shell.pip.tv.TvPipBoundsAlgorithm;
import com.android.wm.shell.pip.tv.TvPipBoundsController;
import com.android.wm.shell.pip.tv.TvPipBoundsState;
@@ -76,13 +75,13 @@ public abstract class TvPipModule {
            PipTaskOrganizer pipTaskOrganizer,
            TvPipMenuController tvPipMenuController,
            PipMediaController pipMediaController,
            TvPipActionsProvider tvPipActionsProvider,
            PipTransitionController pipTransitionController,
            TvPipNotificationController tvPipNotificationController,
            TaskStackListenerImpl taskStackListener,
            PipParamsChangedForwarder pipParamsChangedForwarder,
            DisplayController displayController,
            WindowManagerShellWrapper windowManagerShellWrapper,
            @ShellMainThread Handler mainHandler, // needed for registerReceiverForAllUsers()
            @ShellMainThread ShellExecutor mainExecutor) {
        return Optional.of(
                TvPipController.create(
@@ -97,12 +96,12 @@ public abstract class TvPipModule {
                        pipTransitionController,
                        tvPipMenuController,
                        pipMediaController,
                        tvPipActionsProvider,
                        tvPipNotificationController,
                        taskStackListener,
                        pipParamsChangedForwarder,
                        displayController,
                        windowManagerShellWrapper,
                        mainHandler,
                        mainExecutor));
    }

@@ -160,22 +159,17 @@ public abstract class TvPipModule {
            Context context,
            TvPipBoundsState tvPipBoundsState,
            SystemWindows systemWindows,
            TvPipActionsProvider tvPipActionsProvider,
            @ShellMainThread Handler mainHandler) {
        return new TvPipMenuController(context, tvPipBoundsState, systemWindows, mainHandler,
                tvPipActionsProvider);
        return new TvPipMenuController(context, tvPipBoundsState, systemWindows, mainHandler);
    }

    // Handler needed for registerReceiverForAllUsers()
    @WMSingleton
    @Provides
    static TvPipNotificationController provideTvPipNotificationController(Context context,
            PipMediaController pipMediaController,
            PipParamsChangedForwarder pipParamsChangedForwarder,
            TvPipActionsProvider tvPipActionsProvider,
            @ShellMainThread Handler mainHandler) {
            PipParamsChangedForwarder pipParamsChangedForwarder) {
        return new TvPipNotificationController(context, pipMediaController,
                pipParamsChangedForwarder, tvPipActionsProvider, mainHandler);
                pipParamsChangedForwarder);
    }

    @WMSingleton
@@ -227,11 +221,4 @@ public abstract class TvPipModule {
            @ShellMainThread ShellExecutor mainExecutor) {
        return new PipAppOpsListener(context, pipTaskOrganizer::removePip, mainExecutor);
    }

    @WMSingleton
    @Provides
    static TvPipActionsProvider provideTvPipActionsProvider(Context context,
            PipMediaController pipMediaController) {
        return new TvPipActionsProvider(context, pipMediaController);
    }
}
+12 −13
Original line number Diff line number Diff line
@@ -23,17 +23,14 @@ import android.app.PendingIntent;
import android.content.Context;
import android.os.Handler;

import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TvWindowMenuActionButton;
import com.android.wm.shell.protolog.ShellProtoLogGroup;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;

abstract class TvPipAction {

    private static final String TAG = TvPipAction.class.getSimpleName();

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"ACTION_"}, value = {
            ACTION_FULLSCREEN,
@@ -56,8 +53,13 @@ abstract class TvPipAction {
    @ActionType
    private final int mActionType;

    TvPipAction(@ActionType int actionType) {
    @NonNull
    private final SystemActionsHandler mSystemActionsHandler;

    TvPipAction(@ActionType int actionType, @NonNull SystemActionsHandler systemActionsHandler) {
        Objects.requireNonNull(systemActionsHandler);
        mActionType = actionType;
        mSystemActionsHandler = systemActionsHandler;
    }

    boolean isCloseAction() {
@@ -73,16 +75,13 @@ abstract class TvPipAction {

    abstract PendingIntent getPendingIntent();

    void executePendingIntent() {
        if (getPendingIntent() == null) return;
        try {
            getPendingIntent().send();
        } catch (PendingIntent.CanceledException e) {
            ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: Failed to send action, %s", TAG, e);
        }
    void executeAction() {
        mSystemActionsHandler.executeAction(mActionType);
    }

    abstract Notification.Action toNotificationAction(Context context);

    interface SystemActionsHandler {
        void executeAction(@TvPipAction.ActionType int actionType);
    }
}
+25 −12
Original line number Diff line number Diff line
@@ -23,10 +23,10 @@ import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_CUSTOM_CLOSE;
import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_EXPAND_COLLAPSE;
import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_FULLSCREEN;
import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_MOVE;
import static com.android.wm.shell.pip.tv.TvPipNotificationController.ACTION_CLOSE_PIP;
import static com.android.wm.shell.pip.tv.TvPipNotificationController.ACTION_MOVE_PIP;
import static com.android.wm.shell.pip.tv.TvPipNotificationController.ACTION_TOGGLE_EXPANDED_PIP;
import static com.android.wm.shell.pip.tv.TvPipNotificationController.ACTION_TO_FULLSCREEN;
import static com.android.wm.shell.pip.tv.TvPipController.ACTION_CLOSE_PIP;
import static com.android.wm.shell.pip.tv.TvPipController.ACTION_MOVE_PIP;
import static com.android.wm.shell.pip.tv.TvPipController.ACTION_TOGGLE_EXPANDED_PIP;
import static com.android.wm.shell.pip.tv.TvPipController.ACTION_TO_FULLSCREEN;

import android.annotation.NonNull;
import android.app.RemoteAction;
@@ -47,13 +47,14 @@ import java.util.List;
 * changes to the actions, including the custom app actions and media actions. Other components can
 * listen to those changes.
 */
public class TvPipActionsProvider {
public class TvPipActionsProvider implements TvPipAction.SystemActionsHandler {
    private static final String TAG = TvPipActionsProvider.class.getSimpleName();

    private static final int CLOSE_ACTION_INDEX = 1;
    private static final int FIRST_CUSTOM_ACTION_INDEX = 2;

    private final List<Listener> mListeners = new ArrayList<>();
    private final TvPipAction.SystemActionsHandler mSystemActionsHandler;

    private final List<TvPipAction> mActionsList;
    private final TvPipSystemAction mDefaultCloseAction;
@@ -62,26 +63,37 @@ public class TvPipActionsProvider {
    private final List<RemoteAction> mMediaActions = new ArrayList<>();
    private final List<RemoteAction> mAppActions = new ArrayList<>();

    public TvPipActionsProvider(Context context, PipMediaController pipMediaController) {
    public TvPipActionsProvider(Context context, PipMediaController pipMediaController,
            TvPipAction.SystemActionsHandler systemActionsHandler) {
        mSystemActionsHandler = systemActionsHandler;

        mActionsList = new ArrayList<>();
        mActionsList.add(new TvPipSystemAction(ACTION_FULLSCREEN, R.string.pip_fullscreen,
                R.drawable.pip_ic_fullscreen_white, ACTION_TO_FULLSCREEN, context));
                R.drawable.pip_ic_fullscreen_white, ACTION_TO_FULLSCREEN, context,
                mSystemActionsHandler));

        mDefaultCloseAction = new TvPipSystemAction(ACTION_CLOSE, R.string.pip_close,
                R.drawable.pip_ic_close_white, ACTION_CLOSE_PIP, context);
                R.drawable.pip_ic_close_white, ACTION_CLOSE_PIP, context, mSystemActionsHandler);
        mActionsList.add(mDefaultCloseAction);

        mActionsList.add(new TvPipSystemAction(ACTION_MOVE, R.string.pip_move,
                R.drawable.pip_ic_move_white, ACTION_MOVE_PIP, context));
                R.drawable.pip_ic_move_white, ACTION_MOVE_PIP, context, mSystemActionsHandler));

        mExpandCollapseAction = new TvPipSystemAction(ACTION_EXPAND_COLLAPSE, R.string.pip_collapse,
                R.drawable.pip_ic_collapse, ACTION_TOGGLE_EXPANDED_PIP, context);
                R.drawable.pip_ic_collapse, ACTION_TOGGLE_EXPANDED_PIP, context,
                mSystemActionsHandler);
        mActionsList.add(mExpandCollapseAction);

        pipMediaController.addActionListener(this::onMediaActionsChanged);
    }

    @Override
    public void executeAction(@TvPipAction.ActionType int actionType) {
        if (mSystemActionsHandler != null) {
            mSystemActionsHandler.executeAction(actionType);
        }
    }

    private void notifyActionsChanged(int added, int changed, int startIndex) {
        for (Listener listener : mListeners) {
            listener.onActionsChanged(added, changed, startIndex);
@@ -93,7 +105,8 @@ public class TvPipActionsProvider {
        // Update close action.
        mActionsList.set(CLOSE_ACTION_INDEX,
                closeAction == null ? mDefaultCloseAction
                        : new TvPipCustomAction(ACTION_CUSTOM_CLOSE, closeAction));
                        : new TvPipCustomAction(ACTION_CUSTOM_CLOSE, closeAction,
                                mSystemActionsHandler));
        notifyActionsChanged(/* added= */ 0, /* updated= */ 1, CLOSE_ACTION_INDEX);

        // Replace custom actions with new ones.
@@ -146,7 +159,7 @@ public class TvPipActionsProvider {

        List<TvPipAction> actions = new ArrayList<>();
        for (RemoteAction action : newCustomActions) {
            actions.add(new TvPipCustomAction(ACTION_CUSTOM, action));
            actions.add(new TvPipCustomAction(ACTION_CUSTOM, action, mSystemActionsHandler));
        }
        mActionsList.addAll(FIRST_CUSTOM_ACTION_INDEX, actions);

+136 −39
Original line number Diff line number Diff line
@@ -22,13 +22,16 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import android.annotation.IntDef;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.TaskInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.view.Gravity;

@@ -67,8 +70,8 @@ import java.util.Set;
 */
public class TvPipController implements PipTransitionController.PipTransitionCallback,
        TvPipBoundsController.PipBoundsListener, TvPipMenuController.Delegate,
        TvPipNotificationController.Delegate, DisplayController.OnDisplaysChangedListener,
        ConfigurationChangeListener, UserChangeListener {
        DisplayController.OnDisplaysChangedListener, ConfigurationChangeListener,
        UserChangeListener {
    private static final String TAG = "TvPipController";

    private static final int NONEXISTENT_TASK_ID = -1;
@@ -98,6 +101,17 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
     */
    private static final int STATE_PIP_MENU = 2;

    static final String ACTION_SHOW_PIP_MENU =
            "com.android.wm.shell.pip.tv.notification.action.SHOW_PIP_MENU";
    static final String ACTION_CLOSE_PIP =
            "com.android.wm.shell.pip.tv.notification.action.CLOSE_PIP";
    static final String ACTION_MOVE_PIP =
            "com.android.wm.shell.pip.tv.notification.action.MOVE_PIP";
    static final String ACTION_TOGGLE_EXPANDED_PIP =
            "com.android.wm.shell.pip.tv.notification.action.TOGGLE_EXPANDED_PIP";
    static final String ACTION_TO_FULLSCREEN =
            "com.android.wm.shell.pip.tv.notification.action.FULLSCREEN";

    private final Context mContext;

    private final ShellController mShellController;
@@ -116,14 +130,16 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
    private final DisplayController mDisplayController;
    private final WindowManagerShellWrapper mWmShellWrapper;
    private final ShellExecutor mMainExecutor;
    private final Handler mMainHandler; // For registering the broadcast receiver
    private final TvPipImpl mImpl = new TvPipImpl();

    private final ActionBroadcastReceiver mActionBroadcastReceiver;

    @State
    private int mState = STATE_NO_PIP;
    private int mPreviousGravity = TvPipBoundsState.DEFAULT_TV_GRAVITY;
    private int mPinnedTaskId = NONEXISTENT_TASK_ID;

    private RemoteAction mCloseAction;
    // How long the shell will wait for the app to close the PiP if a custom action is set.
    private int mPipForceCloseDelay;

@@ -142,12 +158,12 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
            PipTransitionController pipTransitionController,
            TvPipMenuController tvPipMenuController,
            PipMediaController pipMediaController,
            TvPipActionsProvider tvPipActionsProvider,
            TvPipNotificationController pipNotificationController,
            TaskStackListenerImpl taskStackListener,
            PipParamsChangedForwarder pipParamsChangedForwarder,
            DisplayController displayController,
            WindowManagerShellWrapper wmShell,
            Handler mainHandler,
            ShellExecutor mainExecutor) {
        return new TvPipController(
                context,
@@ -161,12 +177,12 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
                pipTransitionController,
                tvPipMenuController,
                pipMediaController,
                tvPipActionsProvider,
                pipNotificationController,
                taskStackListener,
                pipParamsChangedForwarder,
                displayController,
                wmShell,
                mainHandler,
                mainExecutor).mImpl;
    }

@@ -182,14 +198,15 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
            PipTransitionController pipTransitionController,
            TvPipMenuController tvPipMenuController,
            PipMediaController pipMediaController,
            TvPipActionsProvider tvPipActionsProvider,
            TvPipNotificationController pipNotificationController,
            TaskStackListenerImpl taskStackListener,
            PipParamsChangedForwarder pipParamsChangedForwarder,
            DisplayController displayController,
            WindowManagerShellWrapper wmShellWrapper,
            Handler mainHandler,
            ShellExecutor mainExecutor) {
        mContext = context;
        mMainHandler = mainHandler;
        mMainExecutor = mainExecutor;
        mShellController = shellController;
        mDisplayController = displayController;
@@ -202,13 +219,17 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
        mTvPipBoundsController.setListener(this);

        mPipMediaController = pipMediaController;
        mTvPipActionsProvider = tvPipActionsProvider;
        mTvPipActionsProvider = new TvPipActionsProvider(context, pipMediaController,
                this::executeAction);

        mPipNotificationController = pipNotificationController;
        mPipNotificationController.setDelegate(this);
        mPipNotificationController.setTvPipActionsProvider(mTvPipActionsProvider);

        mTvPipMenuController = tvPipMenuController;
        mTvPipMenuController.setDelegate(this);
        mTvPipMenuController.setTvPipActionsProvider(mTvPipActionsProvider);

        mActionBroadcastReceiver = new ActionBroadcastReceiver();

        mAppOpsListener = pipAppOpsListener;
        mPipTaskOrganizer = pipTaskOrganizer;
@@ -261,9 +282,10 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
     * Starts the process if bringing up the Pip menu if by issuing a command to move Pip
     * task/window to the "Menu" position. We'll show the actual Menu UI (eg. actions) once the Pip
     * task/window is properly positioned in {@link #onPipTransitionFinished(int)}.
     *
     * @param moveMenu If true, show the moveMenu, otherwise show the regular menu.
     */
    @Override
    public void showPictureInPictureMenu() {
    private void showPictureInPictureMenu(boolean moveMenu) {
        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "%s: showPictureInPictureMenu(), state=%s", TAG, stateToName(mState));

@@ -274,7 +296,11 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
        }

        setState(STATE_PIP_MENU);
        if (moveMenu) {
            mTvPipMenuController.showMovementMenu();
        } else {
            mTvPipMenuController.showMenu();
        }
        updatePinnedStackBounds();
    }

@@ -294,8 +320,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
    /**
     * Opens the "Pip-ed" Activity fullscreen.
     */
    @Override
    public void movePipToFullscreen() {
    private void movePipToFullscreen() {
        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "%s: movePipToFullscreen(), state=%s", TAG, stateToName(mState));

@@ -303,8 +328,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
        onPipDisappeared();
    }

    @Override
    public void togglePipExpansion() {
    private void togglePipExpansion() {
        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "%s: togglePipExpansion()", TAG);
        boolean expanding = !mTvPipBoundsState.isTvPipExpanded();
@@ -319,12 +343,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
        updatePinnedStackBounds();
    }

    @Override
    public void enterPipMovementMenu() {
        setState(STATE_PIP_MENU);
        mTvPipMenuController.showMovementMenuOnly();
    }

    @Override
    public void movePip(int keycode) {
        if (mTvPipBoundsAlgorithm.updateGravity(keycode)) {
@@ -384,23 +402,16 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
    /**
     * Closes Pip window.
     */
    @Override
    public void closePip() {
        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                "%s: closePip(), state=%s, loseAction=%s", TAG, stateToName(mState),
                mCloseAction);

        if (mCloseAction != null) {
            try {
                mCloseAction.getActionIntent().send();
            } catch (PendingIntent.CanceledException e) {
                ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                        "%s: Failed to send close action, %s", TAG, e);
            }
            mMainExecutor.executeDelayed(() -> closeCurrentPiP(mPinnedTaskId), mPipForceCloseDelay);
        } else {
        closeCurrentPiP(mPinnedTaskId);
    }

    /**
     * Force close the current PiP after some time in case the custom action hasn't done it by
     * itself.
     */
    public void customClosePip() {
        mMainExecutor.executeDelayed(() -> closeCurrentPiP(mPinnedTaskId), mPipForceCloseDelay);
    }

    private void closeCurrentPiP(int pinnedTaskId) {
@@ -430,6 +441,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
        mPinnedTaskId = pinnedTask.taskId;

        mPipMediaController.onActivityPinned();
        mActionBroadcastReceiver.register();
        mPipNotificationController.show(pinnedTask.topActivity.getPackageName());
    }

@@ -449,6 +461,8 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
                "%s: onPipDisappeared() state=%s", TAG, stateToName(mState));

        mPipNotificationController.dismiss();
        mActionBroadcastReceiver.unregister();

        mTvPipMenuController.closeMenu();
        mTvPipBoundsState.resetTvPipState();
        mTvPipBoundsController.onPipDismissed();
@@ -551,7 +565,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
                        "%s: onActionsChanged()", TAG);

                mTvPipActionsProvider.setAppActions(actions, closeAction);
                mCloseAction = closeAction;
            }

            @Override
@@ -678,6 +691,90 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
        }
    }

    private void executeAction(@TvPipAction.ActionType int actionType) {
        switch (actionType) {
            case TvPipAction.ACTION_FULLSCREEN:
                movePipToFullscreen();
                break;
            case TvPipAction.ACTION_CLOSE:
                closePip();
                break;
            case TvPipAction.ACTION_MOVE:
                showPictureInPictureMenu(/* moveMenu= */ true);
                break;
            case TvPipAction.ACTION_CUSTOM_CLOSE:
                customClosePip();
                break;
            case TvPipAction.ACTION_EXPAND_COLLAPSE:
                togglePipExpansion();
                break;
            default:
                // NOOP
                break;
        }
    }

    private class ActionBroadcastReceiver extends BroadcastReceiver {
        private static final String SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF";

        final IntentFilter mIntentFilter;

        {
            mIntentFilter = new IntentFilter();
            mIntentFilter.addAction(ACTION_CLOSE_PIP);
            mIntentFilter.addAction(ACTION_SHOW_PIP_MENU);
            mIntentFilter.addAction(ACTION_MOVE_PIP);
            mIntentFilter.addAction(ACTION_TOGGLE_EXPANDED_PIP);
            mIntentFilter.addAction(ACTION_TO_FULLSCREEN);
        }

        boolean mRegistered = false;

        void register() {
            if (mRegistered) return;

            mContext.registerReceiverForAllUsers(this, mIntentFilter, SYSTEMUI_PERMISSION,
                    mMainHandler);
            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();
            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: on(Broadcast)Receive(), action=%s", TAG, action);

            if (ACTION_SHOW_PIP_MENU.equals(action)) {
                showPictureInPictureMenu(/* moveMenu= */ false);
            } else {
                executeAction(getCorrespondingActionType(action));
            }
        }

        @TvPipAction.ActionType
        private int getCorrespondingActionType(String broadcast) {
            if (ACTION_CLOSE_PIP.equals(broadcast)) {
                return TvPipAction.ACTION_CLOSE;
            } else if (ACTION_MOVE_PIP.equals(broadcast)) {
                return TvPipAction.ACTION_MOVE;
            } else if (ACTION_TOGGLE_EXPANDED_PIP.equals(broadcast)) {
                return TvPipAction.ACTION_EXPAND_COLLAPSE;
            } else if (ACTION_TO_FULLSCREEN.equals(broadcast)) {
                return TvPipAction.ACTION_FULLSCREEN;
            }

            // Default: handle it like an action we don't know the content of.
            return TvPipAction.ACTION_CUSTOM;
        }
    }

    private class TvPipImpl implements Pip {
        // Not used
    }
+16 −2
Original line number Diff line number Diff line
@@ -27,7 +27,9 @@ import android.content.Context;
import android.os.Bundle;
import android.os.Handler;

import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TvWindowMenuActionButton;
import com.android.wm.shell.protolog.ShellProtoLogGroup;

import java.util.List;
import java.util.Objects;
@@ -38,11 +40,13 @@ import java.util.Objects;
 * android.app.PictureInPictureParams.Builder#setActions(List)}.
 */
public class TvPipCustomAction extends TvPipAction {
    private static final String TAG = TvPipCustomAction.class.getSimpleName();

    private final RemoteAction mRemoteAction;

    TvPipCustomAction(@ActionType int actionType, @NonNull RemoteAction remoteAction) {
        super(actionType);
    TvPipCustomAction(@ActionType int actionType, @NonNull RemoteAction remoteAction,
            SystemActionsHandler systemActionsHandler) {
        super(actionType, systemActionsHandler);
        Objects.requireNonNull(remoteAction);
        mRemoteAction = remoteAction;
    }
@@ -62,6 +66,16 @@ public class TvPipCustomAction extends TvPipAction {
        return mRemoteAction.getActionIntent();
    }

    void executeAction() {
        super.executeAction();
        try {
            mRemoteAction.getActionIntent().send();
        } catch (PendingIntent.CanceledException e) {
            ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                    "%s: Failed to send action, %s", TAG, e);
        }
    }

    @Override
    Notification.Action toNotificationAction(Context context) {
        Notification.Action.Builder builder = new Notification.Action.Builder(
Loading