Merge "TV-PiP: Migrate Menu to SystemWindows."
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.pip;
|
||||
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.app.RemoteAction;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.WindowManager;
|
||||
|
||||
/**
|
||||
* Interface to allow {@link com.android.wm.shell.pip.PipTaskOrganizer} to call into
|
||||
* PiP menu when certain events happen (task appear/vanish, PiP move, etc.)
|
||||
*/
|
||||
public interface PipMenuController {
|
||||
|
||||
String MENU_WINDOW_TITLE = "PipMenuView";
|
||||
|
||||
/**
|
||||
* Called when
|
||||
* {@link PipTaskOrganizer#onTaskAppeared(RunningTaskInfo, SurfaceControl)}
|
||||
* is called.
|
||||
*/
|
||||
void attach(SurfaceControl leash);
|
||||
|
||||
/**
|
||||
* Called when
|
||||
* {@link PipTaskOrganizer#onTaskVanished(RunningTaskInfo)} is called.
|
||||
*/
|
||||
void detach();
|
||||
|
||||
/**
|
||||
* Check if menu is visible or not.
|
||||
*/
|
||||
boolean isMenuVisible();
|
||||
|
||||
/**
|
||||
* Show the PIP menu.
|
||||
*/
|
||||
void showMenu();
|
||||
|
||||
/**
|
||||
* Given a set of actions, update the menu.
|
||||
*/
|
||||
void setAppActions(ParceledListSlice<RemoteAction> appActions);
|
||||
|
||||
/**
|
||||
* Resize the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a
|
||||
* need to synchronize the movements on the same frame as PiP.
|
||||
*/
|
||||
default void resizePipMenu(@Nullable SurfaceControl pipLeash,
|
||||
@Nullable SurfaceControl.Transaction t,
|
||||
Rect destinationBounds) {}
|
||||
|
||||
/**
|
||||
* Move the PiP menu with the given bounds. The PiP SurfaceControl is given if there is a
|
||||
* need to synchronize the movements on the same frame as PiP.
|
||||
*/
|
||||
default void movePipMenu(@Nullable SurfaceControl pipLeash,
|
||||
@Nullable SurfaceControl.Transaction t,
|
||||
Rect destinationBounds) {}
|
||||
|
||||
/**
|
||||
* Update the PiP menu with the given bounds for re-layout purposes.
|
||||
*/
|
||||
default void updateMenuBounds(Rect destinationBounds) {}
|
||||
|
||||
/**
|
||||
* Returns a default LayoutParams for the PIP Menu.
|
||||
* @param width the PIP stack width.
|
||||
* @param height the PIP stack height.
|
||||
*/
|
||||
default WindowManager.LayoutParams getPipMenuLayoutParams(String title, int width, int height) {
|
||||
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
|
||||
TYPE_APPLICATION_OVERLAY,
|
||||
FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY | FLAG_NOT_TOUCHABLE,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
lp.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||
lp.setTitle(title);
|
||||
return lp;
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,6 @@ import com.android.internal.os.SomeArgs;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.pip.phone.PipMenuActivityController;
|
||||
import com.android.wm.shell.pip.phone.PipMotionHelper;
|
||||
import com.android.wm.shell.pip.phone.PipUpdateThread;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
@@ -135,8 +134,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
private final Handler mUpdateHandler;
|
||||
private final PipBoundsState mPipBoundsState;
|
||||
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
// TODO(b/172286265): Remove dependency on .pip.PHONE.PipMenuActivityController
|
||||
private final PipMenuActivityController mMenuActivityController;
|
||||
private final @NonNull PipMenuController mPipMenuController;
|
||||
private final PipAnimationController mPipAnimationController;
|
||||
private final PipUiEventLogger mPipUiEventLoggerLogger;
|
||||
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
|
||||
@@ -264,7 +262,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
|
||||
public PipTaskOrganizer(Context context, @NonNull PipBoundsState pipBoundsState,
|
||||
@NonNull PipBoundsAlgorithm boundsHandler,
|
||||
PipMenuActivityController menuActivityController,
|
||||
@NonNull PipMenuController pipMenuController,
|
||||
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
|
||||
Optional<SplitScreen> splitScreenOptional,
|
||||
@NonNull DisplayController displayController,
|
||||
@@ -274,7 +272,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mPipBoundsAlgorithm = boundsHandler;
|
||||
mMenuActivityController = menuActivityController;
|
||||
mPipMenuController = pipMenuController;
|
||||
mEnterExitAnimationDuration = context.getResources()
|
||||
.getInteger(R.integer.config_pipResizeAnimationDuration);
|
||||
mSurfaceTransactionHelper = surfaceTransactionHelper;
|
||||
@@ -501,9 +499,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
mOnDisplayIdChangeCallback.accept(info.displayId);
|
||||
}
|
||||
|
||||
if (mMenuActivityController != null) {
|
||||
mMenuActivityController.onTaskAppeared();
|
||||
}
|
||||
mPipMenuController.attach(leash);
|
||||
|
||||
|
||||
if (mShouldIgnoreEnteringPipTransition) {
|
||||
final Rect destinationBounds = mPipBoundsState.getBounds();
|
||||
@@ -674,9 +671,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
mPictureInPictureParams = null;
|
||||
mState = State.UNDEFINED;
|
||||
mPipUiEventLoggerLogger.setTaskInfo(null);
|
||||
if (mMenuActivityController != null) {
|
||||
mMenuActivityController.onTaskVanished();
|
||||
}
|
||||
mPipMenuController.detach();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -956,9 +951,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
mSurfaceTransactionHelper
|
||||
.crop(tx, mLeash, destinationBounds)
|
||||
.round(tx, mLeash, mState.isInPip());
|
||||
if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
|
||||
if (mPipMenuController.isMenuVisible()) {
|
||||
runOnMainHandler(() ->
|
||||
mMenuActivityController.resizePipMenu(mLeash, tx, destinationBounds));
|
||||
mPipMenuController.resizePipMenu(mLeash, tx, destinationBounds));
|
||||
} else {
|
||||
tx.apply();
|
||||
}
|
||||
@@ -982,9 +977,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
|
||||
final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
|
||||
mSurfaceTransactionHelper.scale(tx, mLeash, startBounds, destinationBounds);
|
||||
if (mMenuActivityController != null && mMenuActivityController.isMenuVisible()) {
|
||||
if (mPipMenuController.isMenuVisible()) {
|
||||
runOnMainHandler(() ->
|
||||
mMenuActivityController.movePipMenu(mLeash, tx, destinationBounds));
|
||||
mPipMenuController.movePipMenu(mLeash, tx, destinationBounds));
|
||||
} else {
|
||||
tx.apply();
|
||||
}
|
||||
@@ -1001,8 +996,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
if (direction == TRANSITION_DIRECTION_REMOVE_STACK) {
|
||||
removePipImmediately();
|
||||
return;
|
||||
} else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA
|
||||
&& mMenuActivityController != null) {
|
||||
} else if (isInPipDirection(direction) && type == ANIM_TYPE_ALPHA) {
|
||||
// TODO: Synchronize this correctly in #applyEnterPipSyncTransaction
|
||||
finishResizeForMenu(destinationBounds);
|
||||
return;
|
||||
@@ -1015,13 +1009,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
|
||||
}
|
||||
|
||||
private void finishResizeForMenu(Rect destinationBounds) {
|
||||
if (mMenuActivityController == null) {
|
||||
if (DEBUG) Log.d(TAG, "mMenuActivityController is null");
|
||||
return;
|
||||
}
|
||||
runOnMainHandler(() -> {
|
||||
mMenuActivityController.movePipMenu(null, null, destinationBounds);
|
||||
mMenuActivityController.updateMenuBounds(destinationBounds);
|
||||
mPipMenuController.movePipMenu(null, null, destinationBounds);
|
||||
mPipMenuController.updateMenuBounds(destinationBounds);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -18,12 +18,6 @@ package com.android.wm.shell.pip.phone;
|
||||
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
|
||||
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
@@ -33,7 +27,6 @@ import android.app.RemoteAction;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Debug;
|
||||
@@ -44,27 +37,26 @@ import android.view.MotionEvent;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SyncRtSurfaceTransactionApplier;
|
||||
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManagerGlobal;
|
||||
|
||||
import com.android.wm.shell.common.SystemWindows;
|
||||
import com.android.wm.shell.pip.PipMediaController;
|
||||
import com.android.wm.shell.pip.PipMediaController.ActionListener;
|
||||
import com.android.wm.shell.pip.PipMenuController;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manages the PiP menu activity which can show menu options or a scrim.
|
||||
* Manages the PiP menu view which can show menu options or a scrim.
|
||||
*
|
||||
* The current media session provides actions whenever there are no valid actions provided by the
|
||||
* current PiP activity. Otherwise, those actions always take precedence.
|
||||
*/
|
||||
public class PipMenuActivityController {
|
||||
public class PhonePipMenuController implements PipMenuController {
|
||||
|
||||
private static final String TAG = "PipMenuActController";
|
||||
private static final String MENU_WINDOW_TITLE = "PipMenuView";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
public static final int MENU_STATE_NONE = 0;
|
||||
@@ -124,7 +116,7 @@ public class PipMenuActivityController {
|
||||
}
|
||||
};
|
||||
|
||||
public PipMenuActivityController(Context context,
|
||||
public PhonePipMenuController(Context context,
|
||||
PipMediaController mediaController, SystemWindows systemWindows) {
|
||||
mContext = context;
|
||||
mMediaController = mediaController;
|
||||
@@ -138,20 +130,22 @@ public class PipMenuActivityController {
|
||||
/**
|
||||
* Attach the menu when the PiP task first appears.
|
||||
*/
|
||||
public void onTaskAppeared() {
|
||||
@Override
|
||||
public void attach(SurfaceControl leash) {
|
||||
attachPipMenuView();
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach the menu when the PiP task is gone.
|
||||
*/
|
||||
public void onTaskVanished() {
|
||||
@Override
|
||||
public void detach() {
|
||||
hideMenu();
|
||||
detachPipMenuView();
|
||||
}
|
||||
|
||||
|
||||
public void onPinnedStackAnimationEnded() {
|
||||
void onPinnedStackAnimationEnded() {
|
||||
if (isMenuVisible()) {
|
||||
mPipMenuView.onPipAnimationEnded();
|
||||
}
|
||||
@@ -163,7 +157,9 @@ public class PipMenuActivityController {
|
||||
detachPipMenuView();
|
||||
}
|
||||
mPipMenuView = new PipMenuView(mContext, this);
|
||||
mSystemWindows.addView(mPipMenuView, getPipMenuLayoutParams(0, 0), 0, SHELL_ROOT_LAYER_PIP);
|
||||
mSystemWindows.addView(mPipMenuView,
|
||||
getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
|
||||
0, SHELL_ROOT_LAYER_PIP);
|
||||
}
|
||||
|
||||
private void detachPipMenuView() {
|
||||
@@ -181,9 +177,11 @@ public class PipMenuActivityController {
|
||||
* Updates the layout parameters of the menu.
|
||||
* @param destinationBounds New Menu bounds.
|
||||
*/
|
||||
@Override
|
||||
public void updateMenuBounds(Rect destinationBounds) {
|
||||
mSystemWindows.updateViewLayout(mPipMenuView,
|
||||
getPipMenuLayoutParams(destinationBounds.width(), destinationBounds.height()));
|
||||
getPipMenuLayoutParams(MENU_WINDOW_TITLE, destinationBounds.width(),
|
||||
destinationBounds.height()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,6 +203,16 @@ public class PipMenuActivityController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When other components requests the menu controller directly to show the menu, we must
|
||||
* first fire off the request to the other listeners who will then propagate the call
|
||||
* back to the controller with the right parameters.
|
||||
*/
|
||||
@Override
|
||||
public void showMenu() {
|
||||
mListeners.forEach(Listener::onPipShowMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #showMenu(int, Rect, boolean, boolean, boolean)} but only show the menu
|
||||
* upon PiP window transition is finished.
|
||||
@@ -250,6 +258,7 @@ public class PipMenuActivityController {
|
||||
/**
|
||||
* Move the PiP menu, which does a translation and possibly a scale transformation.
|
||||
*/
|
||||
@Override
|
||||
public void movePipMenu(@Nullable SurfaceControl pipLeash,
|
||||
@Nullable SurfaceControl.Transaction t,
|
||||
Rect destinationBounds) {
|
||||
@@ -290,6 +299,7 @@ public class PipMenuActivityController {
|
||||
/**
|
||||
* Does an immediate window crop of the PiP menu.
|
||||
*/
|
||||
@Override
|
||||
public void resizePipMenu(@Nullable SurfaceControl pipLeash,
|
||||
@Nullable SurfaceControl.Transaction t,
|
||||
Rect destinationBounds) {
|
||||
@@ -391,8 +401,9 @@ public class PipMenuActivityController {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the menu actions to the actions provided by the current PiP activity.
|
||||
* Sets the menu actions to the actions provided by the current PiP menu.
|
||||
*/
|
||||
@Override
|
||||
public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
|
||||
mAppActions = appActions;
|
||||
updateMenuActions();
|
||||
@@ -406,10 +417,6 @@ public class PipMenuActivityController {
|
||||
mListeners.forEach(Listener::onPipDismiss);
|
||||
}
|
||||
|
||||
void onPipShowMenu() {
|
||||
mListeners.forEach(Listener::onPipShowMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the best set of actions to show in the PiP menu.
|
||||
*/
|
||||
@@ -420,21 +427,6 @@ public class PipMenuActivityController {
|
||||
return mMediaActions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a default LayoutParams for the PIP Menu.
|
||||
* @param width the PIP stack width.
|
||||
* @param height the PIP stack height.
|
||||
*/
|
||||
public static WindowManager.LayoutParams getPipMenuLayoutParams(int width, int height) {
|
||||
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(width, height,
|
||||
TYPE_APPLICATION_OVERLAY,
|
||||
FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY | FLAG_NOT_TOUCHABLE,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
lp.privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||
lp.setTitle(MENU_WINDOW_TITLE);
|
||||
return lp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the PiP menu with the best set of actions provided.
|
||||
*/
|
||||
@@ -521,7 +513,7 @@ public class PipMenuActivityController {
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
void dump(PrintWriter pw, String prefix) {
|
||||
final String innerPrefix = prefix + " ";
|
||||
pw.println(prefix + TAG);
|
||||
pw.println(innerPrefix + "mMenuState=" + mMenuState);
|
||||
@@ -92,7 +92,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
private boolean mIsInFixedRotation;
|
||||
private Consumer<Boolean> mPinnedStackAnimationRecentsCallback;
|
||||
|
||||
protected PipMenuActivityController mMenuController;
|
||||
protected PhonePipMenuController mMenuController;
|
||||
protected PipTaskOrganizer mPipTaskOrganizer;
|
||||
protected PinnedStackListenerForwarder.PinnedStackListener mPinnedStackListener =
|
||||
new PipControllerPinnedStackListener();
|
||||
@@ -229,7 +229,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
@NonNull PipBoundsState pipBoundsState,
|
||||
PipMediaController pipMediaController,
|
||||
PipMenuActivityController pipMenuActivityController,
|
||||
PhonePipMenuController phonePipMenuController,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTouchHandler pipTouchHandler,
|
||||
WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
@@ -250,7 +250,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
mMainExecutor = mainExecutor;
|
||||
mMediaController = pipMediaController;
|
||||
mMenuController = pipMenuActivityController;
|
||||
mMenuController = phonePipMenuController;
|
||||
mTouchHandler = pipTouchHandler;
|
||||
mAppOpsListener = pipAppOpsListener;
|
||||
mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(),
|
||||
@@ -632,7 +632,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
public static PipController create(Context context, DisplayController displayController,
|
||||
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
|
||||
PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
|
||||
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
|
||||
if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
|
||||
@@ -641,7 +641,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
}
|
||||
|
||||
return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm,
|
||||
pipBoundsState, pipMediaController, pipMenuActivityController, pipTaskOrganizer,
|
||||
pipBoundsState, pipMediaController, phonePipMenuController, pipTaskOrganizer,
|
||||
pipTouchHandler, windowManagerShellWrapper, taskStackListener, mainExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTR
|
||||
import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
|
||||
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
|
||||
|
||||
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
|
||||
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
|
||||
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
|
||||
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
|
||||
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
|
||||
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -105,7 +105,7 @@ public class PipMenuView extends FrameLayout {
|
||||
private int mBetweenActionPaddingLand;
|
||||
|
||||
private AnimatorSet mMenuContainerAnimator;
|
||||
private PipMenuActivityController mController;
|
||||
private PhonePipMenuController mController;
|
||||
|
||||
private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
|
||||
new ValueAnimator.AnimatorUpdateListener() {
|
||||
@@ -127,7 +127,7 @@ public class PipMenuView extends FrameLayout {
|
||||
protected View mTopEndContainer;
|
||||
protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
|
||||
|
||||
public PipMenuView(Context context, PipMenuActivityController controller) {
|
||||
public PipMenuView(Context context, PhonePipMenuController controller) {
|
||||
super(context, null, 0);
|
||||
mContext = context;
|
||||
mController = controller;
|
||||
@@ -182,7 +182,7 @@ public class PipMenuView extends FrameLayout {
|
||||
@Override
|
||||
public boolean performAccessibilityAction(View host, int action, Bundle args) {
|
||||
if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
|
||||
mController.onPipShowMenu();
|
||||
mController.showMenu();
|
||||
}
|
||||
return super.performAccessibilityAction(host, action, args);
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
private final PipTaskOrganizer mPipTaskOrganizer;
|
||||
private @NonNull PipBoundsState mPipBoundsState;
|
||||
|
||||
private PipMenuActivityController mMenuController;
|
||||
private PhonePipMenuController mMenuController;
|
||||
private PipSnapAlgorithm mSnapAlgorithm;
|
||||
|
||||
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
|
||||
@@ -162,7 +162,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
|
||||
};
|
||||
|
||||
public PipMotionHelper(Context context, @NonNull PipBoundsState pipBoundsState,
|
||||
PipTaskOrganizer pipTaskOrganizer, PipMenuActivityController menuController,
|
||||
PipTaskOrganizer pipTaskOrganizer, PhonePipMenuController menuController,
|
||||
PipSnapAlgorithm snapAlgorithm, FloatingContentCoordinator floatingContentCoordinator) {
|
||||
mContext = context;
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
|
||||
@@ -103,7 +103,7 @@ public class PipResizeGestureHandler {
|
||||
private InputMonitor mInputMonitor;
|
||||
private InputEventReceiver mInputEventReceiver;
|
||||
private PipTaskOrganizer mPipTaskOrganizer;
|
||||
private PipMenuActivityController mPipMenuActivityController;
|
||||
private PhonePipMenuController mPhonePipMenuController;
|
||||
private PipUiEventLogger mPipUiEventLogger;
|
||||
|
||||
private int mCtrlType;
|
||||
@@ -112,7 +112,7 @@ public class PipResizeGestureHandler {
|
||||
PipBoundsState pipBoundsState, PipMotionHelper motionHelper,
|
||||
PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
|
||||
Runnable updateMovementBoundsRunnable, PipUiEventLogger pipUiEventLogger,
|
||||
PipMenuActivityController menuActivityController) {
|
||||
PhonePipMenuController menuActivityController) {
|
||||
mContext = context;
|
||||
mDisplayId = context.getDisplayId();
|
||||
mMainExecutor = context.getMainExecutor();
|
||||
@@ -122,7 +122,7 @@ public class PipResizeGestureHandler {
|
||||
mPipTaskOrganizer = pipTaskOrganizer;
|
||||
mMovementBoundsSupplier = movementBoundsSupplier;
|
||||
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
|
||||
mPipMenuActivityController = menuActivityController;
|
||||
mPhonePipMenuController = menuActivityController;
|
||||
mPipUiEventLogger = pipUiEventLogger;
|
||||
|
||||
context.getDisplay().getRealSize(mMaxSize);
|
||||
@@ -422,8 +422,8 @@ public class PipResizeGestureHandler {
|
||||
mLastDownBounds.set(mPipBoundsState.getBounds());
|
||||
}
|
||||
if (!currentPipBounds.contains((int) ev.getX(), (int) ev.getY())
|
||||
&& mPipMenuActivityController.isMenuVisible()) {
|
||||
mPipMenuActivityController.hideMenu();
|
||||
&& mPhonePipMenuController.isMenuVisible()) {
|
||||
mPhonePipMenuController.hideMenu();
|
||||
}
|
||||
|
||||
} else if (mAllowGesture) {
|
||||
@@ -442,9 +442,9 @@ public class PipResizeGestureHandler {
|
||||
mInputMonitor.pilferPointers();
|
||||
}
|
||||
if (mThresholdCrossed) {
|
||||
if (mPipMenuActivityController.isMenuVisible()) {
|
||||
mPipMenuActivityController.hideMenuWithoutResize();
|
||||
mPipMenuActivityController.hideMenu();
|
||||
if (mPhonePipMenuController.isMenuVisible()) {
|
||||
mPhonePipMenuController.hideMenuWithoutResize();
|
||||
mPhonePipMenuController.hideMenu();
|
||||
}
|
||||
final Rect currentPipBounds = mPipBoundsState.getBounds();
|
||||
mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(x, y,
|
||||
|
||||
@@ -18,9 +18,9 @@ package com.android.wm.shell.pip.phone;
|
||||
|
||||
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_STASHING;
|
||||
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
|
||||
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_CLOSE;
|
||||
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_FULL;
|
||||
import static com.android.wm.shell.pip.phone.PipMenuActivityController.MENU_STATE_NONE;
|
||||
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
|
||||
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
|
||||
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SuppressLint;
|
||||
@@ -78,7 +78,7 @@ public class PipTouchHandler {
|
||||
private IPinnedStackController mPinnedStackController;
|
||||
private WeakReference<Consumer<Rect>> mPipExclusionBoundsChangeListener;
|
||||
|
||||
private final PipMenuActivityController mMenuController;
|
||||
private final PhonePipMenuController mMenuController;
|
||||
private final AccessibilityManager mAccessibilityManager;
|
||||
private boolean mShowPipMenuOnAnimationEnd = false;
|
||||
|
||||
@@ -125,7 +125,7 @@ public class PipTouchHandler {
|
||||
/**
|
||||
* A listener for the PIP menu activity.
|
||||
*/
|
||||
private class PipMenuListener implements PipMenuActivityController.Listener {
|
||||
private class PipMenuListener implements PhonePipMenuController.Listener {
|
||||
@Override
|
||||
public void onPipMenuStateChanged(int menuState, boolean resize, Runnable callback) {
|
||||
setMenuState(menuState, resize, callback);
|
||||
@@ -152,7 +152,7 @@ public class PipTouchHandler {
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
public PipTouchHandler(Context context,
|
||||
PipMenuActivityController menuController,
|
||||
PhonePipMenuController menuController,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
@NonNull PipBoundsState pipBoundsState,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
|
||||
@@ -111,6 +111,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
private final PipBoundsAlgorithm mPipBoundsAlgorithm;
|
||||
private final PipTaskOrganizer mPipTaskOrganizer;
|
||||
private final PipMediaController mPipMediaController;
|
||||
private final TvPipMenuController mTvPipMenuController;
|
||||
|
||||
private IActivityTaskManager mActivityTaskManager;
|
||||
private int mState = STATE_NO_PIP;
|
||||
@@ -210,9 +211,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
public void onActionsChanged(ParceledListSlice<RemoteAction> actions) {
|
||||
mCustomActions = actions;
|
||||
mHandler.post(() -> {
|
||||
for (int i = mListeners.size() - 1; i >= 0; --i) {
|
||||
mListeners.get(i).onPipMenuActionsChanged(mCustomActions);
|
||||
}
|
||||
mTvPipMenuController.setAppActions(mCustomActions);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -221,6 +220,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
PipBoundsState pipBoundsState,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
TvPipMenuController tvPipMenuController,
|
||||
PipMediaController pipMediaController,
|
||||
PipNotification pipNotification,
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
@@ -230,6 +230,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
mPipNotification = pipNotification;
|
||||
mPipBoundsAlgorithm = pipBoundsAlgorithm;
|
||||
mPipMediaController = pipMediaController;
|
||||
mTvPipMenuController = tvPipMenuController;
|
||||
mTvPipMenuController.attachPipController(this);
|
||||
// Ensure that we have the display info in case we get calls to update the bounds
|
||||
// before the listener calls back
|
||||
final DisplayInfo displayInfo = new DisplayInfo();
|
||||
@@ -282,9 +284,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
PipController.this.onActivityRestartAttempt(task, clearedTask);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
|
||||
PipMenuActivity.setPipController(this);
|
||||
}
|
||||
|
||||
private void loadConfigurationsAndApply(Configuration newConfig) {
|
||||
@@ -445,7 +444,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
Log.d(TAG,
|
||||
"suspendPipResizing() reason=" + reason + " callers=" + Debug.getCallers(2));
|
||||
}
|
||||
|
||||
mSuspendPipResizingReason |= reason;
|
||||
}
|
||||
|
||||
@@ -472,6 +470,7 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
* @param state In Pip state also used to determine the new size for the Pip.
|
||||
*/
|
||||
public void resizePinnedStack(int state) {
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "resizePinnedStack() state=" + stateToName(state) + ", current state="
|
||||
+ getStateDescription(), new Exception());
|
||||
@@ -538,10 +537,8 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
for (int i = mListeners.size() - 1; i >= 0; --i) {
|
||||
mListeners.get(i).onShowPipMenu();
|
||||
}
|
||||
Intent intent = new Intent(mContext, PipMenuActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.putExtra(PipMenuActivity.EXTRA_CUSTOM_ACTIONS, mCustomActions);
|
||||
mContext.startActivity(intent);
|
||||
|
||||
mTvPipMenuController.showMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -644,8 +641,6 @@ public class PipController implements Pip, PipTaskOrganizer.PipTransitionCallbac
|
||||
void onPipActivityClosed();
|
||||
/** Invoked when the PIP menu gets shown. */
|
||||
void onShowPipMenu();
|
||||
/** Invoked when the PIP menu actions change. */
|
||||
void onPipMenuActionsChanged(ParceledListSlice<RemoteAction> actions);
|
||||
/** Invoked when the PIPed activity is about to return back to the fullscreen. */
|
||||
void onMoveToFullscreen();
|
||||
/** Invoked when we are above to start resizing the Pip. */
|
||||
|
||||
@@ -18,63 +18,98 @@ package com.android.wm.shell.pip.tv;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorInflater;
|
||||
import android.app.Activity;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.RemoteAction;
|
||||
import android.content.Intent;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.ViewRootImpl;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.wm.shell.R;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Activity to show the PIP menu to control PIP.
|
||||
* TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
|
||||
* The Menu View that shows controls of the PiP. Always fullscreen.
|
||||
*/
|
||||
public class PipMenuActivity extends Activity implements PipController.Listener {
|
||||
private static final String TAG = "PipMenuActivity";
|
||||
public class PipMenuView extends FrameLayout implements PipController.Listener {
|
||||
private static final String TAG = "PipMenuView";
|
||||
private static final boolean DEBUG = PipController.DEBUG;
|
||||
|
||||
static final String EXTRA_CUSTOM_ACTIONS = "custom_actions";
|
||||
|
||||
private static PipController sPipController;
|
||||
|
||||
private Animator mFadeInAnimation;
|
||||
private Animator mFadeOutAnimation;
|
||||
private final PipController mPipController;
|
||||
private final Animator mFadeInAnimation;
|
||||
private final Animator mFadeOutAnimation;
|
||||
private final PipControlsViewController mPipControlsViewController;
|
||||
private boolean mRestorePipSizeWhenClose;
|
||||
private PipControlsViewController mPipControlsViewController;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle bundle) {
|
||||
if (DEBUG) Log.d(TAG, "onCreate()");
|
||||
public PipMenuView(Context context, PipController pipController) {
|
||||
super(context, null, 0);
|
||||
mPipController = pipController;
|
||||
|
||||
inflate(context, R.layout.tv_pip_menu, this);
|
||||
|
||||
super.onCreate(bundle);
|
||||
if (sPipController == null) {
|
||||
finish();
|
||||
}
|
||||
setContentView(R.layout.tv_pip_menu);
|
||||
mPipControlsViewController = new PipControlsViewController(
|
||||
findViewById(R.id.pip_controls), sPipController);
|
||||
sPipController.addListener(this);
|
||||
findViewById(R.id.pip_controls), mPipController);
|
||||
mRestorePipSizeWhenClose = true;
|
||||
mFadeInAnimation = AnimatorInflater.loadAnimator(
|
||||
this, R.anim.tv_pip_menu_fade_in_animation);
|
||||
mContext, R.anim.tv_pip_menu_fade_in_animation);
|
||||
mFadeInAnimation.setTarget(mPipControlsViewController.getView());
|
||||
mFadeOutAnimation = AnimatorInflater.loadAnimator(
|
||||
this, R.anim.tv_pip_menu_fade_out_animation);
|
||||
mContext, R.anim.tv_pip_menu_fade_out_animation);
|
||||
mFadeOutAnimation.setTarget(mPipControlsViewController.getView());
|
||||
|
||||
onPipMenuActionsChanged(getIntent().getParcelableExtra(EXTRA_CUSTOM_ACTIONS));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
if (DEBUG) Log.d(TAG, "onNewIntent(), intent=" + intent);
|
||||
super.onNewIntent(intent);
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|
||||
&& event.getAction() == KeyEvent.ACTION_UP) {
|
||||
restorePipAndFinish();
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
onPipMenuActionsChanged(getIntent().getParcelableExtra(EXTRA_CUSTOM_ACTIONS));
|
||||
@Nullable
|
||||
SurfaceControl getWindowSurfaceControl() {
|
||||
final ViewRootImpl root = getViewRootImpl();
|
||||
if (root == null) {
|
||||
return null;
|
||||
}
|
||||
final SurfaceControl out = root.getSurfaceControl();
|
||||
if (out != null && out.isValid()) {
|
||||
return out;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void showMenu() {
|
||||
mPipController.addListener(this);
|
||||
mFadeInAnimation.start();
|
||||
setAlpha(1.0f);
|
||||
try {
|
||||
WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
|
||||
getViewRootImpl().getInputToken(), true /* grantFocus */);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to update focus as menu appears", e);
|
||||
}
|
||||
}
|
||||
|
||||
void hideMenu() {
|
||||
mPipController.removeListener(this);
|
||||
mPipController.resumePipResizing(
|
||||
PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
|
||||
mFadeOutAnimation.start();
|
||||
setAlpha(0.0f);
|
||||
try {
|
||||
WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
|
||||
getViewRootImpl().getInputToken(), false /* grantFocus */);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to update focus as menu disappears", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void restorePipAndFinish() {
|
||||
@@ -84,43 +119,9 @@ public class PipMenuActivity extends Activity implements PipController.Listener
|
||||
if (DEBUG) Log.d(TAG, " > restoring to the default position");
|
||||
|
||||
// When PIP menu activity is closed, restore to the default position.
|
||||
sPipController.resizePinnedStack(PipController.STATE_PIP);
|
||||
mPipController.resizePinnedStack(PipController.STATE_PIP);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
if (DEBUG) Log.d(TAG, "onResume()");
|
||||
|
||||
super.onResume();
|
||||
mFadeInAnimation.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (DEBUG) Log.d(TAG, "onPause()");
|
||||
|
||||
super.onPause();
|
||||
mFadeOutAnimation.start();
|
||||
restorePipAndFinish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (DEBUG) Log.d(TAG, "onDestroy()");
|
||||
|
||||
super.onDestroy();
|
||||
sPipController.removeListener(this);
|
||||
sPipController.resumePipResizing(
|
||||
PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (DEBUG) Log.d(TAG, "onBackPressed()");
|
||||
|
||||
restorePipAndFinish();
|
||||
hideMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,11 +133,10 @@ public class PipMenuActivity extends Activity implements PipController.Listener
|
||||
public void onPipActivityClosed() {
|
||||
if (DEBUG) Log.d(TAG, "onPipActivityClosed()");
|
||||
|
||||
finish();
|
||||
hideMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipMenuActionsChanged(ParceledListSlice<RemoteAction> actions) {
|
||||
void setAppActions(ParceledListSlice<RemoteAction> actions) {
|
||||
if (DEBUG) Log.d(TAG, "onPipMenuActionsChanged()");
|
||||
|
||||
boolean hasCustomActions = actions != null && !actions.getList().isEmpty();
|
||||
@@ -156,34 +156,15 @@ public class PipMenuActivity extends Activity implements PipController.Listener
|
||||
// Moving PIP to fullscreen is implemented by resizing PINNED_STACK with null bounds.
|
||||
// This conflicts with restoring PIP position, so disable it.
|
||||
mRestorePipSizeWhenClose = false;
|
||||
finish();
|
||||
hideMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipResizeAboutToStart() {
|
||||
if (DEBUG) Log.d(TAG, "onPipResizeAboutToStart()");
|
||||
|
||||
finish();
|
||||
sPipController.suspendPipResizing(
|
||||
hideMenu();
|
||||
mPipController.suspendPipResizing(
|
||||
PipController.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (DEBUG) Log.d(TAG, "finish()", new RuntimeException());
|
||||
|
||||
super.finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(b/169395392) Refactor PipMenuActivity to PipMenuView
|
||||
*
|
||||
* @param pipController The singleton pipController instance for TV
|
||||
*/
|
||||
public static void setPipController(PipController pipController) {
|
||||
if (sPipController != null) {
|
||||
return;
|
||||
}
|
||||
sPipController = pipController;
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,10 @@ package com.android.wm.shell.pip.tv;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteAction;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.MediaMetadata;
|
||||
@@ -98,11 +96,6 @@ public class PipNotification implements PipController.Listener {
|
||||
// no-op.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPipMenuActionsChanged(ParceledListSlice<RemoteAction> actions) {
|
||||
// no-op.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoveToFullscreen() {
|
||||
dismissPipNotification();
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.pip.tv;
|
||||
|
||||
import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
|
||||
|
||||
import android.app.RemoteAction;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import com.android.wm.shell.common.SystemWindows;
|
||||
import com.android.wm.shell.pip.PipBoundsState;
|
||||
import com.android.wm.shell.pip.PipMenuController;
|
||||
|
||||
/**
|
||||
* Manages the visibility of the PiP Menu as user interacts with PiP.
|
||||
*/
|
||||
public class TvPipMenuController implements PipMenuController {
|
||||
|
||||
private final Context mContext;
|
||||
private final SystemWindows mSystemWindows;
|
||||
private final PipBoundsState mPipBoundsState;
|
||||
private PipMenuView mMenuView;
|
||||
private PipController mPipController;
|
||||
private SurfaceControl mLeash;
|
||||
|
||||
public TvPipMenuController(Context context, PipBoundsState pipBoundsState,
|
||||
SystemWindows systemWindows) {
|
||||
mContext = context;
|
||||
mPipBoundsState = pipBoundsState;
|
||||
mSystemWindows = systemWindows;
|
||||
}
|
||||
|
||||
void attachPipController(PipController pipController) {
|
||||
mPipController = pipController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMenu() {
|
||||
if (mMenuView != null) {
|
||||
mSystemWindows.updateViewLayout(mMenuView, getPipMenuLayoutParams(MENU_WINDOW_TITLE,
|
||||
mPipBoundsState.getDisplayBounds().width(),
|
||||
mPipBoundsState.getDisplayBounds().height()));
|
||||
mMenuView.showMenu();
|
||||
|
||||
// By default, SystemWindows views are above everything else.
|
||||
// Set the relative z-order so the menu is below PiP.
|
||||
if (mMenuView.getWindowSurfaceControl() != null && mLeash != null) {
|
||||
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
|
||||
t.setRelativeLayer(mMenuView.getWindowSurfaceControl(), mLeash, -1);
|
||||
t.apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach(SurfaceControl leash) {
|
||||
if (mMenuView == null) {
|
||||
mMenuView = new PipMenuView(mContext, mPipController);
|
||||
mSystemWindows.addView(mMenuView,
|
||||
getPipMenuLayoutParams(MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
|
||||
0, SHELL_ROOT_LAYER_PIP);
|
||||
mLeash = leash;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
mSystemWindows.removeView(mMenuView);
|
||||
mMenuView = null;
|
||||
mLeash = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAppActions(ParceledListSlice<RemoteAction> appActions) {
|
||||
mMenuView.setAppActions(appActions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMenuVisible() {
|
||||
return mMenuView != null && mMenuView.getAlpha() == 1.0f;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ import android.window.WindowContainerToken;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.pip.phone.PipMenuActivityController;
|
||||
import com.android.wm.shell.pip.phone.PhonePipMenuController;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -66,7 +66,7 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
|
||||
@Mock private DisplayController mMockdDisplayController;
|
||||
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
|
||||
@Mock private PipMenuActivityController mMenuActivityController;
|
||||
@Mock private PhonePipMenuController mMockPhonePipMenuController;
|
||||
@Mock private PipSurfaceTransactionHelper mMockPipSurfaceTransactionHelper;
|
||||
@Mock private PipUiEventLogger mMockPipUiEventLogger;
|
||||
@Mock private Optional<SplitScreen> mMockOptionalSplitScreen;
|
||||
@@ -83,9 +83,9 @@ public class PipTaskOrganizerTest extends ShellTestCase {
|
||||
mComponent2 = new ComponentName(mContext, "component2");
|
||||
mPipBoundsState = new PipBoundsState(mContext);
|
||||
mSpiedPipTaskOrganizer = spy(new PipTaskOrganizer(mContext, mPipBoundsState,
|
||||
mMockPipBoundsAlgorithm, mMenuActivityController, mMockPipSurfaceTransactionHelper,
|
||||
mMockOptionalSplitScreen, mMockdDisplayController, mMockPipUiEventLogger,
|
||||
mMockShellTaskOrganizer));
|
||||
mMockPipBoundsAlgorithm, mMockPhonePipMenuController,
|
||||
mMockPipSurfaceTransactionHelper, mMockOptionalSplitScreen, mMockdDisplayController,
|
||||
mMockPipUiEventLogger, mMockShellTaskOrganizer));
|
||||
preparePipTaskOrg();
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ public class PipControllerTest extends ShellTestCase {
|
||||
private PipController mPipController;
|
||||
|
||||
@Mock private DisplayController mMockDisplayController;
|
||||
@Mock private PipMenuActivityController mMockPipMenuActivityController;
|
||||
@Mock private PhonePipMenuController mMockPhonePipMenuController;
|
||||
@Mock private PipAppOpsListener mMockPipAppOpsListener;
|
||||
@Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
|
||||
@Mock private PipMediaController mMockPipMediaController;
|
||||
@@ -77,7 +77,7 @@ public class PipControllerTest extends ShellTestCase {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mPipController = new PipController(mContext, mMockDisplayController,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
|
||||
mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
|
||||
mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
|
||||
mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
|
||||
mMockExecutor);
|
||||
doAnswer(invocation -> {
|
||||
@@ -110,7 +110,7 @@ public class PipControllerTest extends ShellTestCase {
|
||||
|
||||
assertNull(PipController.create(spyContext, mMockDisplayController,
|
||||
mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipBoundsState,
|
||||
mMockPipMediaController, mMockPipMenuActivityController, mMockPipTaskOrganizer,
|
||||
mMockPipMediaController, mMockPhonePipMenuController, mMockPipTaskOrganizer,
|
||||
mMockPipTouchHandler, mMockWindowManagerShellWrapper, mMockTaskStackListener,
|
||||
mMockExecutor));
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
private PipTouchHandler mPipTouchHandler;
|
||||
|
||||
@Mock
|
||||
private PipMenuActivityController mPipMenuActivityController;
|
||||
private PhonePipMenuController mPhonePipMenuController;
|
||||
|
||||
@Mock
|
||||
private PipTaskOrganizer mPipTaskOrganizer;
|
||||
@@ -92,7 +92,7 @@ public class PipTouchHandlerTest extends ShellTestCase {
|
||||
mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState);
|
||||
mPipSnapAlgorithm = mPipBoundsAlgorithm.getSnapAlgorithm();
|
||||
mPipSnapAlgorithm = new PipSnapAlgorithm();
|
||||
mPipTouchHandler = new PipTouchHandler(mContext, mPipMenuActivityController,
|
||||
mPipTouchHandler = new PipTouchHandler(mContext, mPhonePipMenuController,
|
||||
mPipBoundsAlgorithm, mPipBoundsState, mPipTaskOrganizer,
|
||||
mFloatingContentCoordinator, mPipUiEventLogger);
|
||||
mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
|
||||
|
||||
@@ -516,20 +516,6 @@
|
||||
android:excludeFromRecents="true"
|
||||
android:visibleToInstantApps="true"/>
|
||||
|
||||
<!-- started from PipController -->
|
||||
<activity
|
||||
android:name="com.android.wm.shell.pip.tv.PipMenuActivity"
|
||||
android:permission="com.android.systemui.permission.SELF"
|
||||
android:exported="false"
|
||||
android:theme="@style/PipTheme"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|locale|layoutDirection"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
androidprv:alwaysFocusable="true"
|
||||
android:excludeFromRecents="true" />
|
||||
|
||||
<!-- started from TvNotificationPanel -->
|
||||
<activity
|
||||
android:name=".statusbar.tv.notifications.TvNotificationPanelActivity"
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.android.systemui.dagger.WMSingleton;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.SystemWindows;
|
||||
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.pip.PipBoundsAlgorithm;
|
||||
@@ -34,6 +35,7 @@ import com.android.wm.shell.pip.tv.PipController;
|
||||
import com.android.wm.shell.pip.tv.PipControlsView;
|
||||
import com.android.wm.shell.pip.tv.PipControlsViewController;
|
||||
import com.android.wm.shell.pip.tv.PipNotification;
|
||||
import com.android.wm.shell.pip.tv.TvPipMenuController;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -44,7 +46,7 @@ import dagger.Provides;
|
||||
/**
|
||||
* Dagger module for TV Pip.
|
||||
*/
|
||||
@Module
|
||||
@Module(includes = {WMShellBaseModule.class})
|
||||
public abstract class TvPipModule {
|
||||
@WMSingleton
|
||||
@Provides
|
||||
@@ -53,6 +55,7 @@ public abstract class TvPipModule {
|
||||
PipBoundsState pipBoundsState,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
TvPipMenuController tvPipMenuController,
|
||||
PipMediaController pipMediaController,
|
||||
PipNotification pipNotification,
|
||||
TaskStackListenerImpl taskStackListener,
|
||||
@@ -63,6 +66,7 @@ public abstract class TvPipModule {
|
||||
pipBoundsState,
|
||||
pipBoundsAlgorithm,
|
||||
pipTaskOrganizer,
|
||||
tvPipMenuController,
|
||||
pipMediaController,
|
||||
pipNotification,
|
||||
taskStackListener,
|
||||
@@ -102,16 +106,24 @@ public abstract class TvPipModule {
|
||||
return new PipBoundsState(context);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static TvPipMenuController providesPipTvMenuController(Context context,
|
||||
PipBoundsState pipBoundsState, SystemWindows systemWindows) {
|
||||
return new TvPipMenuController(context, pipBoundsState, systemWindows);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipTaskOrganizer providePipTaskOrganizer(Context context,
|
||||
TvPipMenuController tvMenuController,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
|
||||
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
|
||||
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
|
||||
return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
|
||||
null /* menuActivityController */, pipSurfaceTransactionHelper, splitScreenOptional,
|
||||
tvMenuController, pipSurfaceTransactionHelper, splitScreenOptional,
|
||||
displayController, pipUiEventLogger, shellTaskOrganizer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ import dagger.Provides;
|
||||
* Provides dependencies from {@link com.android.wm.shell} which could be customized among different
|
||||
* branches of SystemUI.
|
||||
*/
|
||||
@Module(includes = {WMShellBaseModule.class, TvPipModule.class})
|
||||
@Module(includes = {TvPipModule.class})
|
||||
public class TvWMShellModule {
|
||||
@WMSingleton
|
||||
@Provides
|
||||
|
||||
@@ -41,9 +41,9 @@ import com.android.wm.shell.pip.PipMediaController;
|
||||
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.phone.PhonePipMenuController;
|
||||
import com.android.wm.shell.pip.phone.PipAppOpsListener;
|
||||
import com.android.wm.shell.pip.phone.PipController;
|
||||
import com.android.wm.shell.pip.phone.PipMenuActivityController;
|
||||
import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
@@ -93,12 +93,12 @@ public class WMShellModule {
|
||||
static Optional<Pip> providePip(Context context, DisplayController displayController,
|
||||
PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState, PipMediaController pipMediaController,
|
||||
PipMenuActivityController pipMenuActivityController, PipTaskOrganizer pipTaskOrganizer,
|
||||
PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer,
|
||||
PipTouchHandler pipTouchHandler, WindowManagerShellWrapper windowManagerShellWrapper,
|
||||
TaskStackListenerImpl taskStackListener, ShellExecutor mainExecutor) {
|
||||
return Optional.ofNullable(PipController.create(context, displayController,
|
||||
pipAppOpsListener, pipBoundsAlgorithm, pipBoundsState, pipMediaController,
|
||||
pipMenuActivityController, pipTaskOrganizer, pipTouchHandler,
|
||||
phonePipMenuController, pipTaskOrganizer, pipTouchHandler,
|
||||
windowManagerShellWrapper, taskStackListener, mainExecutor));
|
||||
}
|
||||
|
||||
@@ -117,20 +117,20 @@ public class WMShellModule {
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipMenuActivityController providesPipMenuActivityController(Context context,
|
||||
static PhonePipMenuController providesPipPhoneMenuController(Context context,
|
||||
PipMediaController pipMediaController, SystemWindows systemWindows) {
|
||||
return new PipMenuActivityController(context, pipMediaController, systemWindows);
|
||||
return new PhonePipMenuController(context, pipMediaController, systemWindows);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static PipTouchHandler providePipTouchHandler(Context context,
|
||||
PipMenuActivityController menuActivityController, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PhonePipMenuController menuPhoneController, PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipTaskOrganizer pipTaskOrganizer,
|
||||
FloatingContentCoordinator floatingContentCoordinator,
|
||||
PipUiEventLogger pipUiEventLogger) {
|
||||
return new PipTouchHandler(context, menuActivityController, pipBoundsAlgorithm,
|
||||
return new PipTouchHandler(context, menuPhoneController, pipBoundsAlgorithm,
|
||||
pipBoundsState, pipTaskOrganizer, floatingContentCoordinator, pipUiEventLogger);
|
||||
}
|
||||
|
||||
@@ -139,12 +139,12 @@ public class WMShellModule {
|
||||
static PipTaskOrganizer providePipTaskOrganizer(Context context,
|
||||
PipBoundsState pipBoundsState,
|
||||
PipBoundsAlgorithm pipBoundsAlgorithm,
|
||||
PipMenuActivityController menuActivityController,
|
||||
PhonePipMenuController menuPhoneController,
|
||||
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
|
||||
Optional<SplitScreen> splitScreenOptional, DisplayController displayController,
|
||||
PipUiEventLogger pipUiEventLogger, ShellTaskOrganizer shellTaskOrganizer) {
|
||||
return new PipTaskOrganizer(context, pipBoundsState, pipBoundsAlgorithm,
|
||||
menuActivityController, pipSurfaceTransactionHelper, splitScreenOptional,
|
||||
menuPhoneController, pipSurfaceTransactionHelper, splitScreenOptional,
|
||||
displayController, pipUiEventLogger, shellTaskOrganizer);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user