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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
mTvPipMenuController.showMenu();
|
||||
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);
|
||||
closeCurrentPiP(mPinnedTaskId);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -57,13 +57,14 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
private final SystemWindows mSystemWindows;
|
||||
private final TvPipBoundsState mTvPipBoundsState;
|
||||
private final Handler mMainHandler;
|
||||
private final TvPipActionsProvider mTvPipActionsProvider;
|
||||
private TvPipActionsProvider mTvPipActionsProvider;
|
||||
|
||||
private Delegate mDelegate;
|
||||
private SurfaceControl mLeash;
|
||||
private TvPipMenuView mPipMenuView;
|
||||
private View mPipBackgroundView;
|
||||
|
||||
private boolean mMenuIsOpen;
|
||||
// User can actively move the PiP via the DPAD.
|
||||
private boolean mInMoveMode;
|
||||
// Used when only showing the move menu since we want to close the menu completely when
|
||||
@@ -77,13 +78,11 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
Matrix mMoveTransform = new Matrix();
|
||||
|
||||
public TvPipMenuController(Context context, TvPipBoundsState tvPipBoundsState,
|
||||
SystemWindows systemWindows, Handler mainHandler,
|
||||
TvPipActionsProvider tvPipActionsProvider) {
|
||||
SystemWindows systemWindows, Handler mainHandler) {
|
||||
mContext = context;
|
||||
mTvPipBoundsState = tvPipBoundsState;
|
||||
mSystemWindows = systemWindows;
|
||||
mMainHandler = mainHandler;
|
||||
mTvPipActionsProvider = tvPipActionsProvider;
|
||||
|
||||
// We need to "close" the menu the platform call for all the system dialogs to close (for
|
||||
// example, on the Home button press).
|
||||
@@ -112,6 +111,10 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
mDelegate = delegate;
|
||||
}
|
||||
|
||||
void setTvPipActionsProvider(TvPipActionsProvider tvPipActionsProvider) {
|
||||
mTvPipActionsProvider = tvPipActionsProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach(SurfaceControl leash) {
|
||||
if (mDelegate == null) {
|
||||
@@ -143,6 +146,11 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
}
|
||||
|
||||
private void attachPipMenuView() {
|
||||
if (mTvPipActionsProvider == null) {
|
||||
ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||
"%s: Actions provider is not set", TAG);
|
||||
return;
|
||||
}
|
||||
mPipMenuView = new TvPipMenuView(mContext, mMainHandler, this, mTvPipActionsProvider);
|
||||
setUpViewSurfaceZOrder(mPipMenuView, 1);
|
||||
addPipMenuViewToSystemWindows(mPipMenuView, MENU_WINDOW_TITLE);
|
||||
@@ -186,12 +194,16 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
});
|
||||
}
|
||||
|
||||
void showMovementMenuOnly() {
|
||||
void showMovementMenu() {
|
||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||
"%s: showMovementMenuOnly()", TAG);
|
||||
setInMoveMode(true);
|
||||
mCloseAfterExitMoveMenu = true;
|
||||
showMenuInternal();
|
||||
if (mMenuIsOpen) {
|
||||
mPipMenuView.showMoveMenu(mDelegate.getPipGravity());
|
||||
} else {
|
||||
mCloseAfterExitMoveMenu = true;
|
||||
showMenuInternal();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -207,6 +219,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
return;
|
||||
}
|
||||
|
||||
mMenuIsOpen = true;
|
||||
grantPipMenuFocus(true);
|
||||
if (mInMoveMode) {
|
||||
mPipMenuView.showMoveMenu(mDelegate.getPipGravity());
|
||||
@@ -237,6 +250,8 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
if (mPipMenuView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mMenuIsOpen = false;
|
||||
mPipMenuView.hideAllUserControls();
|
||||
grantPipMenuFocus(false);
|
||||
mDelegate.onMenuClosed();
|
||||
@@ -256,30 +271,20 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnterMoveMode() {
|
||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||
"%s: onEnterMoveMode - %b, close when exiting move menu: %b", TAG, mInMoveMode,
|
||||
mCloseAfterExitMoveMenu);
|
||||
setInMoveMode(true);
|
||||
mPipMenuView.showMoveMenu(mDelegate.getPipGravity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onExitMoveMode() {
|
||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||
"%s: onExitMoveMode - %b, close when exiting move menu: %b", TAG, mInMoveMode,
|
||||
mCloseAfterExitMoveMenu);
|
||||
"%s: onExitMoveMode - %b, close when exiting move menu: %b",
|
||||
TAG, mInMoveMode, mCloseAfterExitMoveMenu);
|
||||
|
||||
if (mCloseAfterExitMoveMenu) {
|
||||
setInMoveMode(false);
|
||||
mCloseAfterExitMoveMenu = false;
|
||||
closeMenu();
|
||||
return true;
|
||||
}
|
||||
if (mInMoveMode) {
|
||||
setInMoveMode(false);
|
||||
mPipMenuView.showButtonsMenu(/* exitingMoveMode= */ true);
|
||||
if (mCloseAfterExitMoveMenu) {
|
||||
mCloseAfterExitMoveMenu = false;
|
||||
closeMenu();
|
||||
} else {
|
||||
mPipMenuView.showButtonsMenu(/* exitingMoveMode= */ true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -496,21 +501,6 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseButtonClick() {
|
||||
mDelegate.closePip();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFullscreenButtonClick() {
|
||||
mDelegate.movePipToFullscreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onToggleExpandedMode() {
|
||||
mDelegate.togglePipExpansion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseEduText() {
|
||||
mTvPipBoundsState.setPipMenuTemporaryDecorInsets(Insets.NONE);
|
||||
@@ -518,21 +508,15 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
|
||||
}
|
||||
|
||||
interface Delegate {
|
||||
void movePipToFullscreen();
|
||||
|
||||
void movePip(int keycode);
|
||||
|
||||
void onInMoveModeChanged();
|
||||
|
||||
int getPipGravity();
|
||||
|
||||
void togglePipExpansion();
|
||||
|
||||
void onMenuClosed();
|
||||
|
||||
void closeEduText();
|
||||
|
||||
void closePip();
|
||||
}
|
||||
|
||||
private void grantPipMenuFocus(boolean grantFocus) {
|
||||
|
||||
@@ -25,11 +25,6 @@ import static android.view.KeyEvent.KEYCODE_DPAD_RIGHT;
|
||||
import static android.view.KeyEvent.KEYCODE_DPAD_UP;
|
||||
import static android.view.KeyEvent.KEYCODE_ENTER;
|
||||
|
||||
import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_CLOSE;
|
||||
import static com.android.wm.shell.pip.tv.TvPipAction.ACTION_CUSTOM;
|
||||
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 android.content.Context;
|
||||
@@ -516,26 +511,8 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L
|
||||
public void onClick(View v) {
|
||||
TvPipAction action = mActionList.get(
|
||||
mActionButtonsRecyclerView.getChildLayoutPosition(v));
|
||||
switch (action.getActionType()) {
|
||||
case ACTION_FULLSCREEN:
|
||||
mListener.onFullscreenButtonClick();
|
||||
return;
|
||||
case ACTION_CLOSE:
|
||||
case ACTION_CUSTOM_CLOSE:
|
||||
mListener.onCloseButtonClick();
|
||||
return;
|
||||
case ACTION_MOVE:
|
||||
mListener.onEnterMoveMode();
|
||||
return;
|
||||
case ACTION_EXPAND_COLLAPSE:
|
||||
mListener.onToggleExpandedMode();
|
||||
return;
|
||||
case ACTION_CUSTOM:
|
||||
action.executePendingIntent();
|
||||
return;
|
||||
default:
|
||||
ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||
"%s: No action available", TAG);
|
||||
if (action != null) {
|
||||
action.executeAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -545,8 +522,6 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L
|
||||
|
||||
void onBackPress();
|
||||
|
||||
void onEnterMoveMode();
|
||||
|
||||
/**
|
||||
* Called when a button for exiting move mode was pressed.
|
||||
*
|
||||
@@ -559,11 +534,5 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L
|
||||
* @return whether pip movement was handled.
|
||||
*/
|
||||
boolean onPipMovement(int keycode);
|
||||
|
||||
void onCloseButtonClick();
|
||||
|
||||
void onFullscreenButtonClick();
|
||||
|
||||
void onToggleExpandedMode();
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,9 @@ import android.annotation.NonNull;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
@@ -32,7 +30,6 @@ import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.media.session.MediaSession;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
|
||||
@@ -52,32 +49,17 @@ import java.util.List;
|
||||
* configuration changes and user initiated expanded PiP toggling.
|
||||
*/
|
||||
public class TvPipNotificationController implements TvPipActionsProvider.Listener {
|
||||
private static final String TAG = "TvPipNotification";
|
||||
private static final String TAG = TvPipNotificationController.class.getSimpleName();
|
||||
|
||||
// Referenced in com.android.systemui.util.NotificationChannels.
|
||||
public static final String NOTIFICATION_CHANNEL = "TVPIP";
|
||||
private static final String NOTIFICATION_TAG = "TvPip";
|
||||
private static final String SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF";
|
||||
|
||||
private 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 PackageManager mPackageManager;
|
||||
private final NotificationManager mNotificationManager;
|
||||
private final Notification.Builder mNotificationBuilder;
|
||||
private final ActionBroadcastReceiver mActionBroadcastReceiver;
|
||||
private final Handler mMainHandler;
|
||||
private Delegate mDelegate;
|
||||
private final TvPipActionsProvider mTvPipActionsProvider;
|
||||
private TvPipActionsProvider mTvPipActionsProvider;
|
||||
|
||||
private MediaSession.Token mMediaSessionToken;
|
||||
|
||||
@@ -89,22 +71,17 @@ public class TvPipNotificationController implements TvPipActionsProvider.Listene
|
||||
private String mPipTitle;
|
||||
private String mPipSubtitle;
|
||||
|
||||
// Saving the actions so they don't have to be regenerated when e.g. the PiP title changes.
|
||||
// Saving the actions, so they don't have to be regenerated when e.g. the PiP title changes.
|
||||
@NonNull
|
||||
private Notification.Action[] mPipActions;
|
||||
|
||||
private Bitmap mActivityIcon;
|
||||
|
||||
public TvPipNotificationController(Context context, PipMediaController pipMediaController,
|
||||
PipParamsChangedForwarder pipParamsChangedForwarder,
|
||||
TvPipActionsProvider tvPipActionsProvider, Handler mainHandler) {
|
||||
PipParamsChangedForwarder pipParamsChangedForwarder) {
|
||||
mContext = context;
|
||||
mPackageManager = context.getPackageManager();
|
||||
mNotificationManager = context.getSystemService(NotificationManager.class);
|
||||
mMainHandler = mainHandler;
|
||||
|
||||
mTvPipActionsProvider = tvPipActionsProvider;
|
||||
mTvPipActionsProvider.addListener(this);
|
||||
|
||||
mPipActions = new Notification.Action[0];
|
||||
|
||||
@@ -116,11 +93,10 @@ public class TvPipNotificationController implements TvPipActionsProvider.Listene
|
||||
.setOnlyAlertOnce(true)
|
||||
.setSmallIcon(R.drawable.pip_icon)
|
||||
.setAllowSystemGeneratedContextualActions(false)
|
||||
.setContentIntent(createPendingIntent(context, ACTION_TO_FULLSCREEN));
|
||||
.setContentIntent(
|
||||
createPendingIntent(context, TvPipController.ACTION_TO_FULLSCREEN));
|
||||
// TvExtender and DeleteIntent set later since they might change.
|
||||
|
||||
mActionBroadcastReceiver = new ActionBroadcastReceiver();
|
||||
|
||||
pipMediaController.addTokenListener(this::onMediaSessionTokenChanged);
|
||||
|
||||
pipParamsChangedForwarder.addListener(
|
||||
@@ -141,35 +117,30 @@ public class TvPipNotificationController implements TvPipActionsProvider.Listene
|
||||
onConfigurationChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call before showing any notification.
|
||||
*/
|
||||
void setTvPipActionsProvider(@NonNull TvPipActionsProvider tvPipActionsProvider) {
|
||||
mTvPipActionsProvider = tvPipActionsProvider;
|
||||
mTvPipActionsProvider.addListener(this);
|
||||
}
|
||||
|
||||
void onConfigurationChanged() {
|
||||
mDefaultTitle = mContext.getResources().getString(R.string.pip_notification_unknown_title);
|
||||
updateNotificationContent();
|
||||
}
|
||||
|
||||
void setDelegate(Delegate delegate) {
|
||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: setDelegate(), delegate=%s",
|
||||
TAG, 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) {
|
||||
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: show %s", TAG, packageName);
|
||||
if (mDelegate == null) {
|
||||
throw new IllegalStateException("Delegate is not set.");
|
||||
if (mTvPipActionsProvider == null) {
|
||||
ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
|
||||
"%s: Missing TvPipActionsProvider", TAG);
|
||||
return;
|
||||
}
|
||||
|
||||
mIsNotificationShown = true;
|
||||
mPackageName = packageName;
|
||||
mActivityIcon = getActivityIcon();
|
||||
mActionBroadcastReceiver.register();
|
||||
|
||||
updateNotificationContent();
|
||||
}
|
||||
@@ -179,8 +150,6 @@ public class TvPipNotificationController implements TvPipActionsProvider.Listene
|
||||
|
||||
mIsNotificationShown = false;
|
||||
mPackageName = null;
|
||||
mActionBroadcastReceiver.unregister();
|
||||
|
||||
mNotificationManager.cancel(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP);
|
||||
}
|
||||
|
||||
@@ -213,7 +182,8 @@ public class TvPipNotificationController implements TvPipActionsProvider.Listene
|
||||
mNotificationBuilder.setDeleteIntent(closeIntent);
|
||||
// TvExtender not recognized if not set last.
|
||||
mNotificationBuilder.extend(new Notification.TvExtender()
|
||||
.setContentIntent(createPendingIntent(mContext, ACTION_SHOW_PIP_MENU))
|
||||
.setContentIntent(
|
||||
createPendingIntent(mContext, TvPipController.ACTION_SHOW_PIP_MENU))
|
||||
.setDeleteIntent(closeIntent));
|
||||
|
||||
mNotificationManager.notify(NOTIFICATION_TAG, SystemMessage.NOTE_TV_PIP,
|
||||
@@ -283,62 +253,4 @@ public class TvPipNotificationController implements TvPipActionsProvider.Listene
|
||||
updateNotificationContent();
|
||||
}
|
||||
|
||||
private class ActionBroadcastReceiver extends BroadcastReceiver {
|
||||
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)) {
|
||||
mDelegate.showPictureInPictureMenu();
|
||||
} else if (ACTION_CLOSE_PIP.equals(action)) {
|
||||
mDelegate.closePip();
|
||||
} else if (ACTION_MOVE_PIP.equals(action)) {
|
||||
mDelegate.enterPipMovementMenu();
|
||||
} else if (ACTION_TOGGLE_EXPANDED_PIP.equals(action)) {
|
||||
mDelegate.togglePipExpansion();
|
||||
} else if (ACTION_TO_FULLSCREEN.equals(action)) {
|
||||
mDelegate.movePipToFullscreen();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface Delegate {
|
||||
void showPictureInPictureMenu();
|
||||
|
||||
void closePip();
|
||||
|
||||
void enterPipMovementMenu();
|
||||
|
||||
void togglePipExpansion();
|
||||
|
||||
void movePipToFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,9 @@ public class TvPipSystemAction extends TvPipAction {
|
||||
private final PendingIntent mBroadcastIntent;
|
||||
|
||||
TvPipSystemAction(@ActionType int actionType, @StringRes int title, @DrawableRes int icon,
|
||||
String broadcastAction, @NonNull Context context) {
|
||||
super(actionType);
|
||||
String broadcastAction, @NonNull Context context,
|
||||
SystemActionsHandler systemActionsHandler) {
|
||||
super(actionType, systemActionsHandler);
|
||||
update(title, icon);
|
||||
mBroadcastIntent = TvPipNotificationController.createPendingIntent(context,
|
||||
broadcastAction);
|
||||
@@ -63,7 +64,7 @@ public class TvPipSystemAction extends TvPipAction {
|
||||
}
|
||||
|
||||
PendingIntent getPendingIntent() {
|
||||
return null;
|
||||
return mBroadcastIntent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -63,6 +63,8 @@ public class TvPipActionProviderTest extends ShellTestCase {
|
||||
@Mock
|
||||
private TvPipActionsProvider.Listener mMockListener;
|
||||
@Mock
|
||||
private TvPipAction.SystemActionsHandler mMockSystemActionsHandler;
|
||||
@Mock
|
||||
private Icon mMockIcon;
|
||||
@Mock
|
||||
private PendingIntent mMockPendingIntent;
|
||||
@@ -94,7 +96,8 @@ public class TvPipActionProviderTest extends ShellTestCase {
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mActionsProvider = new TvPipActionsProvider(mContext, mMockPipMediaController);
|
||||
mActionsProvider = new TvPipActionsProvider(mContext, mMockPipMediaController,
|
||||
mMockSystemActionsHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user