summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Jetpack/Android.bp18
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java10
-rw-r--r--libs/WindowManager/Jetpack/window-extensions-core-release.aarbin3714 -> 0 bytes
-rw-r--r--libs/WindowManager/Jetpack/window-extensions-release.aarbin41055 -> 0 bytes
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java49
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java24
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java45
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java58
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java66
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java47
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java39
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java107
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java71
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java88
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java87
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidTest.xml1
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java26
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java25
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java25
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java32
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java19
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java54
-rw-r--r--libs/hwui/RecordingCanvas.cpp17
-rw-r--r--libs/hwui/hwui/AnimatedImageDrawable.cpp33
-rw-r--r--libs/hwui/hwui/AnimatedImageDrawable.h17
-rw-r--r--libs/hwui/jni/AnimatedImageDrawable.cpp6
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp36
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h8
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp24
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp9
-rw-r--r--libs/hwui/pipeline/skia/SkiaVulkanPipeline.h4
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp6
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp9
-rw-r--r--libs/hwui/renderthread/CanvasContext.h3
-rw-r--r--libs/hwui/renderthread/EglManager.cpp20
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h2
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp40
-rw-r--r--libs/hwui/renderthread/VulkanSurface.cpp33
-rw-r--r--libs/hwui/renderthread/VulkanSurface.h4
57 files changed, 848 insertions, 503 deletions
diff --git a/libs/WindowManager/Jetpack/Android.bp b/libs/WindowManager/Jetpack/Android.bp
index a5b192cd7ceb..abe8f859f2fe 100644
--- a/libs/WindowManager/Jetpack/Android.bp
+++ b/libs/WindowManager/Jetpack/Android.bp
@@ -55,20 +55,6 @@ prebuilt_etc {
}
// Extensions
-// NOTE: This module is still under active development and must not
-// be used in production. Use 'androidx.window.sidecar' instead.
-android_library_import {
- name: "window-extensions",
- aars: ["window-extensions-release.aar"],
- sdk_version: "current",
-}
-
-android_library_import {
- name: "window-extensions-core",
- aars: ["window-extensions-core-release.aar"],
- sdk_version: "current",
-}
-
java_library {
name: "androidx.window.extensions",
srcs: [
@@ -77,8 +63,8 @@ java_library {
"src/androidx/window/common/**/*.java",
],
static_libs: [
- "window-extensions",
- "window-extensions-core",
+ "androidx.window.extensions_extensions-nodeps",
+ "androidx.window.extensions.core_core-nodeps",
],
installable: true,
sdk_version: "core_platform",
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index 8386131b177d..a7a6b3c92157 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -122,16 +122,6 @@ public class WindowLayoutComponentImpl implements WindowLayoutComponent {
addWindowLayoutInfoListener(activity, extConsumer);
}
- @Override
- public void addWindowLayoutInfoListener(@NonNull @UiContext Context context,
- @NonNull java.util.function.Consumer<WindowLayoutInfo> consumer) {
- final Consumer<WindowLayoutInfo> extConsumer = consumer::accept;
- synchronized (mLock) {
- mJavaToExtConsumers.put(consumer, extConsumer);
- }
- addWindowLayoutInfoListener(context, extConsumer);
- }
-
/**
* Similar to {@link #addWindowLayoutInfoListener(Activity, java.util.function.Consumer)}, but
* takes a UI Context as a parameter.
diff --git a/libs/WindowManager/Jetpack/window-extensions-core-release.aar b/libs/WindowManager/Jetpack/window-extensions-core-release.aar
deleted file mode 100644
index 96ff840b984b..000000000000
--- a/libs/WindowManager/Jetpack/window-extensions-core-release.aar
+++ /dev/null
Binary files differ
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
deleted file mode 100644
index c3b6916121d0..000000000000
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ /dev/null
Binary files differ
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
index 521a65cc4df6..bfbddbbe4aa0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingController.java
@@ -22,6 +22,7 @@ import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
import static java.util.Objects.requireNonNull;
import android.content.Context;
+import android.graphics.Rect;
import android.os.IBinder;
import android.util.ArrayMap;
import android.view.SurfaceControl;
@@ -35,6 +36,9 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.util.TransitionUtil;
+
+import java.util.List;
/**
* Responsible for handling ActivityEmbedding related transitions.
@@ -86,12 +90,13 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
boolean containsEmbeddingSplit = false;
- for (TransitionInfo.Change change : info.getChanges()) {
+ boolean containsNonEmbeddedChange = false;
+ final List<TransitionInfo.Change> changes = info.getChanges();
+ for (int i = changes.size() - 1; i >= 0; i--) {
+ final TransitionInfo.Change change = changes.get(i);
if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
- // Only animate the transition if all changes are in a Task with ActivityEmbedding.
- return false;
- }
- if (!containsEmbeddingSplit && !change.hasFlags(FLAG_FILLS_TASK)) {
+ containsNonEmbeddedChange = true;
+ } else if (!change.hasFlags(FLAG_FILLS_TASK)) {
// Whether the Task contains any ActivityEmbedding split before or after the
// transition.
containsEmbeddingSplit = true;
@@ -103,6 +108,9 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
// such as the device is in a folded state.
return false;
}
+ if (containsNonEmbeddedChange && !handleNonEmbeddedChanges(changes)) {
+ return false;
+ }
// Start ActivityEmbedding animation.
mTransitionCallbacks.put(transition, finishCallback);
@@ -110,6 +118,37 @@ public class ActivityEmbeddingController implements Transitions.TransitionHandle
return true;
}
+ private boolean handleNonEmbeddedChanges(List<TransitionInfo.Change> changes) {
+ final Rect nonClosingEmbeddedArea = new Rect();
+ for (int i = changes.size() - 1; i >= 0; i--) {
+ final TransitionInfo.Change change = changes.get(i);
+ if (!TransitionUtil.isClosingType(change.getMode())) {
+ if (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
+ nonClosingEmbeddedArea.union(change.getEndAbsBounds());
+ continue;
+ }
+ // Not able to handle non-embedded container if it is not closing.
+ return false;
+ }
+ }
+ for (int i = changes.size() - 1; i >= 0; i--) {
+ final TransitionInfo.Change change = changes.get(i);
+ if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)
+ && !nonClosingEmbeddedArea.contains(change.getEndAbsBounds())) {
+ // Unknown to animate containers outside the area of embedded activities.
+ return false;
+ }
+ }
+ // Drop the non-embedded closing change because it is occluded by embedded activities.
+ for (int i = changes.size() - 1; i >= 0; i--) {
+ final TransitionInfo.Change change = changes.get(i);
+ if (!change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
+ changes.remove(i);
+ }
+ }
+ return true;
+ }
+
@Nullable
@Override
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index e84a78f42616..133fd87a2f63 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -33,12 +33,19 @@ public interface BackAnimation {
*
* @param touchX the X touch position of the {@link MotionEvent}.
* @param touchY the Y touch position of the {@link MotionEvent}.
+ * @param velocityX the X velocity computed from the {@link MotionEvent}.
+ * @param velocityY the Y velocity computed from the {@link MotionEvent}.
* @param keyAction the original {@link KeyEvent#getAction()} when the event was dispatched to
* the process. This is forwarded separately because the input pipeline may mutate
* the {#event} action state later.
* @param swipeEdge the edge from which the swipe begins.
*/
- void onBackMotion(float touchX, float touchY, int keyAction,
+ void onBackMotion(
+ float touchX,
+ float touchY,
+ float velocityX,
+ float velocityY,
+ int keyAction,
@BackEvent.SwipeEdge int swipeEdge);
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 210c9aab14d6..47d3a5c52074 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -256,8 +256,20 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private class BackAnimationImpl implements BackAnimation {
@Override
public void onBackMotion(
- float touchX, float touchY, int keyAction, @BackEvent.SwipeEdge int swipeEdge) {
- mShellExecutor.execute(() -> onMotionEvent(touchX, touchY, keyAction, swipeEdge));
+ float touchX,
+ float touchY,
+ float velocityX,
+ float velocityY,
+ int keyAction,
+ @BackEvent.SwipeEdge int swipeEdge
+ ) {
+ mShellExecutor.execute(() -> onMotionEvent(
+ /* touchX = */ touchX,
+ /* touchY = */ touchY,
+ /* velocityX = */ velocityX,
+ /* velocityY = */ velocityY,
+ /* keyAction = */ keyAction,
+ /* swipeEdge = */ swipeEdge));
}
@Override
@@ -332,13 +344,18 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
* Called when a new motion event needs to be transferred to this
* {@link BackAnimationController}
*/
- public void onMotionEvent(float touchX, float touchY, int keyAction,
+ public void onMotionEvent(
+ float touchX,
+ float touchY,
+ float velocityX,
+ float velocityY,
+ int keyAction,
@BackEvent.SwipeEdge int swipeEdge) {
if (mPostCommitAnimationInProgress) {
return;
}
- mTouchTracker.update(touchX, touchY);
+ mTouchTracker.update(touchX, touchY, velocityX, velocityY);
if (keyAction == MotionEvent.ACTION_DOWN) {
if (!mBackGestureStarted) {
mShouldStartOnNextMoveEvent = true;
@@ -561,6 +578,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
if (runner.isWaitingAnimation()) {
ProtoLog.w(WM_SHELL_BACK_PREVIEW, "Gesture released, but animation didn't ready.");
+ // Supposed it is in post commit animation state, and start the timeout to watch
+ // if the animation is ready.
+ mShellExecutor.executeDelayed(mAnimationTimeoutRunnable, MAX_ANIMATION_DURATION);
return;
} else if (runner.isAnimationCancelled()) {
invokeOrCancelBack();
@@ -577,6 +597,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
if (mPostCommitAnimationInProgress) {
return;
}
+
+ mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable);
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: startPostCommitAnimation()");
mPostCommitAnimationInProgress = true;
mShellExecutor.executeDelayed(mAnimationTimeoutRunnable, MAX_ANIMATION_DURATION);
@@ -595,9 +617,6 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
*/
@VisibleForTesting
void onBackAnimationFinished() {
- if (!mPostCommitAnimationInProgress) {
- return;
- }
// Stop timeout runner.
mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable);
mPostCommitAnimationInProgress = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 695ef4e66302..904574b08562 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -42,11 +42,13 @@ class TouchTracker {
*/
private float mInitTouchX;
private float mInitTouchY;
+ private float mLatestVelocityX;
+ private float mLatestVelocityY;
private float mStartThresholdX;
private int mSwipeEdge;
private boolean mCancelled;
- void update(float touchX, float touchY) {
+ void update(float touchX, float touchY, float velocityX, float velocityY) {
/**
* If back was previously cancelled but the user has started swiping in the forward
* direction again, restart back.
@@ -58,6 +60,8 @@ class TouchTracker {
}
mLatestTouchX = touchX;
mLatestTouchY = touchY;
+ mLatestVelocityX = velocityX;
+ mLatestVelocityY = velocityY;
}
void setTriggerBack(boolean triggerBack) {
@@ -84,7 +88,14 @@ class TouchTracker {
}
BackMotionEvent createStartEvent(RemoteAnimationTarget target) {
- return new BackMotionEvent(mInitTouchX, mInitTouchY, 0, mSwipeEdge, target);
+ return new BackMotionEvent(
+ /* touchX = */ mInitTouchX,
+ /* touchY = */ mInitTouchY,
+ /* progress = */ 0,
+ /* velocityX = */ 0,
+ /* velocityY = */ 0,
+ /* swipeEdge = */ mSwipeEdge,
+ /* departingAnimationTarget = */ target);
}
BackMotionEvent createProgressEvent() {
@@ -111,7 +122,14 @@ class TouchTracker {
}
BackMotionEvent createProgressEvent(float progress) {
- return new BackMotionEvent(mLatestTouchX, mLatestTouchY, progress, mSwipeEdge, null);
+ return new BackMotionEvent(
+ /* touchX = */ mLatestTouchX,
+ /* touchY = */ mLatestTouchY,
+ /* progress = */ progress,
+ /* velocityX = */ mLatestVelocityX,
+ /* velocityY = */ mLatestVelocityY,
+ /* swipeEdge = */ mSwipeEdge,
+ /* departingAnimationTarget = */ null);
}
public void setProgressThreshold(float progressThreshold) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 670b24c176b5..0400963a47e8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -25,6 +25,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.app.WindowConfiguration.WindowingMode
import android.content.Context
+import android.graphics.Point
import android.graphics.Rect
import android.os.IBinder
import android.os.SystemProperties
@@ -193,6 +194,21 @@ class DesktopTasksController(
}
}
+
+ /**
+ * Move a task to fullscreen after being dragged from fullscreen and released back into
+ * status bar area
+ */
+ fun cancelMoveToFreeform(task: RunningTaskInfo, startPosition: Point) {
+ val wct = WindowContainerTransaction()
+ addMoveToFullscreenChanges(wct, task.token)
+ if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+ enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition)
+ } else {
+ shellTaskOrganizer.applyTransaction(wct)
+ }
+ }
+
fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) {
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 3df2340d4524..27eda16f4171 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -17,11 +17,13 @@
package com.android.wm.shell.desktopmode;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
+import android.graphics.Point;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.SurfaceControl;
@@ -55,6 +57,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
public static final int FREEFORM_ANIMATION_DURATION = 336;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
+ private Point mStartPosition;
public EnterDesktopTaskTransitionHandler(
Transitions transitions) {
@@ -79,6 +82,17 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
mPendingTransitionTokens.add(token);
}
+ /**
+ * Starts Transition of type TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
+ * @param wct WindowContainerTransaction for transition
+ * @param startPosition Position of task when transition is triggered
+ */
+ public void startCancelMoveToDesktopMode(@NonNull WindowContainerTransaction wct,
+ Point startPosition) {
+ mStartPosition = startPosition;
+ startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct);
+ }
+
@Override
public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startT,
@@ -173,6 +187,37 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
return true;
}
+ if (type == Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
+ && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ && mStartPosition != null) {
+ // This Transition animates a task to fullscreen after being dragged from the status
+ // bar and then released back into the status bar area
+ final SurfaceControl sc = change.getLeash();
+ startT.setWindowCrop(sc, null);
+ startT.apply();
+
+ final ValueAnimator animator = new ValueAnimator();
+ animator.setFloatValues(DRAG_FREEFORM_SCALE, 1f);
+ animator.setDuration(FREEFORM_ANIMATION_DURATION);
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+ animator.addUpdateListener(animation -> {
+ final float scale = animation.getAnimatedFraction();
+ t.setPosition(sc, mStartPosition.x * (1 - scale),
+ mStartPosition.y * (1 - scale));
+ t.setScale(sc, scale, scale);
+ t.apply();
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTransitions.getMainExecutor().execute(
+ () -> finishCallback.onTransitionFinished(null, null));
+ }
+ });
+ animator.start();
+ return true;
+ }
+
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index f70df833cf4f..1d7e64988359 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -30,14 +30,17 @@ import android.app.TaskInfo;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Rect;
+import android.os.SystemClock;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.launcher3.icons.IconProvider;
import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.transition.Transitions;
import java.lang.annotation.Retention;
@@ -61,6 +64,14 @@ public class PipAnimationController {
@Retention(RetentionPolicy.SOURCE)
public @interface AnimationType {}
+ /**
+ * The alpha type is set for swiping to home. But the swiped task may not enter PiP. And if
+ * another task enters PiP by non-swipe ways, e.g. call API in foreground or switch to 3-button
+ * navigation, then the alpha type is unexpected. So use a timeout to avoid applying wrong
+ * animation style to an unrelated task.
+ */
+ private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 800;
+
public static final int TRANSITION_DIRECTION_NONE = 0;
public static final int TRANSITION_DIRECTION_SAME = 1;
public static final int TRANSITION_DIRECTION_TO_PIP = 2;
@@ -109,6 +120,9 @@ public class PipAnimationController {
});
private PipTransitionAnimator mCurrentAnimator;
+ @AnimationType
+ private int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
+ private long mLastOneShotAlphaAnimationTime;
public PipAnimationController(PipSurfaceTransactionHelper helper) {
mSurfaceTransactionHelper = helper;
@@ -222,6 +236,37 @@ public class PipAnimationController {
}
/**
+ * Sets the preferred enter animation type for one time. This is typically used to set the
+ * animation type to {@link PipAnimationController#ANIM_TYPE_ALPHA}.
+ * <p>
+ * For example, gesture navigation would first fade out the PiP activity, and the transition
+ * should be responsible to animate in (such as fade in) the PiP.
+ */
+ public void setOneShotEnterAnimationType(@AnimationType int animationType) {
+ mOneShotAnimationType = animationType;
+ if (animationType == ANIM_TYPE_ALPHA) {
+ mLastOneShotAlphaAnimationTime = SystemClock.uptimeMillis();
+ }
+ }
+
+ /** Returns the preferred animation type and consumes the one-shot type if needed. */
+ @AnimationType
+ public int takeOneShotEnterAnimationType() {
+ final int type = mOneShotAnimationType;
+ if (type == ANIM_TYPE_ALPHA) {
+ // Restore to default type.
+ mOneShotAnimationType = ANIM_TYPE_BOUNDS;
+ if (SystemClock.uptimeMillis() - mLastOneShotAlphaAnimationTime
+ > ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "Alpha animation is expired. Use bounds animation.");
+ return ANIM_TYPE_BOUNDS;
+ }
+ }
+ return type;
+ }
+
+ /**
* Additional callback interface for PiP animation
*/
public static class PipAnimationCallback {
@@ -255,7 +300,7 @@ public class PipAnimationController {
* @return true if handled by the handler, false otherwise.
*/
public boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx,
- Rect destinationBounds) {
+ Rect destinationBounds, float alpha) {
return false;
}
}
@@ -356,9 +401,10 @@ public class PipAnimationController {
}
boolean handlePipTransaction(SurfaceControl leash, SurfaceControl.Transaction tx,
- Rect destinationBounds) {
+ Rect destinationBounds, float alpha) {
if (mPipTransactionHandler != null) {
- return mPipTransactionHandler.handlePipTransaction(leash, tx, destinationBounds);
+ return mPipTransactionHandler.handlePipTransaction(
+ leash, tx, destinationBounds, alpha);
}
return false;
}
@@ -503,7 +549,9 @@ public class PipAnimationController {
getSurfaceTransactionHelper().alpha(tx, leash, alpha)
.round(tx, leash, shouldApplyCornerRadius())
.shadow(tx, leash, shouldApplyShadowRadius());
- tx.apply();
+ if (!handlePipTransaction(leash, tx, destinationBounds, alpha)) {
+ tx.apply();
+ }
}
@Override
@@ -618,7 +666,7 @@ public class PipAnimationController {
.shadow(tx, leash, shouldApplyShadowRadius());
}
}
- if (!handlePipTransaction(leash, tx, bounds)) {
+ if (!handlePipTransaction(leash, tx, bounds, /* alpha= */ 1f)) {
tx.apply();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
index 000624499f79..0775f5279e31 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
@@ -45,6 +45,13 @@ public interface PipMenuController {
String MENU_WINDOW_TITLE = "PipMenuView";
/**
+ * Used with
+ * {@link PipMenuController#movePipMenu(SurfaceControl, SurfaceControl.Transaction, Rect,
+ * float)} to indicate that we don't want to affect the alpha value of the menu surfaces.
+ */
+ float ALPHA_NO_CHANGE = -1f;
+
+ /**
* Called when
* {@link PipTaskOrganizer#onTaskAppeared(RunningTaskInfo, SurfaceControl)}
* is called.
@@ -85,8 +92,8 @@ public interface PipMenuController {
* need to synchronize the movements on the same frame as PiP.
*/
default void movePipMenu(@Nullable SurfaceControl pipLeash,
- @Nullable SurfaceControl.Transaction t,
- Rect destinationBounds) {}
+ @Nullable SurfaceControl.Transaction t, Rect destinationBounds, float alpha) {
+ }
/**
* Update the PiP menu with the given bounds for re-layout purposes.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index a0bd064149d2..23706a5e35a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -62,7 +62,6 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.Log;
import android.view.Choreographer;
@@ -111,12 +110,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
DisplayController.OnDisplaysChangedListener, ShellTaskOrganizer.FocusListener {
private static final String TAG = PipTaskOrganizer.class.getSimpleName();
private static final boolean DEBUG = false;
- /**
- * The alpha type is set for swiping to home. But the swiped task may not enter PiP. And if
- * another task enters PiP by non-swipe ways, e.g. call API in foreground or switch to 3-button
- * navigation, then the alpha type is unexpected.
- */
- private static final int ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS = 1000;
/**
* The fixed start delay in ms when fading out the content overlay from bounds animation.
@@ -256,7 +249,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}, null);
}
- private boolean shouldSyncPipTransactionWithMenu() {
+ protected boolean shouldSyncPipTransactionWithMenu() {
return mPipMenuController.isMenuVisible();
}
@@ -284,9 +277,9 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
new PipAnimationController.PipTransactionHandler() {
@Override
public boolean handlePipTransaction(SurfaceControl leash,
- SurfaceControl.Transaction tx, Rect destinationBounds) {
+ SurfaceControl.Transaction tx, Rect destinationBounds, float alpha) {
if (shouldSyncPipTransactionWithMenu()) {
- mPipMenuController.movePipMenu(leash, tx, destinationBounds);
+ mPipMenuController.movePipMenu(leash, tx, destinationBounds, alpha);
return true;
}
return false;
@@ -301,8 +294,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
private WindowContainerToken mToken;
private SurfaceControl mLeash;
protected PipTransitionState mPipTransitionState;
- private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
- private long mLastOneShotAlphaAnimationTime;
private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
protected PictureInPictureParams mPictureInPictureParams;
@@ -390,6 +381,10 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return mPipTransitionController;
}
+ PipAnimationController.PipTransactionHandler getPipTransactionHandler() {
+ return mPipTransactionHandler;
+ }
+
public Rect getCurrentOrAnimatingBounds() {
PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getCurrentAnimator();
@@ -422,18 +417,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
/**
- * Sets the preferred animation type for one time.
- * This is typically used to set the animation type to
- * {@link PipAnimationController#ANIM_TYPE_ALPHA}.
- */
- public void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) {
- mOneShotAnimationType = animationType;
- if (animationType == ANIM_TYPE_ALPHA) {
- mLastOneShotAlphaAnimationTime = SystemClock.uptimeMillis();
- }
- }
-
- /**
* Override if the PiP should always use a fade-in animation during PiP entry.
*
* @return true if the mOneShotAnimationType should always be
@@ -733,26 +716,17 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
return;
}
- if (mOneShotAnimationType == ANIM_TYPE_ALPHA
- && SystemClock.uptimeMillis() - mLastOneShotAlphaAnimationTime
- > ONE_SHOT_ALPHA_ANIMATION_TIMEOUT_MS) {
- ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "%s: Alpha animation is expired. Use bounds animation.", TAG);
- mOneShotAnimationType = ANIM_TYPE_BOUNDS;
- }
-
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
// For Shell transition, we will animate the window in PipTransition#startAnimation
// instead of #onTaskAppeared.
return;
}
- if (shouldAlwaysFadeIn()) {
- mOneShotAnimationType = ANIM_TYPE_ALPHA;
- }
-
+ final int animationType = shouldAlwaysFadeIn()
+ ? ANIM_TYPE_ALPHA
+ : mPipAnimationController.takeOneShotEnterAnimationType();
if (mWaitForFixedRotation) {
- onTaskAppearedWithFixedRotation();
+ onTaskAppearedWithFixedRotation(animationType);
return;
}
@@ -763,7 +737,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
- if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
+ if (animationType == ANIM_TYPE_BOUNDS) {
if (!shouldAttachMenuEarly()) {
mPipMenuController.attach(mLeash);
}
@@ -773,16 +747,15 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
sourceHintRect, TRANSITION_DIRECTION_TO_PIP, mEnterAnimationDuration,
null /* updateBoundsCallback */);
mPipTransitionState.setTransitionState(PipTransitionState.ENTERING_PIP);
- } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ } else if (animationType == ANIM_TYPE_ALPHA) {
enterPipWithAlphaAnimation(destinationBounds, mEnterAnimationDuration);
- mOneShotAnimationType = ANIM_TYPE_BOUNDS;
} else {
- throw new RuntimeException("Unrecognized animation type: " + mOneShotAnimationType);
+ throw new RuntimeException("Unrecognized animation type: " + animationType);
}
}
- private void onTaskAppearedWithFixedRotation() {
- if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ private void onTaskAppearedWithFixedRotation(int animationType) {
+ if (animationType == ANIM_TYPE_ALPHA) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
"%s: Defer entering PiP alpha animation, fixed rotation is ongoing", TAG);
// If deferred, hside the surface till fixed rotation is completed.
@@ -791,7 +764,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
tx.setAlpha(mLeash, 0f);
tx.show(mLeash);
tx.apply();
- mOneShotAnimationType = ANIM_TYPE_BOUNDS;
return;
}
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
@@ -1417,7 +1389,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
.scale(tx, mLeash, startBounds, toBounds, degrees)
.round(tx, mLeash, startBounds, toBounds);
if (shouldSyncPipTransactionWithMenu()) {
- mPipMenuController.movePipMenu(mLeash, tx, toBounds);
+ mPipMenuController.movePipMenu(mLeash, tx, toBounds, PipMenuController.ALPHA_NO_CHANGE);
} else {
tx.apply();
}
@@ -1583,7 +1555,8 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
if (!isInPip()) {
return;
}
- mPipMenuController.movePipMenu(null, null, destinationBounds);
+ mPipMenuController.movePipMenu(null, null, destinationBounds,
+ PipMenuController.ALPHA_NO_CHANGE);
mPipMenuController.updateMenuBounds(destinationBounds);
}
@@ -1895,7 +1868,6 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
+ " binder=" + (mToken != null ? mToken.asBinder() : null));
pw.println(innerPrefix + "mLeash=" + mLeash);
pw.println(innerPrefix + "mState=" + mPipTransitionState.getTransitionState());
- pw.println(innerPrefix + "mOneShotAnimationType=" + mOneShotAnimationType);
pw.println(innerPrefix + "mPictureInPictureParams=" + mPictureInPictureParams);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index 4a76a502462c..c5e92294794e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -87,7 +87,7 @@ public class PipTransition extends PipTransitionController {
private final int mEnterExitAnimationDuration;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private final Optional<SplitScreenController> mSplitScreenOptional;
- private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS;
+ private @PipAnimationController.AnimationType int mEnterAnimationType = ANIM_TYPE_BOUNDS;
private Transitions.TransitionFinishCallback mFinishCallback;
private SurfaceControl.Transaction mFinishTransaction;
private final Rect mExitDestinationBounds = new Rect();
@@ -133,20 +133,6 @@ public class PipTransition extends PipTransitionController {
}
@Override
- public void setIsFullAnimation(boolean isFullAnimation) {
- setOneShotAnimationType(isFullAnimation ? ANIM_TYPE_BOUNDS : ANIM_TYPE_ALPHA);
- }
-
- /**
- * Sets the preferred animation type for one time.
- * This is typically used to set the animation type to
- * {@link PipAnimationController#ANIM_TYPE_ALPHA}.
- */
- private void setOneShotAnimationType(@PipAnimationController.AnimationType int animationType) {
- mOneShotAnimationType = animationType;
- }
-
- @Override
public void startExitTransition(int type, WindowContainerTransaction out,
@Nullable Rect destinationBounds) {
if (destinationBounds != null) {
@@ -288,7 +274,10 @@ public class PipTransition extends PipTransitionController {
if (!requestHasPipEnter(request)) {
throw new IllegalStateException("Called PiP augmentRequest when request has no PiP");
}
- if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ mEnterAnimationType = mPipOrganizer.shouldAlwaysFadeIn()
+ ? ANIM_TYPE_ALPHA
+ : mPipAnimationController.takeOneShotEnterAnimationType();
+ if (mEnterAnimationType == ANIM_TYPE_ALPHA) {
mRequestedEnterTransition = transition;
mRequestedEnterTask = request.getTriggerTask().token;
outWCT.setActivityWindowingMode(request.getTriggerTask().token,
@@ -308,7 +297,7 @@ public class PipTransition extends PipTransitionController {
@Override
public boolean handleRotateDisplay(int startRotation, int endRotation,
WindowContainerTransaction wct) {
- if (mRequestedEnterTransition != null && mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ if (mRequestedEnterTransition != null && mEnterAnimationType == ANIM_TYPE_ALPHA) {
// A fade-in was requested but not-yet started. In this case, just recalculate the
// initial state under the new rotation.
int rotationDelta = deltaRotation(startRotation, endRotation);
@@ -760,7 +749,6 @@ public class PipTransition extends PipTransitionController {
if (taskInfo.pictureInPictureParams != null
&& taskInfo.pictureInPictureParams.isAutoEnterEnabled()
&& mPipTransitionState.getInSwipePipToHomeTransition()) {
- mOneShotAnimationType = ANIM_TYPE_BOUNDS;
final SurfaceControl swipePipToHomeOverlay = mPipOrganizer.mSwipePipToHomeOverlay;
startTransaction.setMatrix(leash, Matrix.IDENTITY_MATRIX, new float[9])
.setPosition(leash, destinationBounds.left, destinationBounds.top)
@@ -796,17 +784,16 @@ public class PipTransition extends PipTransitionController {
startTransaction.setMatrix(leash, tmpTransform, new float[9]);
}
- if (mPipOrganizer.shouldAlwaysFadeIn()) {
- mOneShotAnimationType = ANIM_TYPE_ALPHA;
- }
-
- if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ final int enterAnimationType = mEnterAnimationType;
+ if (enterAnimationType == ANIM_TYPE_ALPHA) {
+ // Restore to default type.
+ mEnterAnimationType = ANIM_TYPE_BOUNDS;
startTransaction.setAlpha(leash, 0f);
}
startTransaction.apply();
PipAnimationController.PipTransitionAnimator animator;
- if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
+ if (enterAnimationType == ANIM_TYPE_BOUNDS) {
animator = mPipAnimationController.getAnimator(taskInfo, leash, currentBounds,
currentBounds, destinationBounds, sourceHintRect, TRANSITION_DIRECTION_TO_PIP,
0 /* startingAngle */, rotationDelta);
@@ -829,15 +816,14 @@ public class PipTransition extends PipTransitionController {
animator.setColorContentOverlay(mContext);
}
}
- } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
+ } else if (enterAnimationType == ANIM_TYPE_ALPHA) {
animator = mPipAnimationController.getAnimator(taskInfo, leash, destinationBounds,
0f, 1f);
- mOneShotAnimationType = ANIM_TYPE_BOUNDS;
} else {
- throw new RuntimeException("Unrecognized animation type: "
- + mOneShotAnimationType);
+ throw new RuntimeException("Unrecognized animation type: " + enterAnimationType);
}
animator.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
+ .setPipTransactionHandler(mPipOrganizer.getPipTransactionHandler())
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration);
if (rotationDelta != Surface.ROTATION_0 && mInFixedRotation) {
@@ -897,7 +883,7 @@ public class PipTransition extends PipTransitionController {
.setWindowCrop(leash, endBounds.width(), endBounds.height());
}
}
- mSplitScreenOptional.get().finishEnterSplitScreen(startTransaction);
+ mSplitScreenOptional.get().finishEnterSplitScreen(finishTransaction);
startTransaction.apply();
mPipOrganizer.onExitPipFinished(taskInfo);
@@ -964,7 +950,8 @@ public class PipTransition extends PipTransitionController {
}
private void finishResizeForMenu(Rect destinationBounds) {
- mPipMenuController.movePipMenu(null, null, destinationBounds);
+ mPipMenuController.movePipMenu(null, null, destinationBounds,
+ PipMenuController.ALPHA_NO_CHANGE);
mPipMenuController.updateMenuBounds(destinationBounds);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index f51e247fe112..7979ce7a80c1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -105,15 +105,6 @@ public abstract class PipTransitionController implements Transitions.TransitionH
}
/**
- * Called to inform the transition that the animation should start with the assumption that
- * PiP is not animating from its original bounds, but rather a continuation of another
- * animation. For example, gesture navigation would first fade out the PiP activity, and the
- * transition should be responsible to animate in (such as fade in) the PiP.
- */
- public void setIsFullAnimation(boolean isFullAnimation) {
- }
-
- /**
* Called when the Shell wants to start an exit Pip transition/animation.
*/
public void startExitTransition(int type, WindowContainerTransaction out,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 94e593b106a5..e7a1395f541c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -298,7 +298,8 @@ public class PhonePipMenuController implements PipMenuController {
}
// Sync the menu bounds before showing it in case it is out of sync.
- movePipMenu(null /* pipLeash */, null /* transaction */, stackBounds);
+ movePipMenu(null /* pipLeash */, null /* transaction */, stackBounds,
+ PipMenuController.ALPHA_NO_CHANGE);
updateMenuBounds(stackBounds);
mPipMenuView.showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
@@ -311,7 +312,7 @@ public class PhonePipMenuController implements PipMenuController {
@Override
public void movePipMenu(@Nullable SurfaceControl pipLeash,
@Nullable SurfaceControl.Transaction t,
- Rect destinationBounds) {
+ Rect destinationBounds, float alpha) {
if (destinationBounds.isEmpty()) {
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 463ad77d828f..b0bb14b49db6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -968,12 +968,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mPipBoundsState.setShelfVisibility(visible, shelfHeight);
}
- private void setPinnedStackAnimationType(int animationType) {
- mPipTaskOrganizer.setOneShotAnimationType(animationType);
- mPipTransitionController.setIsFullAnimation(
- animationType == PipAnimationController.ANIM_TYPE_BOUNDS);
- }
-
@VisibleForTesting
void setPinnedStackAnimationListener(PipAnimationListener callback) {
mPinnedStackAnimationRecentsCallback = callback;
@@ -1337,7 +1331,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb
@Override
public void setPipAnimationTypeToAlpha() {
executeRemoteCallWithTaskPermission(mController, "setPipAnimationTypeToAlpha",
- (controller) -> controller.setPinnedStackAnimationType(ANIM_TYPE_ALPHA));
+ (controller) -> controller.mPipAnimationController.setOneShotEnterAnimationType(
+ ANIM_TYPE_ALPHA));
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
index a7171fd5b220..82fe38ccc7b3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipSizeSpecHandler.java
@@ -21,6 +21,7 @@ import static com.android.wm.shell.pip.PipUtils.dpToPx;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
@@ -366,11 +367,8 @@ public class PipSizeSpecHandler {
mContext = context;
mPipDisplayLayoutState = pipDisplayLayoutState;
- boolean enablePipSizeLargeScreen = SystemProperties
- .getBoolean("persist.wm.debug.enable_pip_size_large_screen", true);
-
// choose between two implementations of size spec logic
- if (enablePipSizeLargeScreen) {
+ if (supportsPipSizeLargeScreen()) {
mSizeSpecSourceImpl = new SizeSpecLargeScreenOptimizedImpl();
} else {
mSizeSpecSourceImpl = new SizeSpecDefaultImpl();
@@ -515,6 +513,18 @@ public class PipSizeSpecHandler {
}
}
+ @VisibleForTesting
+ boolean supportsPipSizeLargeScreen() {
+ // TODO(b/271468706): switch Tv to having a dedicated SizeSpecSource once the SizeSpecSource
+ // can be injected
+ return SystemProperties
+ .getBoolean("persist.wm.debug.enable_pip_size_large_screen", true) && !isTv();
+ }
+
+ private boolean isTv() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
/** Dumps internal state. */
public void dump(PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index b18e21c03c63..b2a189b45d6c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -30,6 +30,7 @@ import android.os.Handler;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewRootImpl;
+import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.window.SurfaceSyncGroup;
@@ -202,8 +203,10 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
}
private void addPipMenuViewToSystemWindows(View v, String title) {
- mSystemWindows.addView(v, getPipMenuLayoutParams(mContext, title, 0 /* width */,
- 0 /* height */), 0 /* displayId */, SHELL_ROOT_LAYER_PIP);
+ final WindowManager.LayoutParams layoutParams =
+ getPipMenuLayoutParams(mContext, title, 0 /* width */, 0 /* height */);
+ layoutParams.alpha = 0f;
+ mSystemWindows.addView(v, layoutParams, 0 /* displayId */, SHELL_ROOT_LAYER_PIP);
}
void onPipTransitionFinished(boolean enterTransition) {
@@ -309,9 +312,9 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
@Override
public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction pipTx,
- Rect pipBounds) {
+ Rect pipBounds, float alpha) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
- "%s: movePipMenu: %s", TAG, pipBounds.toShortString());
+ "%s: movePipMenu: %s, alpha %s", TAG, pipBounds.toShortString(), alpha);
if (pipBounds.isEmpty()) {
if (pipTx == null) {
@@ -333,6 +336,11 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
pipTx.setPosition(frontSurface, menuDestBounds.left, menuDestBounds.top);
pipTx.setPosition(backSurface, menuDestBounds.left, menuDestBounds.top);
+ if (alpha != ALPHA_NO_CHANGE) {
+ pipTx.setAlpha(frontSurface, alpha);
+ pipTx.setAlpha(backSurface, alpha);
+ }
+
// Synchronize drawing the content in the front and back surfaces together with the pip
// transaction and the position change for the front and back surfaces
final SurfaceSyncGroup syncGroup = new SurfaceSyncGroup("TvPip");
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
index 0940490e9944..4819f665d6d3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
@@ -98,4 +98,11 @@ public class TvPipTaskOrganizer extends PipTaskOrganizer {
protected boolean shouldAlwaysFadeIn() {
return true;
}
+
+ @Override
+ protected boolean shouldSyncPipTransactionWithMenu() {
+ // We always have a menu visible and want to sync the pip transaction with the menu, even
+ // when the menu alpha is 0 (e.g. when a fade-in animation starts).
+ return true;
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 2cd16be9590c..498f95c8595e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -541,6 +541,34 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
instanceId);
}
+ void startShortcutAndTask(ShortcutInfo shortcutInfo, @Nullable Bundle options1,
+ int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition,
+ float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+ if (options1 == null) options1 = new Bundle();
+ final ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
+ final String packageName1 = shortcutInfo.getPackage();
+ // NOTE: This doesn't correctly pull out packageName2 if taskId is referring to a task in
+ // recents that hasn't launched and is not being organized
+ final String packageName2 = SplitScreenUtils.getPackageName(taskId, mTaskOrganizer);
+ if (samePackage(packageName1, packageName2)) {
+ if (supportMultiInstancesSplit(packageName1)) {
+ activityOptions.setApplyMultipleTaskFlagForShortcut(true);
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
+ } else {
+ if (mRecentTasksOptional.isPresent()) {
+ mRecentTasksOptional.get().removeSplitPair(taskId);
+ }
+ taskId = INVALID_TASK_ID;
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "Cancel entering split as not supporting multi-instances");
+ Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ mStageCoordinator.startShortcutAndTask(shortcutInfo, options1, taskId, options2,
+ splitPosition, splitRatio, remoteTransition, instanceId);
+ }
+
/**
* See {@link #startIntent(PendingIntent, Intent, int, Bundle)}
* @param instanceId to be used by {@link SplitscreenEventLogger}
@@ -580,6 +608,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
Intent fillInIntent = null;
final String packageName1 = SplitScreenUtils.getPackageName(pendingIntent);
+ // NOTE: This doesn't correctly pull out packageName2 if taskId is referring to a task in
+ // recents that hasn't launched and is not being organized
final String packageName2 = SplitScreenUtils.getPackageName(taskId, mTaskOrganizer);
if (samePackage(packageName1, packageName2)) {
if (supportMultiInstancesSplit(packageName1)) {
@@ -587,6 +617,10 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Adding MULTIPLE_TASK");
} else {
+ if (mRecentTasksOptional.isPresent()) {
+ mRecentTasksOptional.get().removeSplitPair(taskId);
+ }
+ taskId = INVALID_TASK_ID;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
"Cancel entering split as not supporting multi-instances");
Toast.makeText(mContext, R.string.dock_multi_instances_not_supported_text,
@@ -1075,9 +1109,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
float splitRatio, @Nullable RemoteTransition remoteTransition,
InstanceId instanceId) {
executeRemoteCallWithTaskPermission(mController, "startShortcutAndTask",
- (controller) -> controller.mStageCoordinator.startShortcutAndTask(shortcutInfo,
- options1, taskId, options2, splitPosition, splitRatio, remoteTransition,
- instanceId));
+ (controller) -> controller.startShortcutAndTask(shortcutInfo, options1, taskId,
+ options2, splitPosition, splitRatio, remoteTransition, instanceId));
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 22800ad8e8a8..2c08cd44becc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -22,6 +22,7 @@ import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
@@ -155,8 +156,10 @@ class SplitScreenTransitions {
}
boolean isRootOrSplitSideRoot = change.getParent() == null
|| topRoot.equals(change.getParent());
- // For enter or exit, we only want to animate the side roots but not the top-root.
- if (!isRootOrSplitSideRoot || topRoot.equals(change.getContainer())) {
+ boolean isDivider = change.getFlags() == FLAG_IS_DIVIDER_BAR;
+ // For enter or exit, we only want to animate side roots and the divider but not the
+ // top-root.
+ if (!isRootOrSplitSideRoot || topRoot.equals(change.getContainer()) || isDivider) {
continue;
}
@@ -165,6 +168,10 @@ class SplitScreenTransitions {
t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top);
t.setWindowCrop(leash, change.getEndAbsBounds().width(),
change.getEndAbsBounds().height());
+ } else if (isDivider) {
+ t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top);
+ t.setLayer(leash, Integer.MAX_VALUE);
+ t.show(leash);
}
boolean isOpening = isOpeningTransition(info);
if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
@@ -282,6 +289,12 @@ class SplitScreenTransitions {
return null;
}
+ void startFullscreenTransition(WindowContainerTransaction wct,
+ @Nullable RemoteTransition handler) {
+ mTransitions.startTransition(TRANSIT_OPEN, wct,
+ new OneShotRemoteHandler(mTransitions.getMainExecutor(), handler));
+ }
+
/** Starts a transition to enter split with a remote transition animator. */
IBinder startEnterTransition(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index f00fdba50748..e4f27240b2cb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -612,6 +612,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio,
@Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (taskId2 == INVALID_TASK_ID) {
+ if (mMainStage.containsTask(taskId1) || mSideStage.containsTask(taskId1)) {
+ prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
+ }
+ if (mRecentTasks.isPresent()) {
+ mRecentTasks.get().removeSplitPair(taskId1);
+ }
+ options1 = options1 != null ? options1 : new Bundle();
+ wct.startTask(taskId1, options1);
+ mSplitTransitions.startFullscreenTransition(wct, remoteTransition);
+ return;
+ }
+
prepareEvictChildTasksIfSplitActive(wct);
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
@@ -627,6 +640,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@SplitPosition int splitPosition, float splitRatio,
@Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (taskId == INVALID_TASK_ID) {
+ options1 = options1 != null ? options1 : new Bundle();
+ wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
+ mSplitTransitions.startFullscreenTransition(wct, remoteTransition);
+ return;
+ }
+
prepareEvictChildTasksIfSplitActive(wct);
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
@@ -641,6 +661,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition,
float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (taskId == INVALID_TASK_ID) {
+ options1 = options1 != null ? options1 : new Bundle();
+ wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
+ mSplitTransitions.startFullscreenTransition(wct, remoteTransition);
+ return;
+ }
+
prepareEvictChildTasksIfSplitActive(wct);
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
@@ -689,6 +716,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@SplitPosition int splitPosition, float splitRatio,
@Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (pendingIntent2 == null) {
+ options1 = options1 != null ? options1 : new Bundle();
+ if (shortcutInfo1 != null) {
+ wct.startShortcut(mContext.getPackageName(), shortcutInfo1, options1);
+ } else {
+ wct.sendPendingIntent(pendingIntent1, fillInIntent1, options1);
+ }
+ mSplitTransitions.startFullscreenTransition(wct, remoteTransition);
+ return;
+ }
+
if (!mMainStage.isActive()) {
// Build a request WCT that will launch both apps such that task 0 is on the main stage
// while task 1 is on the side stage.
@@ -730,6 +768,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (options1 == null) options1 = new Bundle();
if (taskId2 == INVALID_TASK_ID) {
// Launching a solo task.
+ // Exit split first if this task under split roots.
+ if (mMainStage.containsTask(taskId1) || mSideStage.containsTask(taskId1)) {
+ exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
+ }
ActivityOptions activityOptions = ActivityOptions.fromBundle(options1);
activityOptions.update(ActivityOptions.makeRemoteAnimation(adapter));
options1 = activityOptions.toBundle();
@@ -931,10 +973,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSyncQueue.queue(wrapAsSplitRemoteAnimation(adapter), WindowManager.TRANSIT_OPEN, wct);
}
- mSyncQueue.runInSync(t -> {
- setDividerVisibility(true, t);
- });
-
setEnterInstanceId(instanceId);
}
@@ -973,6 +1011,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
@Override
public void onAnimationCancelled(boolean isKeyguardOccluded) {
onRemoteAnimationFinishedOrCancelled(evictWct);
+ setDividerVisibility(true, null);
try {
adapter.getRunner().onAnimationCancelled(isKeyguardOccluded);
} catch (RemoteException e) {
@@ -1013,6 +1052,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
t.setPosition(apps[i].leash, 0, 0);
}
}
+ setDividerVisibility(true, t);
t.apply();
IRemoteAnimationFinishedCallback wrapCallback =
@@ -1503,6 +1543,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
void finishEnterSplitScreen(SurfaceControl.Transaction t) {
mSplitLayout.init();
setDividerVisibility(true, t);
+ // Ensure divider surface are re-parented back into the hierarchy at the end of the
+ // transition. See Transition#buildFinishTransaction for more detail.
+ t.reparent(mSplitLayout.getDividerLeash(), mRootTaskLeash);
+
updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
t.show(mRootTaskLeash);
setSplitsVisible(true);
@@ -1812,6 +1856,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setDividerVisibility(mainStageVisible, null);
}
+ // Set divider visibility flag and try to apply it, the param transaction is used to apply.
+ // See applyDividerVisibility for more detail.
private void setDividerVisibility(boolean visible, @Nullable SurfaceControl.Transaction t) {
if (visible == mDividerVisible) {
return;
@@ -1838,14 +1884,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
- if (t != null) {
- applyDividerVisibility(t);
- } else {
- mSyncQueue.runInSync(transaction -> applyDividerVisibility(transaction));
- }
+ applyDividerVisibility(t);
}
- private void applyDividerVisibility(SurfaceControl.Transaction t) {
+ // Apply divider visibility by current visibility flag. If param transaction is non-null, it
+ // will apply by that transaction, if it is null and visible, it will run a fade-in animation,
+ // otherwise hide immediately.
+ private void applyDividerVisibility(@Nullable SurfaceControl.Transaction t) {
final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
if (dividerLeash == null) {
ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
@@ -1862,7 +1907,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDividerFadeInAnimator.cancel();
}
- if (mDividerVisible) {
+ mSplitLayout.getRefDividerBounds(mTempRect1);
+ if (t != null) {
+ t.setVisibility(dividerLeash, mDividerVisible);
+ t.setLayer(dividerLeash, Integer.MAX_VALUE);
+ t.setPosition(dividerLeash, mTempRect1.left, mTempRect1.top);
+ } else if (mDividerVisible) {
final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
mDividerFadeInAnimator = ValueAnimator.ofFloat(0f, 1f);
mDividerFadeInAnimator.addUpdateListener(animation -> {
@@ -1902,7 +1952,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mDividerFadeInAnimator.start();
} else {
- t.hide(dividerLeash);
+ final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
+ transaction.hide(dividerLeash);
+ transaction.apply();
+ mTransactionPool.release(transaction);
}
}
@@ -2361,9 +2414,14 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
}
if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
- // TODO(shell-transitions): Implement a fallback behavior for now.
- throw new IllegalStateException("Somehow removed the last task in a stage"
- + " outside of a proper transition");
+ Log.e(TAG, "Somehow removed the last task in a stage outside of a proper "
+ + "transition.");
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final int dismissTop = mMainStage.getChildCount() == 0
+ ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
+ prepareExitSplitScreen(dismissTop, wct);
+ mSplitTransitions.startDismissTransition(wct, this, dismissTop,
+ EXIT_REASON_UNKNOWN);
// This can happen in some pathological cases. For example:
// 1. main has 2 tasks [Task A (Single-task), Task B], side has one task [Task C]
// 2. Task B closes itself and starts Task A in LAUNCH_ADJACENT at the same time
@@ -2486,7 +2544,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
finishEnterSplitScreen(finishT);
- addDividerBarToTransition(info, finishT, true /* show */);
+ addDividerBarToTransition(info, true /* show */);
return true;
}
@@ -2629,7 +2687,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (dismissTransition.mDismissTop == STAGE_TYPE_UNDEFINED) {
// TODO: Have a proper remote for this. Until then, though, reset state and use the
// normal animation stuff (which falls back to the normal launcher remote).
- t.hide(mSplitLayout.getDividerLeash());
+ setDividerVisibility(false, t);
mSplitLayout.release(t);
mSplitTransitions.mPendingDismiss = null;
return false;
@@ -2647,7 +2705,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
});
}
- addDividerBarToTransition(info, finishT, false /* show */);
+ addDividerBarToTransition(info, false /* show */);
return true;
}
@@ -2688,11 +2746,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
logExit(EXIT_REASON_UNKNOWN);
}
- private void addDividerBarToTransition(@NonNull TransitionInfo info,
- @NonNull SurfaceControl.Transaction finishT, boolean show) {
+ private void addDividerBarToTransition(@NonNull TransitionInfo info, boolean show) {
final SurfaceControl leash = mSplitLayout.getDividerLeash();
final TransitionInfo.Change barChange = new TransitionInfo.Change(null /* token */, leash);
mSplitLayout.getRefDividerBounds(mTempRect1);
+ barChange.setParent(mRootTaskInfo.token);
barChange.setStartAbsBounds(mTempRect1);
barChange.setEndAbsBounds(mTempRect1);
barChange.setMode(show ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK);
@@ -2700,15 +2758,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Technically this should be order-0, but this is running after layer assignment
// and it's a special case, so just add to end.
info.addChange(barChange);
-
- if (show) {
- finishT.setLayer(leash, Integer.MAX_VALUE);
- finishT.setPosition(leash, mTempRect1.left, mTempRect1.top);
- finishT.show(leash);
- // Ensure divider surface are re-parented back into the hierarchy at the end of the
- // transition. See Transition#buildFinishTransaction for more detail.
- finishT.reparent(leash, mRootTaskLeash);
- }
}
RemoteAnimationTarget getDividerBarLegacyTarget() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index fa4de16b37f1..bdb7d44bad32 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -143,6 +143,10 @@ public class Transitions implements RemoteCallable<Transitions> {
/** Transition type to fullscreen from desktop mode. */
public static final int TRANSIT_EXIT_DESKTOP_MODE = WindowManager.TRANSIT_FIRST_CUSTOM + 12;
+ /** Transition type to animate back to fullscreen when drag to freeform is cancelled. */
+ public static final int TRANSIT_CANCEL_ENTERING_DESKTOP_MODE =
+ WindowManager.TRANSIT_FIRST_CUSTOM + 13;
+
private final WindowOrganizer mOrganizer;
private final Context mContext;
private final ShellExecutor mMainExecutor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 060dc4e05b46..dfde7e6feff5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -110,19 +110,11 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
final WindowContainerTransaction wct = new WindowContainerTransaction();
- final int outsetLeftId = R.dimen.freeform_resize_handle;
- final int outsetTopId = R.dimen.freeform_resize_handle;
- final int outsetRightId = R.dimen.freeform_resize_handle;
- final int outsetBottomId = R.dimen.freeform_resize_handle;
-
mRelayoutParams.reset();
mRelayoutParams.mRunningTaskInfo = taskInfo;
mRelayoutParams.mLayoutResId = R.layout.caption_window_decor;
mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
- if (isDragResizeable) {
- mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId);
- }
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index f99821747fef..5226eeebcaa2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -34,6 +34,7 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.os.Handler;
@@ -197,7 +198,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
@Override
public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
- if (mTransitionPausingRelayout.equals(merged)) {
+ if (merged.equals(mTransitionPausingRelayout)) {
mTransitionPausingRelayout = playing;
}
}
@@ -312,8 +313,12 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
} else if (id == R.id.back_button) {
mTaskOperations.injectBackKey();
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
- moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
- decoration.createHandleMenu();
+ if (!decoration.isHandleMenuActive()) {
+ moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
+ decoration.createHandleMenu();
+ } else {
+ decoration.closeHandleMenu();
+ }
} else if (id == R.id.desktop_button) {
mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
mDesktopTasksController.ifPresent(c -> c.moveToDesktop(mTaskId));
@@ -553,8 +558,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mDragToDesktopAnimationStarted = false;
return;
} else if (mDragToDesktopAnimationStarted) {
- mDesktopTasksController.ifPresent(c ->
- c.moveToFullscreen(relevantDecor.mTaskInfo));
+ Point startPosition = new Point((int) ev.getX(), (int) ev.getY());
+ mDesktopTasksController.ifPresent(
+ c -> c.cancelMoveToFreeform(relevantDecor.mTaskInfo,
+ startPosition));
mDragToDesktopAnimationStarted = false;
return;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index efc90b5e63e1..67e99d73b811 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -42,6 +42,7 @@ import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
+import android.window.SurfaceSyncGroup;
import android.window.WindowContainerTransaction;
import com.android.launcher3.icons.IconProvider;
@@ -208,11 +209,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
final WindowContainerTransaction wct = new WindowContainerTransaction();
- final int outsetLeftId = R.dimen.freeform_resize_handle;
- final int outsetTopId = R.dimen.freeform_resize_handle;
- final int outsetRightId = R.dimen.freeform_resize_handle;
- final int outsetBottomId = R.dimen.freeform_resize_handle;
-
final int windowDecorLayoutId = getDesktopModeWindowDecorLayoutId(
taskInfo.getWindowingMode());
mRelayoutParams.reset();
@@ -220,9 +216,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
mRelayoutParams.mLayoutResId = windowDecorLayoutId;
mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height;
mRelayoutParams.mShadowRadiusId = shadowRadiusID;
- if (isDragResizeable) {
- mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId);
- }
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
// After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
@@ -319,51 +312,50 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
* Create and display handle menu window
*/
void createHandleMenu() {
+ final SurfaceSyncGroup ssg = new SurfaceSyncGroup(TAG);
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
updateHandleMenuPillPositions();
- createAppInfoPill(t);
+ createAppInfoPill(t, ssg);
// Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
if (shouldShowWindowingPill) {
- createWindowingPill(t);
+ createWindowingPill(t, ssg);
}
- createMoreActionsPill(t);
+ createMoreActionsPill(t, ssg);
- mSyncQueue.runInSync(transaction -> {
- transaction.merge(t);
- t.close();
- });
+ ssg.addTransaction(t);
+ ssg.markSyncReady();
setupHandleMenu(shouldShowWindowingPill);
}
- private void createAppInfoPill(SurfaceControl.Transaction t) {
+ private void createAppInfoPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
final int x = (int) mHandleMenuAppInfoPillPosition.x;
final int y = (int) mHandleMenuAppInfoPillPosition.y;
mHandleMenuAppInfoPill = addWindow(
R.layout.desktop_mode_window_decor_handle_menu_app_info_pill,
"Menu's app info pill",
- t, x, y, mMenuWidth, mAppInfoPillHeight, mShadowRadius, mCornerRadius);
+ t, ssg, x, y, mMenuWidth, mAppInfoPillHeight, mShadowRadius, mCornerRadius);
}
- private void createWindowingPill(SurfaceControl.Transaction t) {
+ private void createWindowingPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
final int x = (int) mHandleMenuWindowingPillPosition.x;
final int y = (int) mHandleMenuWindowingPillPosition.y;
mHandleMenuWindowingPill = addWindow(
R.layout.desktop_mode_window_decor_handle_menu_windowing_pill,
"Menu's windowing pill",
- t, x, y, mMenuWidth, mWindowingPillHeight, mShadowRadius, mCornerRadius);
+ t, ssg, x, y, mMenuWidth, mWindowingPillHeight, mShadowRadius, mCornerRadius);
}
- private void createMoreActionsPill(SurfaceControl.Transaction t) {
+ private void createMoreActionsPill(SurfaceControl.Transaction t, SurfaceSyncGroup ssg) {
final int x = (int) mHandleMenuMoreActionsPillPosition.x;
final int y = (int) mHandleMenuMoreActionsPillPosition.y;
mHandleMenuMoreActionsPill = addWindow(
R.layout.desktop_mode_window_decor_handle_menu_more_actions_pill,
"Menu's more actions pill",
- t, x, y, mMenuWidth, mMoreActionsPillHeight, mShadowRadius, mCornerRadius);
+ t, ssg, x, y, mMenuWidth, mMoreActionsPillHeight, mShadowRadius, mCornerRadius);
}
private void setupHandleMenu(boolean windowingPillShown) {
@@ -424,13 +416,12 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
if (mRelayoutParams.mLayoutResId
== R.layout.desktop_mode_app_controls_window_decor) {
// Align the handle menu to the left of the caption.
- menuX = mRelayoutParams.mCaptionX - mResult.mDecorContainerOffsetX + mMarginMenuStart;
- menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + mMarginMenuTop;
+ menuX = mRelayoutParams.mCaptionX + mMarginMenuStart;
+ menuY = mRelayoutParams.mCaptionY + mMarginMenuTop;
} else {
// Position the handle menu at the center of the caption.
- menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - (mMenuWidth / 2)
- - mResult.mDecorContainerOffsetX;
- menuY = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY + mMarginMenuStart;
+ menuX = mRelayoutParams.mCaptionX + (captionWidth / 2) - (mMenuWidth / 2);
+ menuY = mRelayoutParams.mCaptionY + mMarginMenuStart;
}
// App Info pill setup.
@@ -487,26 +478,30 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
if (mHandleMenuAppInfoPill.mWindowViewHost.getView().getWidth() == 0) return;
PointF inputPoint = offsetCaptionLocation(ev);
+
+ // If this is called before open_menu_button's onClick, we don't want to close
+ // the menu since it will just reopen in onClick.
+ final boolean pointInOpenMenuButton = pointInView(
+ mResult.mRootView.findViewById(R.id.open_menu_button),
+ inputPoint.x,
+ inputPoint.y);
+
final boolean pointInAppInfoPill = pointInView(
mHandleMenuAppInfoPill.mWindowViewHost.getView(),
- inputPoint.x - mHandleMenuAppInfoPillPosition.x - mResult.mDecorContainerOffsetX,
- inputPoint.y - mHandleMenuAppInfoPillPosition.y
- - mResult.mDecorContainerOffsetY);
+ inputPoint.x - mHandleMenuAppInfoPillPosition.x,
+ inputPoint.y - mHandleMenuAppInfoPillPosition.y);
boolean pointInWindowingPill = false;
if (mHandleMenuWindowingPill != null) {
pointInWindowingPill = pointInView(mHandleMenuWindowingPill.mWindowViewHost.getView(),
- inputPoint.x - mHandleMenuWindowingPillPosition.x
- - mResult.mDecorContainerOffsetX,
- inputPoint.y - mHandleMenuWindowingPillPosition.y
- - mResult.mDecorContainerOffsetY);
+ inputPoint.x - mHandleMenuWindowingPillPosition.x,
+ inputPoint.y - mHandleMenuWindowingPillPosition.y);
}
final boolean pointInMoreActionsPill = pointInView(
mHandleMenuMoreActionsPill.mWindowViewHost.getView(),
- inputPoint.x - mHandleMenuMoreActionsPillPosition.x
- - mResult.mDecorContainerOffsetX,
- inputPoint.y - mHandleMenuMoreActionsPillPosition.y
- - mResult.mDecorContainerOffsetY);
- if (!pointInAppInfoPill && !pointInWindowingPill && !pointInMoreActionsPill) {
+ inputPoint.x - mHandleMenuMoreActionsPillPosition.x,
+ inputPoint.y - mHandleMenuMoreActionsPillPosition.y);
+ if (!pointInAppInfoPill && !pointInWindowingPill
+ && !pointInMoreActionsPill && !pointInOpenMenuButton) {
closeHandleMenu();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 8cb575cc96e3..d5437c72acac 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -64,8 +64,8 @@ class DragResizeInputListener implements AutoCloseable {
private final TaskResizeInputEventReceiver mInputEventReceiver;
private final DragPositioningCallback mCallback;
- private int mWidth;
- private int mHeight;
+ private int mTaskWidth;
+ private int mTaskHeight;
private int mResizeHandleThickness;
private int mCornerSize;
@@ -128,78 +128,84 @@ class DragResizeInputListener implements AutoCloseable {
* This is also used to update the touch regions of this handler every event dispatched here is
* a potential resize request.
*
- * @param width The width of the drag resize handler in pixels, including resize handle
- * thickness. That is task width + 2 * resize handle thickness.
- * @param height The height of the drag resize handler in pixels, including resize handle
- * thickness. That is task height + 2 * resize handle thickness.
+ * @param taskWidth The width of the task.
+ * @param taskHeight The height of the task.
* @param resizeHandleThickness The thickness of the resize handle in pixels.
* @param cornerSize The size of the resize handle centered in each corner.
* @param touchSlop The distance in pixels user has to drag with touch for it to register as
* a resize action.
*/
- void setGeometry(int width, int height, int resizeHandleThickness, int cornerSize,
+ void setGeometry(int taskWidth, int taskHeight, int resizeHandleThickness, int cornerSize,
int touchSlop) {
- if (mWidth == width && mHeight == height
+ if (mTaskWidth == taskWidth && mTaskHeight == taskHeight
&& mResizeHandleThickness == resizeHandleThickness
&& mCornerSize == cornerSize) {
return;
}
- mWidth = width;
- mHeight = height;
+ mTaskWidth = taskWidth;
+ mTaskHeight = taskHeight;
mResizeHandleThickness = resizeHandleThickness;
mCornerSize = cornerSize;
mDragDetector.setTouchSlop(touchSlop);
Region touchRegion = new Region();
- final Rect topInputBounds = new Rect(0, 0, mWidth, mResizeHandleThickness);
+ final Rect topInputBounds = new Rect(
+ -mResizeHandleThickness,
+ -mResizeHandleThickness,
+ mTaskWidth + mResizeHandleThickness,
+ 0);
touchRegion.union(topInputBounds);
- final Rect leftInputBounds = new Rect(0, mResizeHandleThickness,
- mResizeHandleThickness, mHeight - mResizeHandleThickness);
+ final Rect leftInputBounds = new Rect(
+ -mResizeHandleThickness,
+ 0,
+ 0,
+ mTaskHeight);
touchRegion.union(leftInputBounds);
final Rect rightInputBounds = new Rect(
- mWidth - mResizeHandleThickness, mResizeHandleThickness,
- mWidth, mHeight - mResizeHandleThickness);
+ mTaskWidth,
+ 0,
+ mTaskWidth + mResizeHandleThickness,
+ mTaskHeight);
touchRegion.union(rightInputBounds);
- final Rect bottomInputBounds = new Rect(0, mHeight - mResizeHandleThickness,
- mWidth, mHeight);
+ final Rect bottomInputBounds = new Rect(
+ -mResizeHandleThickness,
+ mTaskHeight,
+ mTaskWidth + mResizeHandleThickness,
+ mTaskHeight + mResizeHandleThickness);
touchRegion.union(bottomInputBounds);
// Set up touch areas in each corner.
int cornerRadius = mCornerSize / 2;
mLeftTopCornerBounds = new Rect(
- mResizeHandleThickness - cornerRadius,
- mResizeHandleThickness - cornerRadius,
- mResizeHandleThickness + cornerRadius,
- mResizeHandleThickness + cornerRadius
- );
+ -cornerRadius,
+ -cornerRadius,
+ cornerRadius,
+ cornerRadius);
touchRegion.union(mLeftTopCornerBounds);
mRightTopCornerBounds = new Rect(
- mWidth - mResizeHandleThickness - cornerRadius,
- mResizeHandleThickness - cornerRadius,
- mWidth - mResizeHandleThickness + cornerRadius,
- mResizeHandleThickness + cornerRadius
- );
+ mTaskWidth - cornerRadius,
+ -cornerRadius,
+ mTaskWidth + cornerRadius,
+ cornerRadius);
touchRegion.union(mRightTopCornerBounds);
mLeftBottomCornerBounds = new Rect(
- mResizeHandleThickness - cornerRadius,
- mHeight - mResizeHandleThickness - cornerRadius,
- mResizeHandleThickness + cornerRadius,
- mHeight - mResizeHandleThickness + cornerRadius
- );
+ -cornerRadius,
+ mTaskHeight - cornerRadius,
+ cornerRadius,
+ mTaskHeight + cornerRadius);
touchRegion.union(mLeftBottomCornerBounds);
mRightBottomCornerBounds = new Rect(
- mWidth - mResizeHandleThickness - cornerRadius,
- mHeight - mResizeHandleThickness - cornerRadius,
- mWidth - mResizeHandleThickness + cornerRadius,
- mHeight - mResizeHandleThickness + cornerRadius
- );
+ mTaskWidth - cornerRadius,
+ mTaskHeight - cornerRadius,
+ mTaskWidth + cornerRadius,
+ mTaskHeight + cornerRadius);
touchRegion.union(mRightBottomCornerBounds);
try {
@@ -358,16 +364,16 @@ class DragResizeInputListener implements AutoCloseable {
@TaskPositioner.CtrlType
private int calculateResizeHandlesCtrlType(float x, float y) {
int ctrlType = 0;
- if (x < mResizeHandleThickness) {
+ if (x < 0) {
ctrlType |= TaskPositioner.CTRL_TYPE_LEFT;
}
- if (x > mWidth - mResizeHandleThickness) {
+ if (x > mTaskWidth) {
ctrlType |= TaskPositioner.CTRL_TYPE_RIGHT;
}
- if (y < mResizeHandleThickness) {
+ if (y < 0) {
ctrlType |= TaskPositioner.CTRL_TYPE_TOP;
}
- if (y > mHeight - mResizeHandleThickness) {
+ if (y > mTaskHeight) {
ctrlType |= TaskPositioner.CTRL_TYPE_BOTTOM;
}
return ctrlType;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 4ebd09fdecee..19a31822aabb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -34,6 +34,7 @@ import android.view.ViewRootImpl;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowlessWindowManager;
+import android.window.SurfaceSyncGroup;
import android.window.TaskConstants;
import android.window.WindowContainerTransaction;
@@ -98,7 +99,6 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
private final Binder mOwner = new Binder();
private final Rect mCaptionInsetsRect = new Rect();
- private final Rect mTaskSurfaceCrop = new Rect();
private final float[] mTmpColor = new float[3];
WindowDecoration(
@@ -193,13 +193,13 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
mDecorWindowContext = mContext.createConfigurationContext(taskConfig);
if (params.mLayoutResId != 0) {
outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext)
- .inflate(params.mLayoutResId, null);
+ .inflate(params.mLayoutResId, null);
}
}
if (outResult.mRootView == null) {
outResult.mRootView = (T) LayoutInflater.from(mDecorWindowContext)
- .inflate(params.mLayoutResId , null);
+ .inflate(params.mLayoutResId, null);
}
// DecorationContainerSurface
@@ -218,21 +218,14 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
final Rect taskBounds = taskConfig.windowConfiguration.getBounds();
final Resources resources = mDecorWindowContext.getResources();
- outResult.mDecorContainerOffsetX = -loadDimensionPixelSize(resources, params.mOutsetLeftId);
- outResult.mDecorContainerOffsetY = -loadDimensionPixelSize(resources, params.mOutsetTopId);
- outResult.mWidth = taskBounds.width()
- + loadDimensionPixelSize(resources, params.mOutsetRightId)
- - outResult.mDecorContainerOffsetX;
- outResult.mHeight = taskBounds.height()
- + loadDimensionPixelSize(resources, params.mOutsetBottomId)
- - outResult.mDecorContainerOffsetY;
- startT.setPosition(
- mDecorationContainerSurface,
- outResult.mDecorContainerOffsetX, outResult.mDecorContainerOffsetY)
- .setWindowCrop(mDecorationContainerSurface,
- outResult.mWidth, outResult.mHeight)
+ outResult.mWidth = taskBounds.width();
+ outResult.mHeight = taskBounds.height();
+ startT.setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight)
.show(mDecorationContainerSurface);
+ // TODO(b/270202228): This surface can be removed. Instead, use
+ // |mDecorationContainerSurface| to set the background now that it no longer has outsets
+ // and its crop is set to the task bounds.
// TaskBackgroundSurface
if (mTaskBackgroundSurface == null) {
final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
@@ -250,8 +243,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f;
mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f;
mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f;
- startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(),
- taskBounds.height())
+ startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height())
.setShadowRadius(mTaskBackgroundSurface, shadowRadius)
.setColor(mTaskBackgroundSurface, mTmpColor)
.show(mTaskBackgroundSurface);
@@ -269,11 +261,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
final int captionWidth = taskBounds.width();
- startT.setPosition(
- mCaptionContainerSurface,
- -outResult.mDecorContainerOffsetX + params.mCaptionX,
- -outResult.mDecorContainerOffsetY + params.mCaptionY)
- .setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight)
+ startT.setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight)
.show(mCaptionContainerSurface);
if (mCaptionWindowManager == null) {
@@ -314,14 +302,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
// Task surface itself
Point taskPosition = mTaskInfo.positionInParent;
- mTaskSurfaceCrop.set(
- outResult.mDecorContainerOffsetX,
- outResult.mDecorContainerOffsetY,
- outResult.mWidth + outResult.mDecorContainerOffsetX,
- outResult.mHeight + outResult.mDecorContainerOffsetY);
startT.show(mTaskSurface);
finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
- .setCrop(mTaskSurface, mTaskSurfaceCrop);
+ .setWindowCrop(mTaskSurface, outResult.mWidth, outResult.mHeight);
}
/**
@@ -400,18 +383,20 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
/**
* Create a window associated with this WindowDecoration.
* Note that subclass must dispose of this when the task is hidden/closed.
- * @param layoutId layout to make the window from
- * @param t the transaction to apply
- * @param xPos x position of new window
- * @param yPos y position of new window
- * @param width width of new window
- * @param height height of new window
+ *
+ * @param layoutId layout to make the window from
+ * @param t the transaction to apply
+ * @param xPos x position of new window
+ * @param yPos y position of new window
+ * @param width width of new window
+ * @param height height of new window
* @param shadowRadius radius of the shadow of the new window
* @param cornerRadius radius of the corners of the new window
* @return the {@link AdditionalWindow} that was added.
*/
AdditionalWindow addWindow(int layoutId, String namePrefix, SurfaceControl.Transaction t,
- int xPos, int yPos, int width, int height, int shadowRadius, int cornerRadius) {
+ SurfaceSyncGroup ssg, int xPos, int yPos, int width, int height, int shadowRadius,
+ int cornerRadius) {
final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
SurfaceControl windowSurfaceControl = builder
.setName(namePrefix + " of Task=" + mTaskInfo.taskId)
@@ -435,49 +420,27 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
windowSurfaceControl, null /* hostInputToken */);
SurfaceControlViewHost viewHost = mSurfaceControlViewHostFactory
.create(mDecorWindowContext, mDisplay, windowManager);
- viewHost.setView(v, lp);
+ ssg.add(viewHost.getSurfacePackage(), () -> viewHost.setView(v, lp));
return new AdditionalWindow(windowSurfaceControl, viewHost,
mSurfaceControlTransactionSupplier);
}
- static class RelayoutParams{
+ static class RelayoutParams {
RunningTaskInfo mRunningTaskInfo;
int mLayoutResId;
int mCaptionHeightId;
int mCaptionWidthId;
int mShadowRadiusId;
- int mOutsetTopId;
- int mOutsetBottomId;
- int mOutsetLeftId;
- int mOutsetRightId;
-
int mCaptionX;
int mCaptionY;
- void setOutsets(int leftId, int topId, int rightId, int bottomId) {
- mOutsetLeftId = leftId;
- mOutsetTopId = topId;
- mOutsetRightId = rightId;
- mOutsetBottomId = bottomId;
- }
-
- void setCaptionPosition(int left, int top) {
- mCaptionX = left;
- mCaptionY = top;
- }
-
void reset() {
mLayoutResId = Resources.ID_NULL;
mCaptionHeightId = Resources.ID_NULL;
mCaptionWidthId = Resources.ID_NULL;
mShadowRadiusId = Resources.ID_NULL;
- mOutsetTopId = Resources.ID_NULL;
- mOutsetBottomId = Resources.ID_NULL;
- mOutsetLeftId = Resources.ID_NULL;
- mOutsetRightId = Resources.ID_NULL;
-
mCaptionX = 0;
mCaptionY = 0;
}
@@ -487,14 +450,10 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
int mWidth;
int mHeight;
T mRootView;
- int mDecorContainerOffsetX;
- int mDecorContainerOffsetY;
void reset() {
mWidth = 0;
mHeight = 0;
- mDecorContainerOffsetX = 0;
- mDecorContainerOffsetY = 0;
mRootView = null;
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index 67ca9a1a17f7..b6d92814ad43 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -29,6 +29,7 @@
<option name="teardown-command" value="settings delete secure show_ime_with_hard_keyboard" />
<option name="teardown-command" value="settings delete system show_touches" />
<option name="teardown-command" value="settings delete system pointer_location" />
+ <option name="teardown-command" value="cmd overlay enable com.android.internal.systemui.navbar.gestural" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index e986ee127708..c416ad011c4e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -137,7 +137,7 @@ fun FlickerTest.splitAppLayerBoundsBecomesVisible(
portraitPosTop: Boolean
) {
assertLayers {
- this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
+ this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component), isOptional = true)
.then()
.isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component))
.then()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
index cbbb29199d75..b8f615a1855f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/activityembedding/ActivityEmbeddingControllerTests.java
@@ -16,6 +16,7 @@
package com.android.wm.shell.activityembedding;
+import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
@@ -82,10 +83,13 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
@Test
public void testStartAnimation_containsNonActivityEmbeddingChange() {
+ final TransitionInfo.Change nonEmbeddedOpen = createChange(0 /* flags */);
+ final TransitionInfo.Change embeddedOpen = createEmbeddedChange(
+ EMBEDDED_LEFT_BOUNDS, EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS);
+ nonEmbeddedOpen.setMode(TRANSIT_OPEN);
final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
- .addChange(createEmbeddedChange(
- EMBEDDED_LEFT_BOUNDS, EMBEDDED_LEFT_BOUNDS, TASK_BOUNDS))
- .addChange(createChange(0 /* flags */))
+ .addChange(embeddedOpen)
+ .addChange(nonEmbeddedOpen)
.build();
// No-op because it contains non-embedded change.
@@ -95,6 +99,22 @@ public class ActivityEmbeddingControllerTests extends ActivityEmbeddingAnimation
verifyNoMoreInteractions(mStartTransaction);
verifyNoMoreInteractions(mFinishTransaction);
verifyNoMoreInteractions(mFinishCallback);
+
+ final TransitionInfo.Change nonEmbeddedClose = createChange(0 /* flags */);
+ nonEmbeddedClose.setMode(TRANSIT_CLOSE);
+ nonEmbeddedClose.setEndAbsBounds(TASK_BOUNDS);
+ final TransitionInfo.Change embeddedOpen2 = createEmbeddedChange(
+ EMBEDDED_RIGHT_BOUNDS, EMBEDDED_RIGHT_BOUNDS, TASK_BOUNDS);
+ final TransitionInfo info2 = new TransitionInfoBuilder(TRANSIT_OPEN, 0)
+ .addChange(embeddedOpen)
+ .addChange(embeddedOpen2)
+ .addChange(nonEmbeddedClose)
+ .build();
+ // Ok to animate because nonEmbeddedClose is occluded by embeddedOpen and embeddedOpen2.
+ assertTrue(mController.startAnimation(mTransition, info2, mStartTransaction,
+ mFinishTransaction, mFinishCallback));
+ // The non-embedded change is dropped to avoid affecting embedded animation.
+ assertFalse(info2.getChanges().contains(nonEmbeddedClose));
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 806bffebd4cb..d95c7a488ea1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -166,6 +166,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
doMotionEvent(MotionEvent.ACTION_MOVE, 0);
mController.setTriggerBack(true);
+ }
+
+ private void releaseBackGesture() {
doMotionEvent(MotionEvent.ACTION_UP, 0);
}
@@ -201,6 +204,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
.setOnBackNavigationDone(new RemoteCallback(result)));
triggerBackGesture();
simulateRemoteAnimationStart(type);
+ mShellExecutor.flushAll();
+ releaseBackGesture();
simulateRemoteAnimationFinished();
mShellExecutor.flushAll();
@@ -252,6 +257,7 @@ public class BackAnimationControllerTest extends ShellTestCase {
createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, false);
triggerBackGesture();
+ releaseBackGesture();
verify(mAppCallback, times(1)).onBackInvoked();
@@ -269,6 +275,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
triggerBackGesture();
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+ releaseBackGesture();
+
// Check that back invocation is dispatched.
verify(mAnimatorCallback).onBackInvoked();
verify(mBackAnimationRunner).onAnimationStart(anyInt(), any(), any(), any(), any());
@@ -308,6 +316,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
triggerBackGesture();
simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+ mShellExecutor.flushAll();
+
+ releaseBackGesture();
// Simulate transition timeout.
mShellExecutor.flushAll();
@@ -369,6 +380,9 @@ public class BackAnimationControllerTest extends ShellTestCase {
simulateRemoteAnimationStart(type);
mShellExecutor.flushAll();
+ releaseBackGesture();
+ mShellExecutor.flushAll();
+
assertTrue("Navigation Done callback not called for "
+ BackNavigationInfo.typeToString(type), result.mBackNavigationDone);
assertTrue("TriggerBack should have been true", result.mTriggerBack);
@@ -395,6 +409,8 @@ public class BackAnimationControllerTest extends ShellTestCase {
.setOnBackNavigationDone(new RemoteCallback(result)));
triggerBackGesture();
mShellExecutor.flushAll();
+ releaseBackGesture();
+ mShellExecutor.flushAll();
assertTrue("Navigation Done callback not called for "
+ BackNavigationInfo.typeToString(type), result.mBackNavigationDone);
@@ -458,9 +474,12 @@ public class BackAnimationControllerTest extends ShellTestCase {
private void doMotionEvent(int actionDown, int coordinate) {
mController.onMotionEvent(
- coordinate, coordinate,
- actionDown,
- BackEvent.EDGE_LEFT);
+ /* touchX */ coordinate,
+ /* touchY */ coordinate,
+ /* velocityX = */ 0,
+ /* velocityY = */ 0,
+ /* keyAction */ actionDown,
+ /* swipeEdge */ BackEvent.EDGE_LEFT);
}
private void simulateRemoteAnimationStart(int type) throws RemoteException {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
index 3608474bd90e..874ef80c29f0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackProgressAnimatorTest.java
@@ -16,8 +16,6 @@
package com.android.wm.shell.back;
-import static android.window.BackEvent.EDGE_LEFT;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -48,12 +46,21 @@ public class BackProgressAnimatorTest {
private CountDownLatch mTargetProgressCalled = new CountDownLatch(1);
private Handler mMainThreadHandler;
+ private BackMotionEvent backMotionEventFrom(float touchX, float progress) {
+ return new BackMotionEvent(
+ /* touchX = */ touchX,
+ /* touchY = */ 0,
+ /* progress = */ progress,
+ /* velocityX = */ 0,
+ /* velocityY = */ 0,
+ /* swipeEdge = */ BackEvent.EDGE_LEFT,
+ /* departingAnimationTarget = */ null);
+ }
+
@Before
public void setUp() throws Exception {
mMainThreadHandler = new Handler(Looper.getMainLooper());
- final BackMotionEvent backEvent = new BackMotionEvent(
- 0, 0,
- 0, EDGE_LEFT, null);
+ final BackMotionEvent backEvent = backMotionEventFrom(0, 0);
mMainThreadHandler.post(
() -> {
mProgressAnimator = new BackProgressAnimator();
@@ -63,9 +70,7 @@ public class BackProgressAnimatorTest {
@Test
public void testBackProgressed() throws InterruptedException {
- final BackMotionEvent backEvent = new BackMotionEvent(
- 100, 0,
- mTargetProgress, EDGE_LEFT, null);
+ final BackMotionEvent backEvent = backMotionEventFrom(100, mTargetProgress);
mMainThreadHandler.post(
() -> mProgressAnimator.onBackProgressed(backEvent));
@@ -78,9 +83,7 @@ public class BackProgressAnimatorTest {
@Test
public void testBackCancelled() throws InterruptedException {
// Give the animator some progress.
- final BackMotionEvent backEvent = new BackMotionEvent(
- 100, 0,
- mTargetProgress, EDGE_LEFT, null);
+ final BackMotionEvent backEvent = backMotionEventFrom(100, mTargetProgress);
mMainThreadHandler.post(
() -> mProgressAnimator.onBackProgressed(backEvent));
mTargetProgressCalled.await(1, TimeUnit.SECONDS);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
index ba9c159bad28..d62e6601723a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
@@ -47,43 +47,45 @@ public class TouchTrackerTest {
public void generatesProgress_leftEdge() {
mTouchTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0, BackEvent.EDGE_LEFT);
float touchX = 10;
+ float velocityX = 0;
+ float velocityY = 0;
// Pre-commit
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f);
// Post-commit
touchX += 100;
mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f);
// Cancel
touchX -= 10;
mTouchTracker.setTriggerBack(false);
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), 0, 0f);
// Cancel more
touchX -= 10;
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), 0, 0f);
// Restart
touchX += 10;
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), 0, 0f);
// Restarted, but pre-commit
float restartX = touchX;
touchX += 10;
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), (touchX - restartX) / FAKE_THRESHOLD, 0f);
// Restarted, post-commit
touchX += 10;
mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f);
}
@@ -91,43 +93,45 @@ public class TouchTrackerTest {
public void generatesProgress_rightEdge() {
mTouchTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0, BackEvent.EDGE_RIGHT);
float touchX = INITIAL_X_RIGHT_EDGE - 10; // Fake right edge
+ float velocityX = 0f;
+ float velocityY = 0f;
// Pre-commit
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f);
// Post-commit
touchX -= 100;
mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f);
// Cancel
touchX += 10;
mTouchTracker.setTriggerBack(false);
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), 0, 0f);
// Cancel more
touchX += 10;
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), 0, 0f);
// Restart
touchX -= 10;
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), 0, 0f);
// Restarted, but pre-commit
float restartX = touchX;
touchX -= 10;
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), (restartX - touchX) / FAKE_THRESHOLD, 0f);
// Restarted, post-commit
touchX -= 10;
mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0);
+ mTouchTracker.update(touchX, 0, velocityX, velocityY);
assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 15bb10ed4f2b..842c699fa42d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -262,7 +262,8 @@ public class PipTaskOrganizerTest extends ShellTestCase {
DisplayLayout layout = new DisplayLayout(info,
mContext.getResources(), true, true);
mPipDisplayLayoutState.setDisplayLayout(layout);
- mPipTaskOrganizer.setOneShotAnimationType(PipAnimationController.ANIM_TYPE_ALPHA);
+ doReturn(PipAnimationController.ANIM_TYPE_ALPHA).when(mMockPipAnimationController)
+ .takeOneShotEnterAnimationType();
mPipTaskOrganizer.setSurfaceControlTransactionFactory(
MockSurfaceControlHelper::createMockSurfaceControlTransaction);
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
index 390c830069eb..425bbf056b85 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipSizeSpecHandlerTest.java
@@ -18,7 +18,6 @@ package com.android.wm.shell.pip.phone;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
@@ -76,7 +75,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
@Mock private Resources mResources;
private PipDisplayLayoutState mPipDisplayLayoutState;
- private PipSizeSpecHandler mPipSizeSpecHandler;
+ private TestPipSizeSpecHandler mPipSizeSpecHandler;
/**
* Sets up static Mockito session for SystemProperties and mocks necessary static methods.
@@ -84,8 +83,6 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
private static void setUpStaticSystemPropertiesSession() {
sStaticMockitoSession = mockitoSession()
.mockStatic(SystemProperties.class).startMocking();
- // make sure the feature flag is on
- when(SystemProperties.getBoolean(anyString(), anyBoolean())).thenReturn(true);
when(SystemProperties.get(anyString(), anyString())).thenAnswer(invocation -> {
String property = invocation.getArgument(0);
if (property.equals("com.android.wm.shell.pip.phone.def_percentage")) {
@@ -161,7 +158,7 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
mPipDisplayLayoutState.setDisplayLayout(displayLayout);
setUpStaticSystemPropertiesSession();
- mPipSizeSpecHandler = new PipSizeSpecHandler(mContext, mPipDisplayLayoutState);
+ mPipSizeSpecHandler = new TestPipSizeSpecHandler(mContext, mPipDisplayLayoutState);
// no overridden min edge size by default
mPipSizeSpecHandler.setOverrideMinSize(null);
@@ -214,4 +211,16 @@ public class PipSizeSpecHandlerTest extends ShellTestCase {
Assert.assertEquals(expectedSize, actualSize);
}
+
+ static class TestPipSizeSpecHandler extends PipSizeSpecHandler {
+
+ TestPipSizeSpecHandler(Context context, PipDisplayLayoutState displayLayoutState) {
+ super(context, displayLayoutState);
+ }
+
+ @Override
+ boolean supportsPipSizeLargeScreen() {
+ return true;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index eda6fdc4dbd4..e6219d1aa792 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -113,6 +113,7 @@ public class StageCoordinatorTests extends ShellTestCase {
private SurfaceSession mSurfaceSession = new SurfaceSession();
private SurfaceControl mRootLeash;
+ private SurfaceControl mDividerLeash;
private ActivityManager.RunningTaskInfo mRootTask;
private StageCoordinator mStageCoordinator;
private Transitions mTransitions;
@@ -129,12 +130,14 @@ public class StageCoordinatorTests extends ShellTestCase {
mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool,
mMainExecutor, Optional.empty()));
+ mDividerLeash = new SurfaceControl.Builder(mSurfaceSession).setName("fakeDivider").build();
when(mSplitLayout.getBounds1()).thenReturn(mBounds1);
when(mSplitLayout.getBounds2()).thenReturn(mBounds2);
when(mSplitLayout.getRootBounds()).thenReturn(mRootBounds);
when(mSplitLayout.isLandscape()).thenReturn(false);
when(mSplitLayout.applyTaskChanges(any(), any(), any())).thenReturn(true);
+ when(mSplitLayout.getDividerLeash()).thenReturn(mDividerLeash);
mRootTask = new TestRunningTaskInfoBuilder().build();
mRootLeash = new SurfaceControl.Builder(mSurfaceSession).setName("test").build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index dfa3c1010eed..38a519af934b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -49,6 +49,7 @@ import android.view.View;
import android.view.ViewRootImpl;
import android.view.WindowInsets;
import android.view.WindowManager.LayoutParams;
+import android.window.SurfaceSyncGroup;
import android.window.TaskConstants;
import android.window.WindowContainerTransaction;
@@ -100,6 +101,8 @@ public class WindowDecorationTests extends ShellTestCase {
private TestView mMockView;
@Mock
private WindowContainerTransaction mMockWindowContainerTransaction;
+ @Mock
+ private SurfaceSyncGroup mMockSurfaceSyncGroup;
private final List<SurfaceControl.Transaction> mMockSurfaceControlTransactions =
new ArrayList<>();
@@ -159,14 +162,8 @@ public class WindowDecorationTests extends ShellTestCase {
.setVisible(false)
.build();
taskInfo.isFocused = false;
- // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is
- // 64px.
+ // Density is 2. Shadow radius is 10px. Caption height is 64px.
taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
- mRelayoutParams.setOutsets(
- R.dimen.test_window_decor_left_outset,
- R.dimen.test_window_decor_top_outset,
- R.dimen.test_window_decor_right_outset,
- R.dimen.test_window_decor_bottom_outset);
final SurfaceControl taskSurface = mock(SurfaceControl.class);
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
@@ -213,14 +210,8 @@ public class WindowDecorationTests extends ShellTestCase {
.setVisible(true)
.build();
taskInfo.isFocused = true;
- // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is
- // 64px.
+ // Density is 2. Shadow radius is 10px. Caption height is 64px.
taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
- mRelayoutParams.setOutsets(
- R.dimen.test_window_decor_left_outset,
- R.dimen.test_window_decor_top_outset,
- R.dimen.test_window_decor_right_outset,
- R.dimen.test_window_decor_bottom_outset);
final SurfaceControl taskSurface = mock(SurfaceControl.class);
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
@@ -229,8 +220,7 @@ public class WindowDecorationTests extends ShellTestCase {
verify(decorContainerSurfaceBuilder).setParent(taskSurface);
verify(decorContainerSurfaceBuilder).setContainerLayer();
verify(mMockSurfaceControlStartT).setTrustedOverlay(decorContainerSurface, true);
- verify(mMockSurfaceControlStartT).setPosition(decorContainerSurface, -20, -40);
- verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 380, 220);
+ verify(mMockSurfaceControlStartT).setWindowCrop(decorContainerSurface, 300, 100);
verify(taskBackgroundSurfaceBuilder).setParent(taskSurface);
verify(taskBackgroundSurfaceBuilder).setEffectLayer();
@@ -244,7 +234,6 @@ public class WindowDecorationTests extends ShellTestCase {
verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
verify(captionContainerSurfaceBuilder).setContainerLayer();
- verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40);
verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
@@ -268,12 +257,12 @@ public class WindowDecorationTests extends ShellTestCase {
verify(mMockSurfaceControlFinishT)
.setPosition(taskSurface, TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y);
verify(mMockSurfaceControlFinishT)
- .setCrop(taskSurface, new Rect(-20, -40, 360, 180));
+ .setWindowCrop(taskSurface, 300, 100);
verify(mMockSurfaceControlStartT)
.show(taskSurface);
- assertEquals(380, mRelayoutResult.mWidth);
- assertEquals(220, mRelayoutResult.mHeight);
+ assertEquals(300, mRelayoutResult.mWidth);
+ assertEquals(100, mRelayoutResult.mHeight);
}
@Test
@@ -309,14 +298,8 @@ public class WindowDecorationTests extends ShellTestCase {
.setVisible(true)
.build();
taskInfo.isFocused = true;
- // Density is 2. Outsets are (20, 40, 60, 80) px. Shadow radius is 10px. Caption height is
- // 64px.
+ // Density is 2. Shadow radius is 10px. Caption height is 64px.
taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
- mRelayoutParams.setOutsets(
- R.dimen.test_window_decor_left_outset,
- R.dimen.test_window_decor_top_outset,
- R.dimen.test_window_decor_right_outset,
- R.dimen.test_window_decor_bottom_outset);
final SurfaceControl taskSurface = mock(SurfaceControl.class);
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
@@ -419,11 +402,6 @@ public class WindowDecorationTests extends ShellTestCase {
.build();
taskInfo.isFocused = true;
taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
- mRelayoutParams.setOutsets(
- R.dimen.test_window_decor_left_outset,
- R.dimen.test_window_decor_top_outset,
- R.dimen.test_window_decor_right_outset,
- R.dimen.test_window_decor_bottom_outset);
final SurfaceControl taskSurface = mock(SurfaceControl.class);
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
windowDecor.relayout(taskInfo);
@@ -438,7 +416,7 @@ public class WindowDecorationTests extends ShellTestCase {
verify(additionalWindowSurfaceBuilder).setContainerLayer();
verify(additionalWindowSurfaceBuilder).setParent(decorContainerSurface);
verify(additionalWindowSurfaceBuilder).build();
- verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 20, 40);
+ verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 0, 0);
final int width = WindowDecoration.loadDimensionPixelSize(
mContext.getResources(), mCaptionMenuWidthId);
final int height = WindowDecoration.loadDimensionPixelSize(
@@ -496,11 +474,6 @@ public class WindowDecorationTests extends ShellTestCase {
.build();
taskInfo.isFocused = true;
taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
- mRelayoutParams.setOutsets(
- R.dimen.test_window_decor_left_outset,
- R.dimen.test_window_decor_top_outset,
- R.dimen.test_window_decor_right_outset,
- R.dimen.test_window_decor_bottom_outset);
final SurfaceControl taskSurface = mock(SurfaceControl.class);
final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
@@ -508,7 +481,6 @@ public class WindowDecorationTests extends ShellTestCase {
verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
verify(captionContainerSurfaceBuilder).setContainerLayer();
- verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40);
// Width of the captionContainerSurface should match the width of TASK_BOUNDS
verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
@@ -584,9 +556,7 @@ public class WindowDecorationTests extends ShellTestCase {
String name = "Test Window";
WindowDecoration.AdditionalWindow additionalWindow =
addWindow(R.layout.desktop_mode_window_decor_handle_menu_app_info_pill, name,
- mMockSurfaceControlAddWindowT,
- x - mRelayoutResult.mDecorContainerOffsetX,
- y - mRelayoutResult.mDecorContainerOffsetY,
+ mMockSurfaceControlAddWindowT, mMockSurfaceSyncGroup, x, y,
width, height, shadowRadius, cornerRadius);
return additionalWindow;
}
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 0b58406516e3..924fbd659824 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -51,6 +51,9 @@
#include "include/gpu/GrDirectContext.h"
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/FunctorDrawable.h"
+#ifdef __ANDROID__
+#include "renderthread/CanvasContext.h"
+#endif
namespace android {
namespace uirenderer {
@@ -489,7 +492,19 @@ struct DrawPoints final : Op {
size_t count;
SkPaint paint;
void draw(SkCanvas* c, const SkMatrix&) const {
- c->drawPoints(mode, count, pod<SkPoint>(this), paint);
+ if (paint.isAntiAlias()) {
+ c->drawPoints(mode, count, pod<SkPoint>(this), paint);
+ } else {
+ c->save();
+#ifdef __ANDROID__
+ auto pixelSnap = renderthread::CanvasContext::getActiveContext()->getPixelSnapMatrix();
+ auto transform = c->getLocalToDevice();
+ transform.postConcat(pixelSnap);
+ c->setMatrix(transform);
+#endif
+ c->drawPoints(mode, count, pod<SkPoint>(this), paint);
+ c->restore();
+ }
}
};
struct DrawVertices final : Op {
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index d08bc5c583c2..8049dc946c9e 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -29,9 +29,10 @@
namespace android {
-AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed)
- : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed) {
- mTimeToShowNextSnapshot = ms2ns(mSkAnimatedImage->currentFrameDuration());
+AnimatedImageDrawable::AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed,
+ SkEncodedImageFormat format)
+ : mSkAnimatedImage(std::move(animatedImage)), mBytesUsed(bytesUsed), mFormat(format) {
+ mTimeToShowNextSnapshot = ms2ns(currentFrameDuration());
setStagingBounds(mSkAnimatedImage->getBounds());
}
@@ -92,7 +93,7 @@ bool AnimatedImageDrawable::isDirty(nsecs_t* outDelay) {
// directly from mSkAnimatedImage.
lock.unlock();
std::unique_lock imageLock{mImageLock};
- *outDelay = ms2ns(mSkAnimatedImage->currentFrameDuration());
+ *outDelay = ms2ns(currentFrameDuration());
return true;
} else {
// The next snapshot has not yet been decoded, but we've already passed
@@ -109,7 +110,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::decodeNextFrame() {
Snapshot snap;
{
std::unique_lock lock{mImageLock};
- snap.mDurationMS = mSkAnimatedImage->decodeNextFrame();
+ snap.mDurationMS = adjustFrameDuration(mSkAnimatedImage->decodeNextFrame());
snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
}
@@ -123,7 +124,7 @@ AnimatedImageDrawable::Snapshot AnimatedImageDrawable::reset() {
std::unique_lock lock{mImageLock};
mSkAnimatedImage->reset();
snap.mPic.reset(mSkAnimatedImage->newPictureSnapshot());
- snap.mDurationMS = mSkAnimatedImage->currentFrameDuration();
+ snap.mDurationMS = currentFrameDuration();
}
return snap;
@@ -274,7 +275,7 @@ int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
{
std::unique_lock lock{mImageLock};
mSkAnimatedImage->reset();
- durationMS = mSkAnimatedImage->currentFrameDuration();
+ durationMS = currentFrameDuration();
}
{
std::unique_lock lock{mSwapLock};
@@ -306,7 +307,7 @@ int AnimatedImageDrawable::drawStaging(SkCanvas* canvas) {
{
std::unique_lock lock{mImageLock};
if (update) {
- durationMS = mSkAnimatedImage->decodeNextFrame();
+ durationMS = adjustFrameDuration(mSkAnimatedImage->decodeNextFrame());
}
canvas->drawDrawable(mSkAnimatedImage.get());
@@ -336,4 +337,20 @@ SkRect AnimatedImageDrawable::onGetBounds() {
return SkRectMakeLargest();
}
+int AnimatedImageDrawable::adjustFrameDuration(int durationMs) {
+ if (durationMs == SkAnimatedImage::kFinished) {
+ return SkAnimatedImage::kFinished;
+ }
+
+ if (mFormat == SkEncodedImageFormat::kGIF) {
+ // Match Chrome & Firefox behavior that gifs with a duration <= 10ms is bumped to 100ms
+ return durationMs <= 10 ? 100 : durationMs;
+ }
+ return durationMs;
+}
+
+int AnimatedImageDrawable::currentFrameDuration() {
+ return adjustFrameDuration(mSkAnimatedImage->currentFrameDuration());
+}
+
} // namespace android
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.h b/libs/hwui/hwui/AnimatedImageDrawable.h
index 8ca3c7e125f1..1e965abc82b5 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.h
+++ b/libs/hwui/hwui/AnimatedImageDrawable.h
@@ -16,16 +16,16 @@
#pragma once
-#include <cutils/compiler.h>
-#include <utils/Macros.h>
-#include <utils/RefBase.h>
-#include <utils/Timers.h>
-
#include <SkAnimatedImage.h>
#include <SkCanvas.h>
#include <SkColorFilter.h>
#include <SkDrawable.h>
+#include <SkEncodedImageFormat.h>
#include <SkPicture.h>
+#include <cutils/compiler.h>
+#include <utils/Macros.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
#include <future>
#include <mutex>
@@ -48,7 +48,8 @@ class AnimatedImageDrawable : public SkDrawable {
public:
// bytesUsed includes the approximate sizes of the SkAnimatedImage and the SkPictures in the
// Snapshots.
- AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed);
+ AnimatedImageDrawable(sk_sp<SkAnimatedImage> animatedImage, size_t bytesUsed,
+ SkEncodedImageFormat format);
/**
* This updates the internal time and returns true if the image needs
@@ -115,6 +116,7 @@ protected:
private:
sk_sp<SkAnimatedImage> mSkAnimatedImage;
const size_t mBytesUsed;
+ const SkEncodedImageFormat mFormat;
bool mRunning = false;
bool mStarting = false;
@@ -157,6 +159,9 @@ private:
Properties mProperties;
std::unique_ptr<OnAnimationEndListener> mEndListener;
+
+ int adjustFrameDuration(int);
+ int currentFrameDuration();
};
} // namespace android
diff --git a/libs/hwui/jni/AnimatedImageDrawable.cpp b/libs/hwui/jni/AnimatedImageDrawable.cpp
index 373e893b9a25..a7f5aa83e624 100644
--- a/libs/hwui/jni/AnimatedImageDrawable.cpp
+++ b/libs/hwui/jni/AnimatedImageDrawable.cpp
@@ -97,7 +97,7 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
bytesUsed += picture->approximateBytesUsed();
}
-
+ SkEncodedImageFormat format = imageDecoder->mCodec->getEncodedFormat();
sk_sp<SkAnimatedImage> animatedImg = SkAnimatedImage::Make(std::move(imageDecoder->mCodec),
info, subset,
std::move(picture));
@@ -108,8 +108,8 @@ static jlong AnimatedImageDrawable_nCreate(JNIEnv* env, jobject /*clazz*/,
bytesUsed += sizeof(animatedImg.get());
- sk_sp<AnimatedImageDrawable> drawable(new AnimatedImageDrawable(std::move(animatedImg),
- bytesUsed));
+ sk_sp<AnimatedImageDrawable> drawable(
+ new AnimatedImageDrawable(std::move(animatedImg), bytesUsed, format));
return reinterpret_cast<jlong>(drawable.release());
}
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index cc987bcd8f0e..c4d3f5cedfa8 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -53,6 +53,8 @@ SkiaOpenGLPipeline::~SkiaOpenGLPipeline() {
}
MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
+ bool wasSurfaceless = mEglManager.isCurrent(EGL_NO_SURFACE);
+
// In case the surface was destroyed (e.g. a previous trimMemory call) we
// need to recreate it here.
if (mHardwareBuffer) {
@@ -65,6 +67,37 @@ MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
if (!mEglManager.makeCurrent(mEglSurface, &error)) {
return MakeCurrentResult::AlreadyCurrent;
}
+
+ // Make sure read/draw buffer state of default framebuffer is GL_BACK. Vendor implementations
+ // disagree on the draw/read buffer state if the default framebuffer transitions from a surface
+ // to EGL_NO_SURFACE and vice-versa. There was a related discussion within Khronos on this topic.
+ // See https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13534.
+ // The discussion was not resolved with a clear consensus
+ if (error == 0 && wasSurfaceless && mEglSurface != EGL_NO_SURFACE) {
+ GLint curReadFB = 0;
+ GLint curDrawFB = 0;
+ glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &curReadFB);
+ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &curDrawFB);
+
+ GLint buffer = GL_NONE;
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glGetIntegerv(GL_DRAW_BUFFER0, &buffer);
+ if (buffer == GL_NONE) {
+ const GLenum drawBuffer = GL_BACK;
+ glDrawBuffers(1, &drawBuffer);
+ }
+
+ glGetIntegerv(GL_READ_BUFFER, &buffer);
+ if (buffer == GL_NONE) {
+ glReadBuffer(GL_BACK);
+ }
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, curReadFB);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, curDrawFB);
+
+ GL_CHECKPOINT(LOW);
+ }
+
return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
}
@@ -104,7 +137,8 @@ IRenderPipeline::DrawResult SkiaOpenGLPipeline::draw(
GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, fboInfo);
- SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
+ SkSurfaceProps props(mColorMode == ColorMode::Default ? 0 : SkSurfaceProps::kAlwaysDither_Flag,
+ kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
sk_sp<SkSurface> surface;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 940d6bfdb83c..f0461bef170c 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -53,6 +53,14 @@ public:
bool isSurfaceReady() override;
bool isContextReady() override;
+ const SkM44& getPixelSnapMatrix() const override {
+ // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
+ // desired fragment
+ static const SkScalar kOffset = 0.063f;
+ static const SkM44 sSnapMatrix = SkM44::Translate(kOffset, kOffset);
+ return sSnapMatrix;
+ }
+
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
protected:
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 1f929685b62c..b020e966e05a 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -28,7 +28,6 @@
#include <SkMultiPictureDocument.h>
#include <SkOverdrawCanvas.h>
#include <SkOverdrawColorFilter.h>
-#include <SkPaintFilterCanvas.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
#include <SkRect.h>
@@ -450,23 +449,6 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
}
}
-class ForceDitherCanvas : public SkPaintFilterCanvas {
-public:
- ForceDitherCanvas(SkCanvas* canvas) : SkPaintFilterCanvas(canvas) {}
-
-protected:
- bool onFilter(SkPaint& paint) const override {
- paint.setDither(true);
- return true;
- }
-
- void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
- // We unroll the drawable using "this" canvas, so that draw calls contained inside will
- // get dithering applied
- drawable->draw(this, matrix);
- }
-};
-
void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
@@ -521,12 +503,6 @@ void SkiaPipeline::renderFrameImpl(const SkRect& clip,
canvas->clear(SK_ColorTRANSPARENT);
}
- std::optional<ForceDitherCanvas> forceDitherCanvas;
- if (shouldForceDither()) {
- forceDitherCanvas.emplace(canvas);
- canvas = &forceDitherCanvas.value();
- }
-
if (1 == nodes.size()) {
if (!nodes[0]->nothingToDraw()) {
RenderNodeDrawable root(nodes[0].get(), canvas);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 0763b06b53ef..befee8989383 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -98,8 +98,6 @@ protected:
bool isCapturingSkp() const { return mCaptureMode != CaptureMode::None; }
- virtual bool shouldForceDither() const { return mColorMode != ColorMode::Default; }
-
private:
void renderFrameImpl(const SkRect& clip,
const std::vector<sp<RenderNode>>& nodes, bool opaque,
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 6f1b99b95bbd..86096d5bd01c 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -203,11 +203,6 @@ sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThr
return nullptr;
}
-bool SkiaVulkanPipeline::shouldForceDither() const {
- if (mVkSurface && mVkSurface->isBeyond8Bit()) return false;
- return SkiaPipeline::shouldForceDither();
-}
-
void SkiaVulkanPipeline::onContextDestroyed() {
if (mVkSurface) {
vulkanManager().destroySurface(mVkSurface);
@@ -215,6 +210,10 @@ void SkiaVulkanPipeline::onContextDestroyed() {
}
}
+const SkM44& SkiaVulkanPipeline::getPixelSnapMatrix() const {
+ return mVkSurface->getPixelSnapMatrix();
+}
+
} /* namespace skiapipeline */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 0713e93bccde..284cde537ec0 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -53,8 +53,8 @@ public:
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
- bool supportsExtendedRangeHdr() const override { return true; }
void setTargetSdrHdrRatio(float ratio) override;
+ const SkM44& getPixelSnapMatrix() const override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
@@ -63,8 +63,6 @@ public:
protected:
void onContextDestroyed() override;
- bool shouldForceDither() const override;
-
private:
renderthread::VulkanManager& vulkanManager();
renderthread::VulkanSurface* mVkSurface = nullptr;
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 23611efccd73..7e9d44fbdbd1 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -117,12 +117,8 @@ void CacheManager::trimMemory(TrimLevel mode) {
// flush and submit all work to the gpu and wait for it to finish
mGrContext->flushAndSubmit(/*syncCpu=*/true);
- if (!Properties::isHighEndGfx && mode >= TrimLevel::MODERATE) {
- mode = TrimLevel::COMPLETE;
- }
-
switch (mode) {
- case TrimLevel::COMPLETE:
+ case TrimLevel::BACKGROUND:
mGrContext->freeGpuResources();
SkGraphics::PurgeAllCaches();
mRenderThread.destroyRenderingContext();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 6b2c99534a4c..f60c1f3c6ad8 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -236,7 +236,6 @@ void CanvasContext::setupPipelineSurface() {
if (mNativeSurface && !mNativeSurface->didSetExtraBuffers()) {
setBufferCount(mNativeSurface->getNativeWindow());
-
}
mFrameNumber = 0;
@@ -301,10 +300,6 @@ void CanvasContext::setOpaque(bool opaque) {
float CanvasContext::setColorMode(ColorMode mode) {
if (mode != mColorMode) {
- const bool isHdr = mode == ColorMode::Hdr || mode == ColorMode::Hdr10;
- if (isHdr && !mRenderPipeline->supportsExtendedRangeHdr()) {
- mode = ColorMode::WideColorGamut;
- }
mColorMode = mode;
mRenderPipeline->setSurfaceColorProperties(mode);
setupPipelineSurface();
@@ -871,6 +866,10 @@ SkISize CanvasContext::getNextFrameSize() const {
return size;
}
+const SkM44& CanvasContext::getPixelSnapMatrix() const {
+ return mRenderPipeline->getPixelSnapMatrix();
+}
+
void CanvasContext::prepareAndDraw(RenderNode* node) {
ATRACE_CALL();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 3f2533959c20..d7215de92375 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -200,6 +200,9 @@ public:
SkISize getNextFrameSize() const;
+ // Returns the matrix to use to nudge non-AA'd points/lines towards the fragment center
+ const SkM44& getPixelSnapMatrix() const;
+
// Called when SurfaceStats are available.
static void onSurfaceStatsAvailable(void* context, int32_t surfaceControlId,
ASurfaceControlStats* stats);
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 4fb114b71bf5..94f35fd9eaf2 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -423,6 +423,7 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE};
EGLConfig config = mEglConfig;
+ bool overrideWindowDataSpaceForHdr = false;
if (colorMode == ColorMode::A8) {
// A8 doesn't use a color space
if (!mEglConfigA8) {
@@ -450,12 +451,13 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
case ColorMode::Default:
attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
break;
- // Extended Range HDR requires being able to manipulate the dataspace in ways
- // we cannot easily do while going through EGLSurface. Given this requires
- // composer3 support, just treat HDR as equivalent to wide color gamut if
- // the GLES path is still being hit
+ // We don't have an EGL colorspace for extended range P3 that's used for HDR
+ // So override it after configuring the EGL context
case ColorMode::Hdr:
case ColorMode::Hdr10:
+ overrideWindowDataSpaceForHdr = true;
+ attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
+ break;
case ColorMode::WideColorGamut: {
skcms_Matrix3x3 colorGamut;
LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
@@ -491,6 +493,16 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
(void*)window, eglErrorString());
}
+ if (overrideWindowDataSpaceForHdr) {
+ // This relies on knowing that EGL will not re-set the dataspace after the call to
+ // eglCreateWindowSurface. Since the handling of the colorspace extension is largely
+ // implemented in libEGL in the platform, we can safely assume this is the case
+ int32_t err = ANativeWindow_setBuffersDataSpace(
+ window,
+ static_cast<android_dataspace>(STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_EXTENDED));
+ LOG_ALWAYS_FATAL_IF(err, "Failed to ANativeWindow_setBuffersDataSpace %d", err);
+ }
+
return surface;
}
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index c68fcdfc76f2..6c2cb9d71c55 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -95,8 +95,8 @@ public:
virtual void setPictureCapturedCallback(
const std::function<void(sk_sp<SkPicture>&&)>& callback) = 0;
- virtual bool supportsExtendedRangeHdr() const { return false; }
virtual void setTargetSdrHdrRatio(float ratio) = 0;
+ virtual const SkM44& getPixelSnapMatrix() const = 0;
virtual ~IRenderPipeline() {}
};
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 718d4a16d5c8..96bfc1061d4e 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -42,6 +42,36 @@ namespace android {
namespace uirenderer {
namespace renderthread {
+static std::array<std::string_view, 18> sEnableExtensions{
+ VK_KHR_BIND_MEMORY_2_EXTENSION_NAME,
+ VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
+ VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
+ VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
+ VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
+ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
+ VK_KHR_MAINTENANCE1_EXTENSION_NAME,
+ VK_KHR_MAINTENANCE2_EXTENSION_NAME,
+ VK_KHR_MAINTENANCE3_EXTENSION_NAME,
+ VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
+ VK_KHR_SURFACE_EXTENSION_NAME,
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+ VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME,
+ VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
+ VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME,
+ VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
+ VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
+ VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
+};
+
+static bool shouldEnableExtension(const std::string_view& extension) {
+ for (const auto& it : sEnableExtensions) {
+ if (it == extension) {
+ return true;
+ }
+ }
+ return false;
+}
+
static void free_features_extensions_structs(const VkPhysicalDeviceFeatures2& features) {
// All Vulkan structs that could be part of the features chain will start with the
// structure type followed by the pNext pointer. We cast to the CommonVulkanHeader
@@ -139,6 +169,11 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
bool hasKHRSurfaceExtension = false;
bool hasKHRAndroidSurfaceExtension = false;
for (const VkExtensionProperties& extension : mInstanceExtensionsOwner) {
+ if (!shouldEnableExtension(extension.extensionName)) {
+ ALOGV("Not enabling instance extension %s", extension.extensionName);
+ continue;
+ }
+ ALOGV("Enabling instance extension %s", extension.extensionName);
mInstanceExtensions.push_back(extension.extensionName);
if (!strcmp(extension.extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
hasKHRSurfaceExtension = true;
@@ -219,6 +254,11 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err);
bool hasKHRSwapchainExtension = false;
for (const VkExtensionProperties& extension : mDeviceExtensionsOwner) {
+ if (!shouldEnableExtension(extension.extensionName)) {
+ ALOGV("Not enabling device extension %s", extension.extensionName);
+ continue;
+ }
+ ALOGV("Enabling device extension %s", extension.extensionName);
mDeviceExtensions.push_back(extension.extensionName);
if (!strcmp(extension.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
hasKHRSwapchainExtension = true;
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index ae4f0572576e..10f456745147 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -63,6 +63,18 @@ static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
return SkMatrix::I();
}
+static SkM44 GetPixelSnapMatrix(SkISize windowSize, int transform) {
+ // Small (~1/16th) nudge to ensure that pixel-aligned non-AA'd draws fill the
+ // desired fragment
+ static const SkScalar kOffset = 0.063f;
+ SkMatrix preRotation = GetPreTransformMatrix(windowSize, transform);
+ SkMatrix invert;
+ LOG_ALWAYS_FATAL_IF(!preRotation.invert(&invert));
+ return SkM44::Translate(kOffset, kOffset)
+ .postConcat(SkM44(preRotation))
+ .preConcat(SkM44(invert));
+}
+
static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
ATRACE_CALL();
@@ -178,6 +190,8 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode
outWindowInfo->preTransform =
GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
+ outWindowInfo->pixelSnapMatrix =
+ GetPixelSnapMatrix(outWindowInfo->size, outWindowInfo->transform);
err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
if (err != 0 || query_value < 0) {
@@ -413,6 +427,7 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
}
mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
+ mWindowInfo.pixelSnapMatrix = GetPixelSnapMatrix(mWindowInfo.size, mWindowInfo.transform);
}
uint32_t idx;
@@ -438,9 +453,15 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
if (bufferInfo->skSurface.get() == nullptr) {
+ SkSurfaceProps surfaceProps;
+ if (mWindowInfo.colorMode != ColorMode::Default) {
+ surfaceProps = SkSurfaceProps(SkSurfaceProps::kAlwaysDither_Flag | surfaceProps.flags(),
+ surfaceProps.pixelGeometry());
+ }
bufferInfo->skSurface = SkSurface::MakeFromAHardwareBuffer(
mGrContext, ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
- kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, nullptr, /*from_window=*/true);
+ kTopLeft_GrSurfaceOrigin, mWindowInfo.colorspace, &surfaceProps,
+ /*from_window=*/true);
if (bufferInfo->skSurface.get() == nullptr) {
ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer,
@@ -530,16 +551,6 @@ void VulkanSurface::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
}
}
-bool VulkanSurface::isBeyond8Bit() const {
- switch (mWindowInfo.bufferFormat) {
- case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
- case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
- return true;
- default:
- return false;
- }
-}
-
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index 3b69b73bcab3..6f5280105e55 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -47,8 +47,7 @@ public:
const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; }
void setColorSpace(sk_sp<SkColorSpace> colorSpace);
-
- bool isBeyond8Bit() const;
+ const SkM44& getPixelSnapMatrix() const { return mWindowInfo.pixelSnapMatrix; }
private:
/*
@@ -107,6 +106,7 @@ private:
SkISize actualSize;
// transform to be applied to the SkSurface to map the coordinates to the provided transform
SkMatrix preTransform;
+ SkM44 pixelSnapMatrix;
};
VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, GrDirectContext* grContext);