Use mobile code for TV Shell Transitions.

- Uses alpha instead of bounds animation on TV during PiP entry
- Attaches the menu earlier to make sure the PiP immediately
appears in the right position as the menu affects the position.

Bug: 271098548
Bug: 228071323
Test: manual - PiP should fade in instead of being scaled from
fullscreen to the PiP size, PiP should not appear low and then
move up.

Change-Id: I51b6deea3d0e2f2e7166e9df8c98685d6aee82a3
This commit is contained in:
Jacqueline Bronger
2023-01-24 16:50:49 +01:00
parent d00b03a853
commit f928c832f3
6 changed files with 96 additions and 58 deletions

View File

@@ -157,14 +157,21 @@ public abstract class TvPipModule {
@WMSingleton
@Provides
static PipTransitionController provideTvPipTransition(
Context context,
ShellInit shellInit,
ShellTaskOrganizer shellTaskOrganizer,
Transitions transitions,
PipAnimationController pipAnimationController,
TvPipBoundsState tvPipBoundsState,
PipDisplayLayoutState pipDisplayLayoutState,
PipTransitionState pipTransitionState,
TvPipMenuController pipMenuController,
TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
TvPipBoundsState tvPipBoundsState, TvPipMenuController pipMenuController) {
return new TvPipTransition(shellInit, shellTaskOrganizer, transitions, tvPipBoundsState,
pipMenuController, tvPipBoundsAlgorithm, pipAnimationController);
PipAnimationController pipAnimationController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper) {
return new TvPipTransition(context, shellInit, shellTaskOrganizer, transitions,
tvPipBoundsState, pipDisplayLayoutState, pipTransitionState, pipMenuController,
tvPipBoundsAlgorithm, pipAnimationController, pipSurfaceTransactionHelper,
Optional.empty());
}
@WMSingleton

View File

@@ -415,6 +415,26 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
}
/**
* Override if the PiP should always use a fade-in animation during PiP entry.
*
* @return true if the mOneShotAnimationType should always be
* {@link PipAnimationController#ANIM_TYPE_ALPHA}.
*/
protected boolean shouldAlwaysFadeIn() {
return false;
}
/**
* Whether the menu should get attached as early as possible when entering PiP.
*
* @return whether the menu should be attached before
* {@link PipBoundsAlgorithm#getEntryDestinationBounds()} is called.
*/
protected boolean shouldAttachMenuEarly() {
return false;
}
/**
* Callback when Launcher starts swipe-pip-to-home operation.
* @return {@link Rect} for destination bounds.
@@ -709,17 +729,26 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return;
}
if (shouldAlwaysFadeIn()) {
mOneShotAnimationType = ANIM_TYPE_ALPHA;
}
if (mWaitForFixedRotation) {
onTaskAppearedWithFixedRotation();
return;
}
if (shouldAttachMenuEarly()) {
mPipMenuController.attach(mLeash);
}
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
mPipMenuController.attach(mLeash);
if (!shouldAttachMenuEarly()) {
mPipMenuController.attach(mLeash);
}
final Rect sourceHintRect = PipBoundsAlgorithm.getValidSourceHintRect(
info.pictureInPictureParams, currentBounds);
scheduleAnimateResizePip(currentBounds, destinationBounds, 0 /* startingAngle */,
@@ -834,7 +863,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
@Nullable SurfaceControl.Transaction boundsChangeTransaction) {
// PiP menu is attached late in the process here to avoid any artifacts on the leash
// caused by addShellRoot when in gesture navigation mode.
mPipMenuController.attach(mLeash);
if (!shouldAttachMenuEarly()) {
mPipMenuController.attach(mLeash);
}
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setActivityWindowingMode(mToken, WINDOWING_MODE_UNDEFINED);
wct.setBounds(mToken, destinationBounds);

View File

@@ -272,6 +272,8 @@ public class PipTransition extends PipTransitionController {
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
if (requestHasPipEnter(request)) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: handle PiP enter request", TAG);
WindowContainerTransaction wct = new WindowContainerTransaction();
augmentRequest(transition, request, wct);
return wct;
@@ -731,6 +733,11 @@ public class PipTransition extends PipTransitionController {
setBoundsStateForEntry(taskInfo.topActivity, taskInfo.pictureInPictureParams,
taskInfo.topActivityInfo);
if (mPipOrganizer.shouldAttachMenuEarly()) {
mPipMenuController.attach(leash);
}
final Rect destinationBounds = mPipBoundsAlgorithm.getEntryDestinationBounds();
final Rect currentBounds = taskInfo.configuration.windowConfiguration.getBounds();
int rotationDelta = deltaRotation(startRotation, endRotation);
@@ -745,7 +752,10 @@ public class PipTransition extends PipTransitionController {
mSurfaceTransactionHelper
.crop(finishTransaction, leash, destinationBounds)
.round(finishTransaction, leash, true /* applyCornerRadius */);
mTransitions.getMainExecutor().executeDelayed(() -> mPipMenuController.attach(leash), 0);
if (!mPipOrganizer.shouldAttachMenuEarly()) {
mTransitions.getMainExecutor().executeDelayed(
() -> mPipMenuController.attach(leash), 0);
}
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()
@@ -785,6 +795,11 @@ public class PipTransition extends PipTransitionController {
tmpTransform.postRotate(rotationDelta);
startTransaction.setMatrix(leash, tmpTransform, new float[9]);
}
if (mPipOrganizer.shouldAlwaysFadeIn()) {
mOneShotAnimationType = ANIM_TYPE_ALPHA;
}
if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
startTransaction.setAlpha(leash, 0f);
}

View File

@@ -446,7 +446,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
"%s: PiP has already been closed by custom close action", TAG);
return;
}
removeTask(mPinnedTaskId);
mPipTaskOrganizer.removePip();
onPipDisappeared();
}
@@ -673,17 +673,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal
}
}
private static void removeTask(int taskId) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: removeTask(), taskId=%d", TAG, taskId);
try {
ActivityTaskManager.getService().removeTask(taskId);
} catch (Exception e) {
ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Atm.removeTask() failed, %s", TAG, e);
}
}
private static String stateToName(@State int state) {
switch (state) {
case STATE_NO_PIP:

View File

@@ -85,4 +85,17 @@ public class TvPipTaskOrganizer extends PipTaskOrganizer {
mPipParamsChangedForwarder.notifySubtitleChanged(params.getSubtitle());
}
}
/**
* Override for TV since the menu bounds affect the PiP location. Additionally, we want to
* ensure that menu is shown immediately since it should always be visible on TV as it creates
* a border with rounded corners around the PiP.
*/
protected boolean shouldAttachMenuEarly() {
return true;
}
protected boolean shouldAlwaysFadeIn() {
return true;
}
}

View File

@@ -16,60 +16,43 @@
package com.android.wm.shell.pip.tv;
import android.app.TaskInfo;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.pip.PipBoundsState;
import com.android.wm.shell.pip.PipMenuController;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip.PipDisplayLayoutState;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipTransition;
import com.android.wm.shell.pip.PipTransitionState;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
/**
* PiP Transition for TV.
* TODO: Implement animation once TV is using Transitions.
*/
public class TvPipTransition extends PipTransitionController {
public TvPipTransition(
public class TvPipTransition extends PipTransition {
public TvPipTransition(Context context,
@NonNull ShellInit shellInit,
@NonNull ShellTaskOrganizer shellTaskOrganizer,
@NonNull Transitions transitions,
PipBoundsState pipBoundsState,
PipMenuController pipMenuController,
TvPipBoundsState tvPipBoundsState,
PipDisplayLayoutState pipDisplayLayoutState,
PipTransitionState pipTransitionState,
TvPipMenuController tvPipMenuController,
TvPipBoundsAlgorithm tvPipBoundsAlgorithm,
PipAnimationController pipAnimationController) {
super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController,
tvPipBoundsAlgorithm, pipAnimationController);
PipAnimationController pipAnimationController,
PipSurfaceTransactionHelper pipSurfaceTransactionHelper,
Optional<SplitScreenController> splitScreenOptional) {
super(context, shellInit, shellTaskOrganizer, transitions, tvPipBoundsState,
pipDisplayLayoutState, pipTransitionState, tvPipMenuController,
tvPipBoundsAlgorithm, pipAnimationController, pipSurfaceTransactionHelper,
splitScreenOptional);
}
@Override
public void onFinishResize(TaskInfo taskInfo, Rect destinationBounds, int direction,
SurfaceControl.Transaction tx) {
}
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@android.annotation.NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
return false;
}
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@NonNull TransitionRequestInfo request) {
return null;
}
}