summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Shell/Android.bp29
-rw-r--r--libs/WindowManager/Shell/res/color/taskbar_background.xml20
-rw-r--r--libs/WindowManager/Shell/res/color/taskbar_background_dark.xml (renamed from libs/WindowManager/Shell/res/color-night/taskbar_background.xml)0
-rw-r--r--libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-et/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-fr/strings.xml4
-rw-r--r--libs/WindowManager/Shell/res/values-hi/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-in/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-night/colors.xml1
-rw-r--r--libs/WindowManager/Shell/res/values-sr/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-zh-rHK/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values/colors.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java48
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt57
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java35
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java23
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java130
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java20
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java70
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java52
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java60
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java80
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt54
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt4
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt19
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java19
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java7
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt34
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt336
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt77
-rw-r--r--libs/hwui/Tonemapper.cpp1
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp9
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp26
-rw-r--r--libs/hwui/renderthread/VulkanManager.h3
-rw-r--r--libs/hwui/utils/Color.cpp8
45 files changed, 990 insertions, 371 deletions
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 6a79bc1f46c2..54978bd4496d 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -125,34 +125,6 @@ prebuilt_etc {
// End ProtoLog
-gensrcs {
- name: "wm-shell-protos",
-
- tools: [
- "aprotoc",
- "protoc-gen-javastream",
- "soong_zip",
- ],
-
- tool_files: [
- ":libprotobuf-internal-protos",
- ],
-
- cmd: "mkdir -p $(genDir)/$(in) " +
- "&& $(location aprotoc) " +
- " --plugin=$(location protoc-gen-javastream) " +
- " --javastream_out=$(genDir)/$(in) " +
- " -Iexternal/protobuf/src " +
- " -I . " +
- " $(in) " +
- "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
-
- srcs: [
- "proto/**/*.proto",
- ],
- output_extension: "srcjar",
-}
-
java_library {
name: "WindowManager-Shell-proto",
@@ -170,7 +142,6 @@ android_library {
// TODO(b/168581922) protologtool do not support kotlin(*.kt)
":wm_shell-sources-kt",
":wm_shell-aidls",
- ":wm-shell-protos",
],
resource_dirs: [
"res",
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
deleted file mode 100644
index 876ee02a8adf..000000000000
--- a/libs/WindowManager/Shell/res/color/taskbar_background.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2021 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<!-- Should be the same as in packages/apps/Launcher3/res/color-v31/taskbar_background.xml -->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@android:color/system_neutral1_500" android:lStar="98" />
-</selector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color-night/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
index 01df006f1bd2..01df006f1bd2 100644
--- a/libs/WindowManager/Shell/res/color-night/taskbar_background.xml
+++ b/libs/WindowManager/Shell/res/color/taskbar_background_dark.xml
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 8de9d11def2b..c415c868ac04 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -89,7 +89,7 @@
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Važi"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za još informacija."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Želite li da restartujete radi boljeg prikaza?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Možete da restartujete aplikaciju da bi izgledala bolje na ekranu, s tim što možete da izgubite ono što ste uradili ili nesačuvane promene, ako ih ima"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Možete da restartujete aplikaciju da bi izgledala bolje na ekranu, ali možete da izgubite napredak ili nesačuvane promene"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Otkaži"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartuj"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovo"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 90feff32cc2b..fb23d11ef74a 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -89,7 +89,7 @@
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Selge"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Laiendage lisateabe saamiseks."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Kas taaskäivitada parema vaate saavutamiseks?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Saate rakenduse taaskäivitada, et see näeks ekraanikuval parem välja, kuid võite kaotada edenemise või salvestamata muudatused"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Saate rakenduse taaskäivitada, et see näeks ekraanikuval parem välja, kuid võite kaotada edenemise või salvestamata muudatused."</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Tühista"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Taaskäivita"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ära kuva uuesti"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index da5b5c9bfeba..5fb91f7b6948 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -79,7 +79,7 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Bulle"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gérer"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Bulle fermée."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Appuyez pour redémarrer cette appli et avoir une meilleure vue."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Pour un meilleur affichage, appuyez pour redémarrer cette appli."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo ?\nAppuyez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu ?\nAppuyez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo ? Appuyez pour ignorer."</string>
@@ -89,7 +89,7 @@
<string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développez pour obtenir plus d\'informations"</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Redémarrer pour améliorer l\'affichage ?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Vous pouvez redémarrer l\'appli pour en améliorer son aspect sur votre écran, mais vous risquez de perdre votre progression ou les modifications non enregistrées"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Vous pouvez redémarrer l\'appli pour un meilleur rendu sur votre écran, mais il se peut que vous perdiez votre progression ou les modifications non enregistrées"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Annuler"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index fb5040b36a89..b0b0e9c6f5bc 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -89,7 +89,7 @@
<string name="letterbox_education_got_it" msgid="4057634570866051177">"ठीक है"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ज़्यादा जानकारी के लिए बड़ा करें."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"बेहतर व्यू पाने के लिए ऐप्लिकेशन को रीस्टार्ट करना है?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"स्क्रीन पर ऐप्लिकेशन का बेहतर व्यू पाने के लिए उसे रीस्टार्ट करें. हालांकि, आपने जो बदलाव सेव नहीं किए हैं या अब तक जो काम किए हैं उनका डेटा, ऐप्लिकेशन रीस्टार्ट करने पर मिट सकता है"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"स्क्रीन पर ऐप्लिकेशन का बेहतर व्यू पाने के लिए उसे रीस्टार्ट करें. हालांकि, इससे अब तक किया गया काम और सेव न किए गए बदलाव मिट सकते हैं"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"रद्द करें"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"रीस्टार्ट करें"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"फिर से न दिखाएं"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 5747deb405ab..3f6d9c551aa6 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -88,7 +88,7 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Ketuk dua kali di luar aplikasi untuk mengubah posisinya"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Oke"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Luaskan untuk melihat informasi selengkapnya."</string>
- <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Mulai ulang untuk tampilan yang lebih baik?"</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Mulai ulang untuk melihat tampilan yang lebih baik?"</string>
<string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Anda dapat memulai ulang aplikasi agar terlihat lebih baik di layar, tetapi Anda mungkin kehilangan progres atau perubahan yang belum disimpan"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Batal"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Mulai ulang"</string>
diff --git a/libs/WindowManager/Shell/res/values-night/colors.xml b/libs/WindowManager/Shell/res/values-night/colors.xml
index 5c6bb57a7f1c..83c4d93982f4 100644
--- a/libs/WindowManager/Shell/res/values-night/colors.xml
+++ b/libs/WindowManager/Shell/res/values-night/colors.xml
@@ -15,7 +15,6 @@
-->
<resources>
- <color name="docked_divider_handle">#ffffff</color>
<!-- Bubbles -->
<color name="bubbles_icon_tint">@color/GM2_grey_200</color>
<!-- Splash screen-->
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 307efc9d6a2e..85798cf9f784 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -89,7 +89,7 @@
<string name="letterbox_education_got_it" msgid="4057634570866051177">"Важи"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширите за још информација."</string>
<string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"Желите ли да рестартујете ради бољег приказа?"</string>
- <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Можете да рестартујете апликацију да би изгледала боље на екрану, с тим што можете да изгубите оно што сте урадили или несачуване промене, ако их има"</string>
+ <string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"Можете да рестартујете апликацију да би изгледала боље на екрану, али можете да изгубите напредак или несачуване промене"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"Откажи"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартуј"</string>
<string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Не приказуј поново"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 021ec46072f8..3d33ecaccc38 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -88,7 +88,7 @@
<string name="letterbox_education_reposition_text" msgid="4589957299813220661">"在應用程式外輕按兩下即可調整位置"</string>
<string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
<string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳情。"</string>
- <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"要重新啟動改善檢視畫面嗎?"</string>
+ <string name="letterbox_restart_dialog_title" msgid="8543049527871033505">"要重新啟動以改善檢視畫面嗎?"</string>
<string name="letterbox_restart_dialog_description" msgid="6096946078246557848">"你可重新啟動應用程式,讓系統更新檢視畫面;但系統可能不會儲存目前進度及你作出的任何變更"</string>
<string name="letterbox_restart_cancel" msgid="1342209132692537805">"取消"</string>
<string name="letterbox_restart_restart" msgid="8529976234412442973">"重新啟動"</string>
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index c487e4afd678..54a8f33fd679 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -17,8 +17,8 @@
*/
-->
<resources>
- <color name="docked_divider_handle">#000000</color>
- <color name="split_divider_background">@color/taskbar_background</color>
+ <color name="docked_divider_handle">#ffffff</color>
+ <color name="split_divider_background">@color/taskbar_background_dark</color>
<drawable name="forced_resizable_background">#59000000</drawable>
<color name="minimize_dock_shadow_start">#60000000</color>
<color name="minimize_dock_shadow_end">#00000000</color>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
index 18615f7e353a..39f861de1ba0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationAdapter.java
@@ -19,8 +19,6 @@ package com.android.wm.shell.activityembedding;
import static android.graphics.Matrix.MTRANS_X;
import static android.graphics.Matrix.MTRANS_Y;
-import static com.android.wm.shell.activityembedding.ActivityEmbeddingAnimationRunner.shouldUseSnapshotAnimationForClosingChange;
-
import android.annotation.CallSuper;
import android.graphics.Point;
import android.graphics.Rect;
@@ -62,7 +60,7 @@ class ActivityEmbeddingAnimationAdapter {
private final Rect mContentBounds = new Rect();
/** Offset relative to the window parent surface for {@link #mContentBounds}. */
@NonNull
- private final Point mContentRelOffset = new Point();
+ final Point mContentRelOffset = new Point();
@NonNull
final Transformation mTransformation = new Transformation();
@@ -75,8 +73,8 @@ class ActivityEmbeddingAnimationAdapter {
private int mOverrideLayer = LAYER_NO_OVERRIDE;
ActivityEmbeddingAnimationAdapter(@NonNull Animation animation,
- @NonNull TransitionInfo.Change change) {
- this(animation, change, change.getLeash(), change.getEndAbsBounds());
+ @NonNull TransitionInfo.Change change, @NonNull TransitionInfo.Root root) {
+ this(animation, change, change.getLeash(), change.getEndAbsBounds(), root);
}
/**
@@ -87,32 +85,34 @@ class ActivityEmbeddingAnimationAdapter {
*/
ActivityEmbeddingAnimationAdapter(@NonNull Animation animation,
@NonNull TransitionInfo.Change change, @NonNull SurfaceControl leash,
- @NonNull Rect wholeAnimationBounds) {
+ @NonNull Rect wholeAnimationBounds, @NonNull TransitionInfo.Root root) {
mAnimation = animation;
mChange = change;
mLeash = leash;
mWholeAnimationBounds.set(wholeAnimationBounds);
+
+ final Rect startBounds = change.getStartAbsBounds();
+ final Rect endBounds = change.getEndAbsBounds();
+ if (change.getParent() != null) {
+ mContentRelOffset.set(change.getEndRelOffset());
+ } else {
+ // Change leash has been reparented to the root if its parent is not in the transition.
+ // Because it is reparented to the root, the actual offset should be its relative
+ // position to the root instead. See Transitions#setupAnimHierarchy.
+ final Point rootOffset = root.getOffset();
+ mContentRelOffset.set(endBounds.left - rootOffset.x, endBounds.top - rootOffset.y);
+ }
+
if (TransitionUtil.isClosingType(change.getMode())) {
// When it is closing, we want to show the content at the start position in case the
// window is resizing as well. For example, when the activities is changing from split
// to stack, the bottom TaskFragment will be resized to fullscreen when hiding.
- final Rect startBounds = change.getStartAbsBounds();
- final Rect endBounds = change.getEndAbsBounds();
mContentBounds.set(startBounds);
- // Put the transition to the top left for snapshot animation.
- if (shouldUseSnapshotAnimationForClosingChange(mChange)) {
- // TODO(b/275034335): Fix an issue that black hole when closing the right container
- // in bounds change transition.
- mContentRelOffset.set(0, 0);
- } else {
- mContentRelOffset.set(change.getEndRelOffset());
- mContentRelOffset.offset(
+ mContentRelOffset.offset(
startBounds.left - endBounds.left,
startBounds.top - endBounds.top);
- }
} else {
mContentBounds.set(change.getEndAbsBounds());
- mContentRelOffset.set(change.getEndRelOffset());
}
}
@@ -192,8 +192,8 @@ class ActivityEmbeddingAnimationAdapter {
static class SnapshotAdapter extends ActivityEmbeddingAnimationAdapter {
SnapshotAdapter(@NonNull Animation animation, @NonNull TransitionInfo.Change change,
- @NonNull SurfaceControl snapshotLeash) {
- super(animation, change, snapshotLeash, change.getEndAbsBounds());
+ @NonNull SurfaceControl snapshotLeash, @NonNull TransitionInfo.Root root) {
+ super(animation, change, snapshotLeash, change.getEndAbsBounds(), root);
}
@Override
@@ -219,14 +219,14 @@ class ActivityEmbeddingAnimationAdapter {
*/
static class BoundsChangeAdapter extends ActivityEmbeddingAnimationAdapter {
- BoundsChangeAdapter(@NonNull Animation animation, @NonNull TransitionInfo.Change change) {
- super(animation, change);
+ BoundsChangeAdapter(@NonNull Animation animation, @NonNull TransitionInfo.Change change,
+ @NonNull TransitionInfo.Root root) {
+ super(animation, change, root);
}
@Override
void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
- final Point offset = mChange.getEndRelOffset();
- mTransformation.getMatrix().postTranslate(offset.x, offset.y);
+ mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
t.setAlpha(mLeash, mTransformation.getAlpha());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index ab7c7d8ae6c8..59f120deeb94 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -250,7 +250,8 @@ class ActivityEmbeddingAnimationRunner {
SurfaceControl screenshot = getOrCreateScreenshot(change, change, startTransaction);
if (screenshot != null) {
final SnapshotAdapter snapshotAdapter = new SnapshotAdapter(
- createShowSnapshotForClosingAnimation(), change, screenshot);
+ createShowSnapshotForClosingAnimation(), change, screenshot,
+ TransitionUtil.getRootFor(change, info));
if (!isOpening) {
snapshotAdapter.overrideLayer(offsetLayer++);
}
@@ -338,7 +339,7 @@ class ActivityEmbeddingAnimationRunner {
@NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) {
final Animation animation = animationProvider.get(info, change, wholeAnimationBounds);
return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
- wholeAnimationBounds);
+ wholeAnimationBounds, TransitionUtil.getRootFor(change, info));
}
@NonNull
@@ -387,6 +388,12 @@ class ActivityEmbeddingAnimationRunner {
// size.
parentBounds.union(boundsAnimationChange.getStartAbsBounds());
parentBounds.union(boundsAnimationChange.getEndAbsBounds());
+ if (boundsAnimationChange != change) {
+ // Union the change starting bounds in case the activity is resized and reparented
+ // to a TaskFragment. In that case, the TaskFragment may not cover the activity's
+ // starting bounds.
+ parentBounds.union(change.getStartAbsBounds());
+ }
// There are two animations in the array. The first one is for the start leash
// (snapshot), and the second one is for the end leash (TaskFragment).
@@ -401,17 +408,18 @@ class ActivityEmbeddingAnimationRunner {
// boundsAnimationChange.
final SurfaceControl screenshotLeash = getOrCreateScreenshot(change,
boundsAnimationChange, startTransaction);
+ final TransitionInfo.Root root = TransitionUtil.getRootFor(change, info);
if (screenshotLeash != null) {
// Adapter for the starting screenshot leash.
// The screenshot leash will be removed in SnapshotAdapter#onAnimationEnd
adapters.add(new ActivityEmbeddingAnimationAdapter.SnapshotAdapter(
- animations[0], change, screenshotLeash));
+ animations[0], change, screenshotLeash, root));
} else {
Log.e(TAG, "Failed to take screenshot for change=" + change);
}
// Adapter for the ending bounds changed leash.
adapters.add(new ActivityEmbeddingAnimationAdapter.BoundsChangeAdapter(
- animations[1], boundsAnimationChange));
+ animations[1], boundsAnimationChange, root));
}
if (parentBounds.isEmpty()) {
@@ -443,7 +451,8 @@ class ActivityEmbeddingAnimationRunner {
animation = mAnimationSpec.createChangeBoundsOpenAnimation(change, parentBounds);
shouldShouldBackgroundColor = false;
}
- adapters.add(new ActivityEmbeddingAnimationAdapter(animation, change));
+ adapters.add(new ActivityEmbeddingAnimationAdapter(animation, change,
+ TransitionUtil.getRootFor(change, info)));
}
if (shouldShouldBackgroundColor && changeAnimation != null) {
@@ -534,8 +543,19 @@ class ActivityEmbeddingAnimationRunner {
@NonNull SurfaceControl.Transaction startTransaction) {
for (TransitionInfo.Change change : info.getChanges()) {
final SurfaceControl leash = change.getLeash();
- startTransaction.setPosition(leash,
- change.getEndRelOffset().x, change.getEndRelOffset().y);
+ if (change.getParent() != null) {
+ startTransaction.setPosition(leash,
+ change.getEndRelOffset().x, change.getEndRelOffset().y);
+ } else {
+ // Change leash has been reparented to the root if its parent is not in the
+ // transition.
+ // Because it is reparented to the root, the actual offset should be its relative
+ // position to the root instead. See Transitions#setupAnimHierarchy.
+ final TransitionInfo.Root root = TransitionUtil.getRootFor(change, info);
+ startTransaction.setPosition(leash,
+ change.getEndAbsBounds().left - root.getOffset().x,
+ change.getEndAbsBounds().top - root.getOffset().y);
+ }
startTransaction.setWindowCrop(leash,
change.getEndAbsBounds().width(), change.getEndAbsBounds().height());
if (change.getMode() == TRANSIT_CLOSE) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index f3efaade945f..e7ec7aa164e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -3320,7 +3320,9 @@ public class BubbleStackView extends FrameLayout
* @return the normalized x-axis position of the bubble stack rounded to 4 decimal places.
*/
public float getNormalizedXPosition() {
- return new BigDecimal(getStackPosition().x / mPositioner.getAvailableRect().width())
+ int width = mPositioner.getAvailableRect().width();
+ float stackPosition = width > 0 ? getStackPosition().x / width : 0;
+ return new BigDecimal(stackPosition)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
}
@@ -3329,7 +3331,9 @@ public class BubbleStackView extends FrameLayout
* @return the normalized y-axis position of the bubble stack rounded to 4 decimal places.
*/
public float getNormalizedYPosition() {
- return new BigDecimal(getStackPosition().y / mPositioner.getAvailableRect().height())
+ int height = mPositioner.getAvailableRect().height();
+ float stackPosition = height > 0 ? getStackPosition().y / height : 0;
+ return new BigDecimal(stackPosition)
.setScale(4, RoundingMode.CEILING.HALF_UP)
.floatValue();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index fb0a91f17802..0f0d572f8eae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -162,7 +162,7 @@ public class DesktopModeVisualIndicator {
/**
* Release the indicator and its components when it is no longer needed.
*/
- public void releaseVisualIndicator() {
+ public void releaseVisualIndicator(SurfaceControl.Transaction t) {
if (mViewHost == null) return;
if (mViewHost != null) {
mViewHost.release();
@@ -170,13 +170,8 @@ public class DesktopModeVisualIndicator {
}
if (mLeash != null) {
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.remove(mLeash);
mLeash = null;
- mSyncQueue.runInSync(transaction -> {
- transaction.merge(t);
- t.close();
- });
}
}
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 73a0e362a744..b3109388da2c 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
@@ -16,7 +16,6 @@
package com.android.wm.shell.desktopmode
-import android.app.ActivityManager
import android.app.ActivityManager.RunningTaskInfo
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
@@ -78,6 +77,11 @@ class DesktopTasksController(
private val desktopMode: DesktopModeImpl
private var visualIndicator: DesktopModeVisualIndicator? = null
+ private val mOnAnimationFinishedCallback = Consumer<SurfaceControl.Transaction> {
+ t: SurfaceControl.Transaction ->
+ visualIndicator?.releaseVisualIndicator(t)
+ visualIndicator = null
+ }
init {
desktopMode = DesktopModeImpl()
@@ -154,14 +158,14 @@ class DesktopTasksController(
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
enterDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_ENTER_FREEFORM, wct)
+ Transitions.TRANSIT_ENTER_FREEFORM, wct, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
}
}
/** Brings apps to front and sets freeform task bounds */
- fun moveToDesktopWithAnimation(
+ private fun moveToDesktopWithAnimation(
taskInfo: RunningTaskInfo,
freeformBounds: Rect
) {
@@ -172,9 +176,10 @@ class DesktopTasksController(
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
enterDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct)
+ Transitions.TRANSIT_ENTER_DESKTOP_MODE, wct, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
+ releaseVisualIndicator()
}
}
@@ -196,30 +201,32 @@ 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) {
+ fun cancelMoveToFreeform(task: RunningTaskInfo, position: Point) {
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
- enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, startPosition)
+ enterDesktopTaskTransitionHandler.startCancelMoveToDesktopMode(wct, position,
+ mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
+ releaseVisualIndicator()
}
}
- fun moveToFullscreenWithAnimation(task: ActivityManager.RunningTaskInfo) {
+ private fun moveToFullscreenWithAnimation(task: RunningTaskInfo, position: Point) {
val wct = WindowContainerTransaction()
addMoveToFullscreenChanges(wct, task.token)
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
exitDesktopTaskTransitionHandler.startTransition(
- Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct)
+ Transitions.TRANSIT_EXIT_DESKTOP_MODE, wct, position, mOnAnimationFinishedCallback)
} else {
shellTaskOrganizer.applyTransaction(wct)
+ releaseVisualIndicator()
}
}
@@ -330,6 +337,16 @@ class DesktopTasksController(
?.let { homeTask -> wct.reorder(homeTask.getToken(), true /* onTop */) }
}
+ private fun releaseVisualIndicator() {
+ val t = SurfaceControl.Transaction()
+ visualIndicator?.releaseVisualIndicator(t)
+ visualIndicator = null
+ syncQueue.runInSync { transaction ->
+ transaction.merge(t)
+ t.close()
+ }
+ }
+
override fun getContext(): Context {
return context
}
@@ -471,8 +488,7 @@ class DesktopTasksController(
rootTaskDisplayAreaOrganizer)
visualIndicator?.createFullscreenIndicatorWithAnimatedBounds()
} else if (y > statusBarHeight && visualIndicator != null) {
- visualIndicator?.releaseVisualIndicator()
- visualIndicator = null
+ releaseVisualIndicator()
}
}
}
@@ -481,17 +497,15 @@ class DesktopTasksController(
* Perform checks required on drag end. Move to fullscreen if drag ends in status bar area.
*
* @param taskInfo the task being dragged.
- * @param y height of drag, to be checked against status bar height.
+ * @param position position of surface when drag ends
*/
fun onDragPositioningEnd(
taskInfo: RunningTaskInfo,
- y: Float
+ position: Point
) {
val statusBarHeight = getStatusBarHeight(taskInfo)
- if (y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
- visualIndicator?.releaseVisualIndicator()
- visualIndicator = null
- moveToFullscreenWithAnimation(taskInfo)
+ if (position.y <= statusBarHeight && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
+ moveToFullscreenWithAnimation(taskInfo, position)
}
}
@@ -508,6 +522,11 @@ class DesktopTasksController(
taskSurface: SurfaceControl,
y: Float
) {
+ // If the motion event is above the status bar, return since we do not need to show the
+ // visual indicator at this point.
+ if (y < getStatusBarHeight(taskInfo)) {
+ return
+ }
if (visualIndicator == null) {
visualIndicator = DesktopModeVisualIndicator(syncQueue, taskInfo,
displayController, context, taskSurface, shellTaskOrganizer,
@@ -535,11 +554,8 @@ class DesktopTasksController(
freeformBounds: Rect
) {
moveToDesktopWithAnimation(taskInfo, freeformBounds)
- visualIndicator?.releaseVisualIndicator()
- visualIndicator = null
}
-
private fun getStatusBarHeight(taskInfo: RunningTaskInfo): Int {
return displayController.getDisplayLayout(taskInfo.displayId)?.stableInsets()?.top ?: 0
}
@@ -566,7 +582,6 @@ class DesktopTasksController(
desktopModeTaskRepository.removeTaskCorners(taskId)
}
-
/**
* Adds a listener to find out about changes in the visibility of freeform tasks.
*
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 94675788c514..3733b919e366 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
@@ -39,6 +39,7 @@ import com.android.wm.shell.transition.Transitions;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Supplier;
/**
@@ -57,7 +58,8 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
public static final int FREEFORM_ANIMATION_DURATION = 336;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
- private Point mStartPosition;
+ private Point mPosition;
+ private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
public EnterDesktopTaskTransitionHandler(
Transitions transitions) {
@@ -75,9 +77,12 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
* Starts Transition of a given type
* @param type Transition type
* @param wct WindowContainerTransaction for transition
+ * @param onAnimationEndCallback to be called after animation
*/
public void startTransition(@WindowManager.TransitionType int type,
- @NonNull WindowContainerTransaction wct) {
+ @NonNull WindowContainerTransaction wct,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mOnAnimationFinishedCallback = onAnimationEndCallback;
final IBinder token = mTransitions.startTransition(type, wct, this);
mPendingTransitionTokens.add(token);
}
@@ -85,12 +90,15 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
/**
* Starts Transition of type TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
* @param wct WindowContainerTransaction for transition
- * @param startPosition Position of task when transition is triggered
+ * @param position Position of task when transition is triggered
+ * @param onAnimationEndCallback to be called after animation
*/
public void startCancelMoveToDesktopMode(@NonNull WindowContainerTransaction wct,
- Point startPosition) {
- mStartPosition = startPosition;
- startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct);
+ Point position,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mPosition = position;
+ startTransition(Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE, wct,
+ onAnimationEndCallback);
}
@Override
@@ -111,7 +119,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
if (change.getMode() == WindowManager.TRANSIT_CHANGE) {
transitionHandled |= startChangeTransition(
- transition, info.getType(), change, startT, finishCallback);
+ transition, info.getType(), change, startT, finishT, finishCallback);
}
}
@@ -125,6 +133,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
@WindowManager.TransitionType int type,
@NonNull TransitionInfo.Change change,
@NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
if (!mPendingTransitionTokens.contains(transition)) {
return false;
@@ -178,6 +187,9 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
}
@@ -189,7 +201,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
if (type == Transitions.TRANSIT_CANCEL_ENTERING_DESKTOP_MODE
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN
- && mStartPosition != null) {
+ && mPosition != 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();
@@ -204,8 +216,8 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
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))
+ final float scale = (float) animation.getAnimatedValue();
+ t.setPosition(sc, mPosition.x * (1 - scale), mPosition.y * (1 - scale))
.setScale(sc, scale, scale)
.show(sc)
.apply();
@@ -213,6 +225,9 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
index fa3eee257a52..3ad5edf0e604 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandler.java
@@ -42,6 +42,7 @@ import com.android.wm.shell.transition.Transitions;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -54,8 +55,9 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
private final Context mContext;
private final Transitions mTransitions;
private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
-
+ private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
private Supplier<SurfaceControl.Transaction> mTransactionSupplier;
+ private Point mPosition;
public ExitDesktopTaskTransitionHandler(
Transitions transitions,
@@ -76,9 +78,14 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
* Starts Transition of a given type
* @param type Transition type
* @param wct WindowContainerTransaction for transition
+ * @param position Position of the task when transition is started
+ * @param onAnimationEndCallback to be called after animation
*/
public void startTransition(@WindowManager.TransitionType int type,
- @NonNull WindowContainerTransaction wct) {
+ @NonNull WindowContainerTransaction wct, Point position,
+ Consumer<SurfaceControl.Transaction> onAnimationEndCallback) {
+ mPosition = position;
+ mOnAnimationFinishedCallback = onAnimationEndCallback;
final IBinder token = mTransitions.startTransition(type, wct, this);
mPendingTransitionTokens.add(token);
}
@@ -101,7 +108,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
if (change.getMode() == WindowManager.TRANSIT_CHANGE) {
transitionHandled |= startChangeTransition(
- transition, info.getType(), change, startT, finishCallback);
+ transition, info.getType(), change, startT, finishT, finishCallback);
}
}
@@ -116,6 +123,7 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
@WindowManager.TransitionType int type,
@NonNull TransitionInfo.Change change,
@NonNull SurfaceControl.Transaction startT,
+ @NonNull SurfaceControl.Transaction finishT,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
if (!mPendingTransitionTokens.contains(transition)) {
return false;
@@ -138,17 +146,17 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
final ValueAnimator animator = new ValueAnimator();
animator.setFloatValues(0f, 1f);
animator.setDuration(FULLSCREEN_ANIMATION_DURATION);
+ // The start bounds contain the correct dimensions of the task but hold the positioning
+ // before being dragged to the status bar to transition into fullscreen
final Rect startBounds = change.getStartAbsBounds();
final float scaleX = (float) startBounds.width() / screenWidth;
final float scaleY = (float) startBounds.height() / screenHeight;
final SurfaceControl.Transaction t = mTransactionSupplier.get();
- Point startPos = new Point(startBounds.left,
- startBounds.top);
animator.addUpdateListener(animation -> {
float fraction = animation.getAnimatedFraction();
float currentScaleX = scaleX + ((1 - scaleX) * fraction);
float currentScaleY = scaleY + ((1 - scaleY) * fraction);
- t.setPosition(sc, startPos.x * (1 - fraction), startPos.y * (1 - fraction))
+ t.setPosition(sc, mPosition.x * (1 - fraction), mPosition.y * (1 - fraction))
.setScale(sc, currentScaleX, currentScaleY)
.show(sc)
.apply();
@@ -156,6 +164,9 @@ public class ExitDesktopTaskTransitionHandler implements Transitions.TransitionH
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mOnAnimationFinishedCallback != null) {
+ mOnAnimationFinishedCallback.accept(finishT);
+ }
mTransitions.getMainExecutor().execute(
() -> finishCallback.onTransitionFinished(null, null));
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index 28f59b53b5b6..724a130ef52d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -104,7 +104,7 @@ public class DropZoneView extends FrameLayout {
setContainerMargin(0, 0, 0, 0); // make sure it's populated
mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
- mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mMarginColor = getResources().getColor(R.color.taskbar_background_dark);
int c = getResources().getColor(android.R.color.system_accent1_500);
mHighlightColor = Color.argb(HIGHLIGHT_ALPHA, Color.red(c), Color.green(c), Color.blue(c));
mSplashScreenColor = Color.argb(SPLASHSCREEN_ALPHA, 0, 0, 0);
@@ -125,7 +125,7 @@ public class DropZoneView extends FrameLayout {
public void onThemeChange() {
mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(getContext());
- mMarginColor = getResources().getColor(R.color.taskbar_background);
+ mMarginColor = getResources().getColor(R.color.taskbar_background_dark);
mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
if (mMarginPercent > 0) {
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 d3e7f9ca4227..6cedcf534f3b 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
@@ -27,6 +27,7 @@ import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_PIP;
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
import static com.android.wm.shell.pip.PipAnimationController.FRACTION_START;
@@ -524,12 +525,18 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
}
}
- final Rect destinationBounds = getExitDestinationBounds();
+ final Rect displayBounds = mPipBoundsState.getDisplayBounds();
+ final Rect destinationBounds = new Rect(displayBounds);
final int direction = syncWithSplitScreenBounds(destinationBounds, requestEnterSplit)
? TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN
: TRANSITION_DIRECTION_LEAVE_PIP;
+ // For exiting to fullscreen, the windowing mode of task will be changed to fullscreen
+ // until the animation is finished. Otherwise if the activity is resumed and focused at the
+ // begin of aniamtion, the app may do something too early to distub the animation.
+ final boolean toFullscreen = destinationBounds.equals(displayBounds);
- if (Transitions.ENABLE_SHELL_TRANSITIONS && direction == TRANSITION_DIRECTION_LEAVE_PIP) {
+ if (Transitions.SHELL_TRANSITIONS_ROTATION || (Transitions.ENABLE_SHELL_TRANSITIONS
+ && !toFullscreen)) {
// When exit to fullscreen with Shell transition enabled, we update the Task windowing
// mode directly so that it can also trigger display rotation and visibility update in
// the same transition if there will be any.
@@ -605,7 +612,7 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
removePip();
}
- private void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
+ void applyWindowingModeChangeOnExit(WindowContainerTransaction wct, int direction) {
// Reset the final windowing mode.
wct.setWindowingMode(mToken, getOutPipWindowingMode());
// Simply reset the activity mode set prior to the animation running.
@@ -1771,14 +1778,26 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
* @return {@code true} if destinationBounds is altered for split screen
*/
private boolean syncWithSplitScreenBounds(Rect destinationBoundsOut, boolean enterSplit) {
- if (!enterSplit || !mSplitScreenOptional.isPresent()) {
+ if (mSplitScreenOptional.isEmpty()) {
+ return false;
+ }
+ final SplitScreenController split = mSplitScreenOptional.get();
+ final int position = mTaskInfo.lastParentTaskIdBeforePip > 0
+ ? split.getSplitPosition(mTaskInfo.lastParentTaskIdBeforePip)
+ : SPLIT_POSITION_UNDEFINED;
+ if (position == SPLIT_POSITION_UNDEFINED && !enterSplit) {
return false;
}
final Rect topLeft = new Rect();
final Rect bottomRight = new Rect();
- mSplitScreenOptional.get().getStageBounds(topLeft, bottomRight);
- destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight);
- return true;
+ split.getStageBounds(topLeft, bottomRight);
+ if (enterSplit) {
+ destinationBoundsOut.set(isPipToTopLeft() ? topLeft : bottomRight);
+ return true;
+ }
+ // Moving to an existing split task.
+ destinationBoundsOut.set(position == SPLIT_POSITION_TOP_OR_LEFT ? topLeft : bottomRight);
+ return false;
}
/**
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 99cb6f782d01..98db707d1105 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
@@ -508,8 +508,16 @@ public class PipTransition extends PipTransitionController {
currentBounds.offset(-offset.x, -offset.y);
startTransaction.setPosition(pipLeash, currentBounds.left, currentBounds.top);
+ final WindowContainerToken pipTaskToken = pipChange.getContainer();
+ final boolean toFullscreen = pipChange.getEndAbsBounds().equals(
+ mPipBoundsState.getDisplayBounds());
mFinishCallback = (wct, wctCB) -> {
mPipOrganizer.onExitPipFinished(taskInfo);
+ if (!Transitions.SHELL_TRANSITIONS_ROTATION && toFullscreen) {
+ wct = wct != null ? wct : new WindowContainerTransaction();
+ wct.setBounds(pipTaskToken, null);
+ mPipOrganizer.applyWindowingModeChangeOnExit(wct, TRANSITION_DIRECTION_LEAVE_PIP);
+ }
finishCallback.onTransitionFinished(wct, wctCB);
};
mFinishTransaction = finishTransaction;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
index c7e534a2bcf5..2faed3a4b93d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java
@@ -202,6 +202,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
}
void setTaskViewVisible(TaskViewTaskController taskView, boolean visible) {
+ if (mTaskViews.get(taskView) == null) return;
if (mTaskViews.get(taskView).mVisible == visible) return;
if (taskView.getTaskInfo() == null) {
// Nothing to update, task is not yet available
@@ -220,17 +221,19 @@ public class TaskViewTransitions implements Transitions.TransitionHandler {
void updateBoundsState(TaskViewTaskController taskView, Rect boundsOnScreen) {
TaskViewRequestedState state = mTaskViews.get(taskView);
+ if (state == null) return;
state.mBounds.set(boundsOnScreen);
}
void updateVisibilityState(TaskViewTaskController taskView, boolean visible) {
TaskViewRequestedState state = mTaskViews.get(taskView);
+ if (state == null) return;
state.mVisible = visible;
}
void setTaskBounds(TaskViewTaskController taskView, Rect boundsOnScreen) {
TaskViewRequestedState state = mTaskViews.get(taskView);
- if (Objects.equals(boundsOnScreen, state.mBounds)) {
+ if (state == null || Objects.equals(boundsOnScreen, state.mBounds)) {
return;
}
state.mBounds.set(boundsOnScreen);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
index ba364f8a6e59..0cede902f034 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Tracer.java
@@ -18,25 +18,29 @@ package com.android.wm.shell.transition;
import static android.os.Build.IS_USER;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
-import static com.android.wm.shell.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
+import static com.android.wm.shell.nano.WmShellTransitionTraceProto.MAGIC_NUMBER_H;
+import static com.android.wm.shell.nano.WmShellTransitionTraceProto.MAGIC_NUMBER_L;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.SystemClock;
import android.os.Trace;
import android.util.Log;
-import android.util.proto.ProtoOutputStream;
import com.android.internal.util.TraceBuffer;
+import com.android.wm.shell.nano.HandlerMapping;
import com.android.wm.shell.sysui.ShellCommandHandler;
+import com.google.protobuf.nano.MessageNano;
+
import java.io.File;
import java.io.IOException;
+import java.io.OutputStream;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
+import java.util.Queue;
/**
* Helper class to collect and dump transition traces.
@@ -54,8 +58,35 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
private final Object mEnabledLock = new Object();
private boolean mActiveTracingEnabled = false;
- private final TraceBuffer mTraceBuffer = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY,
- (proto) -> handleOnEntryRemovedFromTrace(proto));
+ private final TraceBuffer.ProtoProvider mProtoProvider =
+ new TraceBuffer.ProtoProvider<MessageNano,
+ com.android.wm.shell.nano.WmShellTransitionTraceProto,
+ com.android.wm.shell.nano.Transition>() {
+ @Override
+ public int getItemSize(MessageNano proto) {
+ return proto.getCachedSize();
+ }
+
+ @Override
+ public byte[] getBytes(MessageNano proto) {
+ return MessageNano.toByteArray(proto);
+ }
+
+ @Override
+ public void write(
+ com.android.wm.shell.nano.WmShellTransitionTraceProto encapsulatingProto,
+ Queue<com.android.wm.shell.nano.Transition> buffer, OutputStream os)
+ throws IOException {
+ encapsulatingProto.transitions = buffer.toArray(
+ new com.android.wm.shell.nano.Transition[0]);
+ os.write(getBytes(encapsulatingProto));
+ }
+ };
+ private final TraceBuffer<MessageNano,
+ com.android.wm.shell.nano.WmShellTransitionTraceProto,
+ com.android.wm.shell.nano.Transition> mTraceBuffer
+ = new TraceBuffer(ALWAYS_ON_TRACING_CAPACITY, mProtoProvider,
+ (proto) -> handleOnEntryRemovedFromTrace(proto));
private final Map<Object, Runnable> mRemovedFromTraceCallbacks = new HashMap<>();
private final Map<Transitions.TransitionHandler, Integer> mHandlerIds = new HashMap<>();
@@ -78,26 +109,20 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
mHandlerIds.put(handler, handlerId);
}
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
- outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
- outputStream.write(com.android.wm.shell.Transition.DISPATCH_TIME_NS,
- SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.wm.shell.Transition.HANDLER, handlerId);
-
- outputStream.end(protoToken);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = transitionId;
+ proto.dispatchTimeNs = SystemClock.elapsedRealtimeNanos();
+ proto.handler = handlerId;
final int useCountAfterAdd = mHandlerUseCountInTrace.getOrDefault(handler, 0) + 1;
mHandlerUseCountInTrace.put(handler, useCountAfterAdd);
- mRemovedFromTraceCallbacks.put(outputStream, () -> {
+ mRemovedFromTraceCallbacks.put(proto, () -> {
final int useCountAfterRemove = mHandlerUseCountInTrace.get(handler) - 1;
mHandlerUseCountInTrace.put(handler, useCountAfterRemove);
});
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -107,18 +132,12 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
* @param playingTransitionId The id of the transition we was to merge the transition into.
*/
public void logMergeRequested(int mergeRequestedTransitionId, int playingTransitionId) {
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
- outputStream.write(com.android.wm.shell.Transition.ID, mergeRequestedTransitionId);
- outputStream.write(com.android.wm.shell.Transition.MERGE_REQUEST_TIME_NS,
- SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = mergeRequestedTransitionId;
+ proto.mergeRequestTimeNs = SystemClock.elapsedRealtimeNanos();
+ proto.mergedInto = playingTransitionId;
- outputStream.end(protoToken);
-
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -128,18 +147,12 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
* @param playingTransitionId The id of the transition the transition was merged into.
*/
public void logMerged(int mergedTransitionId, int playingTransitionId) {
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
- outputStream.write(com.android.wm.shell.Transition.ID, mergedTransitionId);
- outputStream.write(
- com.android.wm.shell.Transition.MERGE_TIME_NS, SystemClock.elapsedRealtimeNanos());
- outputStream.write(com.android.wm.shell.Transition.MERGED_INTO, playingTransitionId);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = mergedTransitionId;
+ proto.mergeTimeNs = SystemClock.elapsedRealtimeNanos();
+ proto.mergedInto = playingTransitionId;
- outputStream.end(protoToken);
-
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -148,17 +161,11 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
* @param transitionId The id of the transition that was aborted.
*/
public void logAborted(int transitionId) {
- ProtoOutputStream outputStream = new ProtoOutputStream();
- final long protoToken =
- outputStream.start(com.android.wm.shell.WmShellTransitionTraceProto.TRANSITIONS);
-
- outputStream.write(com.android.wm.shell.Transition.ID, transitionId);
- outputStream.write(
- com.android.wm.shell.Transition.ABORT_TIME_NS, SystemClock.elapsedRealtimeNanos());
-
- outputStream.end(protoToken);
+ com.android.wm.shell.nano.Transition proto = new com.android.wm.shell.nano.Transition();
+ proto.id = transitionId;
+ proto.abortTimeNs = SystemClock.elapsedRealtimeNanos();
- mTraceBuffer.add(outputStream);
+ mTraceBuffer.add(proto);
}
/**
@@ -230,8 +237,9 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
private void writeTraceToFileLocked(@Nullable PrintWriter pw, File file) {
Trace.beginSection("TransitionTracer#writeTraceToFileLocked");
try {
- ProtoOutputStream proto = new ProtoOutputStream();
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ com.android.wm.shell.nano.WmShellTransitionTraceProto proto =
+ new com.android.wm.shell.nano.WmShellTransitionTraceProto();
+ proto.magicNumber = MAGIC_NUMBER_VALUE;
writeHandlerMappingToProto(proto);
int pid = android.os.Process.myPid();
LogAndPrintln.i(pw, "Writing file to " + file.getAbsolutePath()
@@ -243,19 +251,21 @@ public class Tracer implements ShellCommandHandler.ShellCommandActionHandler {
Trace.endSection();
}
- private void writeHandlerMappingToProto(ProtoOutputStream outputStream) {
+ private void writeHandlerMappingToProto(
+ com.android.wm.shell.nano.WmShellTransitionTraceProto proto) {
+ ArrayList<com.android.wm.shell.nano.HandlerMapping> handlerMappings = new ArrayList<>();
for (Transitions.TransitionHandler handler : mHandlerUseCountInTrace.keySet()) {
final int count = mHandlerUseCountInTrace.get(handler);
if (count > 0) {
- final long protoToken = outputStream.start(
- com.android.wm.shell.WmShellTransitionTraceProto.HANDLER_MAPPINGS);
- outputStream.write(com.android.wm.shell.HandlerMapping.ID,
- mHandlerIds.get(handler));
- outputStream.write(com.android.wm.shell.HandlerMapping.NAME,
- handler.getClass().getName());
- outputStream.end(protoToken);
+ com.android.wm.shell.nano.HandlerMapping mapping =
+ new com.android.wm.shell.nano.HandlerMapping();
+ mapping.id = mHandlerIds.get(handler);
+ mapping.name = handler.getClass().getName();
+ handlerMappings.add(mapping);
}
}
+ proto.handlerMappings = handlerMappings.toArray(
+ new com.android.wm.shell.nano.HandlerMapping[0]);
}
private void handleOnEntryRemovedFromTrace(Object proto) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
index c5cd2d91eb39..67a26fc97150 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java
@@ -306,4 +306,14 @@ public class TransitionUtil {
if (rootIdx >= 0) return rootIdx;
return 0;
}
+
+ /**
+ * Gets the {@link TransitionInfo.Root} for the given {@link TransitionInfo.Change}.
+ * @see #rootIndexFor(TransitionInfo.Change, TransitionInfo)
+ */
+ @NonNull
+ public static TransitionInfo.Root getRootFor(@NonNull TransitionInfo.Change change,
+ @NonNull TransitionInfo info) {
+ return info.getRoot(rootIndexFor(change, info));
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 212ad9ebceaf..2bb3cceb257f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -22,6 +22,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.util.SparseArray;
@@ -185,18 +186,29 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
mSyncQueue);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
- final FluidResizeTaskPositioner taskPositioner =
- new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration, mDisplayController);
+ final DragPositioningCallback dragPositioningCallback = createDragPositioningCallback(
+ windowDecoration, taskInfo);
final CaptionTouchEventListener touchEventListener =
- new CaptionTouchEventListener(taskInfo, taskPositioner);
+ new CaptionTouchEventListener(taskInfo, dragPositioningCallback);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
- windowDecoration.setDragPositioningCallback(taskPositioner);
+ windowDecoration.setDragPositioningCallback(dragPositioningCallback);
windowDecoration.setDragDetector(touchEventListener.mDragDetector);
windowDecoration.relayout(taskInfo, startT, finishT,
false /* applyStartTransactionOnDraw */);
setupCaptionColor(taskInfo, windowDecoration);
}
+ private FluidResizeTaskPositioner createDragPositioningCallback(
+ CaptionWindowDecoration windowDecoration, RunningTaskInfo taskInfo) {
+ final int screenWidth = mDisplayController.getDisplayLayout(taskInfo.displayId).width();
+ final int statusBarHeight = mDisplayController.getDisplayLayout(taskInfo.displayId)
+ .stableInsets().top;
+ final Rect disallowedAreaForEndBounds = new Rect(0, 0, screenWidth,
+ statusBarHeight);
+ return new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
+ mDisplayController, disallowedAreaForEndBounds);
+ }
+
private class CaptionTouchEventListener implements
View.OnClickListener, View.OnTouchListener, DragDetector.MotionEventHandler {
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 12edc3548642..0b821844e46c 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
@@ -33,7 +33,6 @@ import android.app.ActivityManager;
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.graphics.Region;
@@ -41,7 +40,6 @@ import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.InputChannel;
@@ -63,6 +61,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopModeStatus;
@@ -111,7 +110,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
private ValueAnimator mDragToDesktopValueAnimator;
private final Rect mDragToDesktopAnimationStartBounds = new Rect();
private boolean mDragToDesktopAnimationStarted;
- private float mCaptionDragStartX;
public DesktopModeWindowDecorViewModel(
Context context,
@@ -393,10 +391,16 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
final int dragPointerIdx = e.findPointerIndex(mDragPointerId);
+ // Position of the task is calculated by subtracting the raw location of the
+ // motion event (the location of the motion relative to the display) by the
+ // location of the motion event relative to the task's bounds
+ final Point position = new Point(
+ (int) (e.getRawX(dragPointerIdx) - e.getX(dragPointerIdx)),
+ (int) (e.getRawY(dragPointerIdx) - e.getY(dragPointerIdx)));
mDragPositioningCallback.onDragPositioningEnd(
e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
mDesktopTasksController.ifPresent(c -> c.onDragPositioningEnd(taskInfo,
- e.getRawY(dragPointerIdx)));
+ position));
final boolean wasDragging = mIsDragging;
mIsDragging = false;
return wasDragging;
@@ -525,7 +529,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
DesktopModeWindowDecoration relevantDecor) {
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
- mCaptionDragStartX = ev.getX();
// Begin drag through status bar if applicable.
if (relevantDecor != null) {
mDragToDesktopAnimationStartBounds.set(
@@ -562,10 +565,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mDragToDesktopAnimationStarted = false;
return;
} else if (mDragToDesktopAnimationStarted) {
- Point startPosition = new Point((int) ev.getX(), (int) ev.getY());
+ Point position = new Point((int) ev.getX(), (int) ev.getY());
mDesktopTasksController.ifPresent(
c -> c.cancelMoveToFreeform(relevantDecor.mTaskInfo,
- startPosition));
+ position));
mDragToDesktopAnimationStarted = false;
return;
}
@@ -580,8 +583,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
}
if (mTransitionDragActive) {
mDesktopTasksController.ifPresent(
- c -> c.onDragPositioningMoveThroughStatusBar(relevantDecor.mTaskInfo,
- relevantDecor.mTaskSurface, ev.getY()));
+ c -> c.onDragPositioningMoveThroughStatusBar(
+ relevantDecor.mTaskInfo,
+ relevantDecor.mTaskSurface, ev.getY()));
final int statusBarHeight = getStatusBarHeight(
relevantDecor.mTaskInfo.displayId);
if (ev.getY() > statusBarHeight) {
@@ -616,11 +620,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
* Gets bounds of a scaled window centered relative to the screen bounds
* @param scale the amount to scale to relative to the Screen Bounds
*/
- private Rect calculateFreeformBounds(float scale) {
- final Resources resources = mContext.getResources();
- final DisplayMetrics metrics = resources.getDisplayMetrics();
- final int screenWidth = metrics.widthPixels;
- final int screenHeight = metrics.heightPixels;
+ private Rect calculateFreeformBounds(int displayId, float scale) {
+ final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId);
+ final int screenWidth = displayLayout.width();
+ final int screenHeight = displayLayout.height();
final float adjustmentPercentage = (1f - scale) / 2;
final Rect endBounds = new Rect((int) (screenWidth * adjustmentPercentage),
@@ -649,7 +652,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
animator.setDuration(FREEFORM_ANIMATION_DURATION);
final SurfaceControl sc = relevantDecor.mTaskSurface;
- final Rect endBounds = calculateFreeformBounds(DRAG_FREEFORM_SCALE);
+ final Rect endBounds = calculateFreeformBounds(ev.getDisplayId(), DRAG_FREEFORM_SCALE);
final Transaction t = mTransactionFactory.get();
final float diffX = endBounds.centerX() - ev.getX();
final float diffY = endBounds.top - ev.getY();
@@ -666,9 +669,10 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mDesktopTasksController.ifPresent(c ->
- c.onDragPositioningEndThroughStatusBar(relevantDecor.mTaskInfo,
- calculateFreeformBounds(FINAL_FREEFORM_SCALE)));
+ mDesktopTasksController.ifPresent(
+ c -> c.onDragPositioningEndThroughStatusBar(
+ relevantDecor.mTaskInfo,
+ calculateFreeformBounds(ev.getDisplayId(), FINAL_FREEFORM_SCALE)));
}
});
animator.start();
@@ -784,17 +788,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
mSyncQueue);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
- final DragPositioningCallback dragPositioningCallback;
- if (!DesktopModeStatus.isVeiledResizeEnabled()) {
- dragPositioningCallback =
- new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
- mDisplayController, mDragStartListener);
- } else {
- windowDecoration.createResizeVeil();
- dragPositioningCallback =
- new VeiledResizeTaskPositioner(mTaskOrganizer, windowDecoration,
- mDisplayController, mDragStartListener);
- }
+ final DragPositioningCallback dragPositioningCallback = createDragPositioningCallback(
+ windowDecoration, taskInfo);
final DesktopModeTouchEventListener touchEventListener =
new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback);
@@ -806,7 +801,22 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
false /* applyStartTransactionOnDraw */);
incrementEventReceiverTasks(taskInfo.displayId);
}
-
+ private DragPositioningCallback createDragPositioningCallback(
+ @NonNull DesktopModeWindowDecoration windowDecoration,
+ @NonNull RunningTaskInfo taskInfo) {
+ final int screenWidth = mDisplayController.getDisplayLayout(taskInfo.displayId).width();
+ final Rect disallowedAreaForEndBounds = new Rect(0, 0, screenWidth,
+ getStatusBarHeight(taskInfo.displayId));
+ if (!DesktopModeStatus.isVeiledResizeEnabled()) {
+ return new FluidResizeTaskPositioner(mTaskOrganizer, windowDecoration,
+ mDisplayController, disallowedAreaForEndBounds, mDragStartListener,
+ mTransactionFactory);
+ } else {
+ windowDecoration.createResizeVeil();
+ return new VeiledResizeTaskPositioner(mTaskOrganizer, windowDecoration,
+ mDisplayController, disallowedAreaForEndBounds, mDragStartListener);
+ }
+ }
private class DragStartListenerImpl
implements DragPositioningCallbackUtility.DragStartListener {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
index ae93a43f78e9..09e29bcbcf9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtility.java
@@ -25,6 +25,7 @@ import static com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.DisplayMetrics;
+import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
@@ -51,9 +52,9 @@ public class DragPositioningCallbackUtility {
}
/**
- * Based on type of drag and delta provided, calculate the new bounds to display for this task.
+ * Based on type of resize and delta provided, calculate the new bounds to display for this
+ * task.
* @param ctrlType type of drag being performed
- * @param hasMoved whether the current drag has moved on a prior input event
* @param repositionTaskBounds the bounds the task is being repositioned to
* @param taskBoundsAtDragStart the bounds of the task on the first drag input event
* @param stableBounds bounds that represent the resize limit of this task
@@ -62,16 +63,19 @@ public class DragPositioningCallbackUtility {
* @param windowDecoration window decoration of the task being dragged
* @return whether this method changed repositionTaskBounds
*/
- static boolean changeBounds(int ctrlType, boolean hasMoved,
- Rect repositionTaskBounds, Rect taskBoundsAtDragStart, Rect stableBounds,
- PointF delta, DisplayController displayController, WindowDecoration windowDecoration) {
- // |mRepositionTaskBounds| is the bounds last reported if |mHasMoved| is true. If it's not
- // true, we can compare it against |mTaskBoundsAtDragStart|.
- final int oldLeft = hasMoved ? repositionTaskBounds.left : taskBoundsAtDragStart.left;
- final int oldTop = hasMoved ? repositionTaskBounds.top : taskBoundsAtDragStart.top;
- final int oldRight = hasMoved ? repositionTaskBounds.right : taskBoundsAtDragStart.right;
- final int oldBottom =
- hasMoved ? repositionTaskBounds.bottom : taskBoundsAtDragStart.bottom;
+ static boolean changeBounds(int ctrlType, Rect repositionTaskBounds, Rect taskBoundsAtDragStart,
+ Rect stableBounds, PointF delta, DisplayController displayController,
+ WindowDecoration windowDecoration) {
+ // If task is being dragged rather than resized, return since this method only handles
+ // with resizing
+ if (ctrlType == CTRL_TYPE_UNDEFINED) {
+ return false;
+ }
+
+ final int oldLeft = repositionTaskBounds.left;
+ final int oldTop = repositionTaskBounds.top;
+ final int oldRight = repositionTaskBounds.right;
+ final int oldBottom = repositionTaskBounds.bottom;
repositionTaskBounds.set(taskBoundsAtDragStart);
@@ -101,10 +105,6 @@ public class DragPositioningCallbackUtility {
repositionTaskBounds.bottom = (candidateBottom < stableBounds.bottom)
? candidateBottom : oldBottom;
}
- if (ctrlType == CTRL_TYPE_UNDEFINED) {
- repositionTaskBounds.offset((int) delta.x, (int) delta.y);
- }
-
// If width or height are negative or less than the minimum width or height, revert the
// respective bounds to use previous bound dimensions.
if (repositionTaskBounds.width() < getMinWidth(displayController, windowDecoration)) {
@@ -126,8 +126,26 @@ public class DragPositioningCallbackUtility {
}
/**
+ * Set bounds using a {@link SurfaceControl.Transaction}.
+ */
+ static void setPositionOnDrag(WindowDecoration decoration, Rect repositionTaskBounds,
+ Rect taskBoundsAtDragStart, PointF repositionStartPoint, SurfaceControl.Transaction t,
+ float x, float y) {
+ updateTaskBounds(repositionTaskBounds, taskBoundsAtDragStart, repositionStartPoint, x, y);
+ t.setPosition(decoration.mTaskSurface, repositionTaskBounds.left,
+ repositionTaskBounds.top);
+ }
+
+ static void updateTaskBounds(Rect repositionTaskBounds, Rect taskBoundsAtDragStart,
+ PointF repositionStartPoint, float x, float y) {
+ final float deltaX = x - repositionStartPoint.x;
+ final float deltaY = y - repositionStartPoint.y;
+ repositionTaskBounds.set(taskBoundsAtDragStart);
+ repositionTaskBounds.offset((int) deltaX, (int) deltaY);
+ }
+
+ /**
* Apply a bounds change to a task.
- * @param wct provided {@link WindowContainerTransaction} that may contain other changes
* @param windowDecoration decor of task we are changing bounds for
* @param taskBounds new bounds of this task
* @param taskOrganizer applies the provided WindowContainerTransaction
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
index b366c809537f..9bcb77f03abd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositioner.java
@@ -18,11 +18,14 @@ package com.android.wm.shell.windowdecor;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import java.util.function.Supplier;
+
/**
* A task positioner that resizes/relocates task contents as it is dragged.
* Utilizes {@link DragPositioningCallbackUtility} to determine new task bounds.
@@ -30,27 +33,35 @@ import com.android.wm.shell.common.DisplayController;
class FluidResizeTaskPositioner implements DragPositioningCallback {
private final ShellTaskOrganizer mTaskOrganizer;
private final WindowDecoration mWindowDecoration;
+ private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
private DisplayController mDisplayController;
private DragPositioningCallbackUtility.DragStartListener mDragStartListener;
private final Rect mStableBounds = new Rect();
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
+ // If a task move (not resize) finishes in this region, the positioner will not attempt to
+ // finalize the bounds there using WCT#setBounds
+ private final Rect mDisallowedAreaForEndBounds = new Rect();
+ private boolean mHasDragResized;
private int mCtrlType;
- private boolean mHasMoved;
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController) {
- this(taskOrganizer, windowDecoration, displayController, dragStartListener -> {});
+ DisplayController displayController, Rect disallowedAreaForEndBounds) {
+ this(taskOrganizer, windowDecoration, displayController, disallowedAreaForEndBounds,
+ dragStartListener -> {}, SurfaceControl.Transaction::new);
}
FluidResizeTaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
- DisplayController displayController,
- DragPositioningCallbackUtility.DragStartListener dragStartListener) {
+ DisplayController displayController, Rect disallowedAreaForEndBounds,
+ DragPositioningCallbackUtility.DragStartListener dragStartListener,
+ Supplier<SurfaceControl.Transaction> supplier) {
mTaskOrganizer = taskOrganizer;
mWindowDecoration = windowDecoration;
mDisplayController = displayController;
+ mDisallowedAreaForEndBounds.set(disallowedAreaForEndBounds);
mDragStartListener = dragStartListener;
+ mTransactionSupplier = supplier;
}
@Override
@@ -60,47 +71,66 @@ class FluidResizeTaskPositioner implements DragPositioningCallback {
mWindowDecoration.mTaskInfo.configuration.windowConfiguration.getBounds());
mRepositionStartPoint.set(x, y);
mDragStartListener.onDragStart(mWindowDecoration.mTaskInfo.taskId);
+ mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
}
@Override
public void onDragPositioningMove(float x, float y) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint);
- if (DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
+ if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType,
mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
mDisplayController, mWindowDecoration)) {
// The task is being resized, send the |dragResizing| hint to core with the first
// bounds-change wct.
- if (!mHasMoved && mCtrlType != CTRL_TYPE_UNDEFINED) {
+ if (!mHasDragResized) {
// This is the first bounds change since drag resize operation started.
wct.setDragResizing(mWindowDecoration.mTaskInfo.token, true /* dragResizing */);
}
DragPositioningCallbackUtility.applyTaskBoundsChange(wct, mWindowDecoration,
mRepositionTaskBounds, mTaskOrganizer);
- mHasMoved = true;
+ mHasDragResized = true;
+ } else if (mCtrlType == CTRL_TYPE_UNDEFINED) {
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+ DragPositioningCallbackUtility.setPositionOnDrag(mWindowDecoration,
+ mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t, x, y);
+ t.apply();
}
}
@Override
public void onDragPositioningEnd(float x, float y) {
- // |mHasMoved| being false means there is no real change to the task bounds in WM core, so
- // we don't need a WCT to finish it.
- if (mHasMoved) {
+ // If task has been resized or task was dragged into area outside of
+ // mDisallowedAreaForEndBounds, apply WCT to finish it.
+ if (isResizing() && mHasDragResized) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
wct.setDragResizing(mWindowDecoration.mTaskInfo.token, false /* dragResizing */);
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y,
mRepositionStartPoint);
- if (DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
- mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
- mDisplayController, mWindowDecoration)) {
+ if (DragPositioningCallbackUtility.changeBounds(mCtrlType, mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mStableBounds, delta, mDisplayController,
+ mWindowDecoration)) {
wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds);
}
mTaskOrganizer.applyTransaction(wct);
+ } else if (mCtrlType == CTRL_TYPE_UNDEFINED
+ && !mDisallowedAreaForEndBounds.contains((int) x, (int) y)) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ DragPositioningCallbackUtility.updateTaskBounds(mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mRepositionStartPoint, x, y);
+ wct.setBounds(mWindowDecoration.mTaskInfo.token, mRepositionTaskBounds);
+ mTaskOrganizer.applyTransaction(wct);
}
mTaskBoundsAtDragStart.setEmpty();
mRepositionStartPoint.set(0, 0);
mCtrlType = CTRL_TYPE_UNDEFINED;
- mHasMoved = false;
+ mHasDragResized = false;
}
+
+ private boolean isResizing() {
+ return (mCtrlType & CTRL_TYPE_TOP) != 0 || (mCtrlType & CTRL_TYPE_BOTTOM) != 0
+ || (mCtrlType & CTRL_TYPE_LEFT) != 0 || (mCtrlType & CTRL_TYPE_RIGHT) != 0;
+ }
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
index 1d416c65851b..5253fb84a4be 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositioner.java
@@ -18,11 +18,14 @@ package com.android.wm.shell.windowdecor;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.view.SurfaceControl;
import android.window.WindowContainerTransaction;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
+import java.util.function.Supplier;
+
/**
* A task positioner that also takes into account resizing a
* {@link com.android.wm.shell.windowdecor.ResizeVeil}.
@@ -39,17 +42,32 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback {
private final Rect mTaskBoundsAtDragStart = new Rect();
private final PointF mRepositionStartPoint = new PointF();
private final Rect mRepositionTaskBounds = new Rect();
+ // If a task move (not resize) finishes in this region, the positioner will not attempt to
+ // finalize the bounds there using WCT#setBounds
+ private final Rect mDisallowedAreaForEndBounds = new Rect();
+ private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
+ private boolean mHasDragResized;
private int mCtrlType;
- private boolean mHasMoved;
-
public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
DesktopModeWindowDecoration windowDecoration, DisplayController displayController,
+ Rect disallowedAreaForEndBounds,
DragPositioningCallbackUtility.DragStartListener dragStartListener) {
+ this(taskOrganizer, windowDecoration, displayController, disallowedAreaForEndBounds,
+ dragStartListener, SurfaceControl.Transaction::new);
+ }
+
+ public VeiledResizeTaskPositioner(ShellTaskOrganizer taskOrganizer,
+ DesktopModeWindowDecoration windowDecoration, DisplayController displayController,
+ Rect disallowedAreaForEndBounds,
+ DragPositioningCallbackUtility.DragStartListener dragStartListener,
+ Supplier<SurfaceControl.Transaction> supplier) {
mTaskOrganizer = taskOrganizer;
mDesktopWindowDecoration = windowDecoration;
mDisplayController = displayController;
mDragStartListener = dragStartListener;
+ mDisallowedAreaForEndBounds.set(disallowedAreaForEndBounds);
+ mTransactionSupplier = supplier;
}
@Override
@@ -58,27 +76,28 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback {
mTaskBoundsAtDragStart.set(
mDesktopWindowDecoration.mTaskInfo.configuration.windowConfiguration.getBounds());
mRepositionStartPoint.set(x, y);
- if (mCtrlType != CTRL_TYPE_UNDEFINED) {
+ if (isResizing()) {
mDesktopWindowDecoration.showResizeVeil();
}
- mHasMoved = false;
+ mHasDragResized = false;
mDragStartListener.onDragStart(mDesktopWindowDecoration.mTaskInfo.taskId);
+ mRepositionTaskBounds.set(mTaskBoundsAtDragStart);
}
@Override
public void onDragPositioningMove(float x, float y) {
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y, mRepositionStartPoint);
- if (DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
+ if (isResizing() && DragPositioningCallbackUtility.changeBounds(mCtrlType,
mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
mDisplayController, mDesktopWindowDecoration)) {
- if (mCtrlType != CTRL_TYPE_UNDEFINED) {
- mDesktopWindowDecoration.updateResizeVeil(mRepositionTaskBounds);
- } else {
- DragPositioningCallbackUtility.applyTaskBoundsChange(
- new WindowContainerTransaction(), mDesktopWindowDecoration,
- mRepositionTaskBounds, mTaskOrganizer);
- }
- mHasMoved = true;
+ mDesktopWindowDecoration.updateResizeVeil(mRepositionTaskBounds);
+ mHasDragResized = true;
+ } else if (mCtrlType == CTRL_TYPE_UNDEFINED) {
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+ DragPositioningCallbackUtility.setPositionOnDrag(mDesktopWindowDecoration,
+ mRepositionTaskBounds, mTaskBoundsAtDragStart, mRepositionStartPoint, t,
+ x, y);
+ t.apply();
}
}
@@ -86,22 +105,35 @@ public class VeiledResizeTaskPositioner implements DragPositioningCallback {
public void onDragPositioningEnd(float x, float y) {
PointF delta = DragPositioningCallbackUtility.calculateDelta(x, y,
mRepositionStartPoint);
- if (mHasMoved) {
- DragPositioningCallbackUtility.changeBounds(mCtrlType, mHasMoved,
- mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds, delta,
- mDisplayController, mDesktopWindowDecoration);
- DragPositioningCallbackUtility.applyTaskBoundsChange(
- new WindowContainerTransaction(), mDesktopWindowDecoration,
- mRepositionTaskBounds, mTaskOrganizer);
- }
- // TODO: (b/279062291) Synchronize the start of hide to the end of the draw triggered above.
- if (mCtrlType != CTRL_TYPE_UNDEFINED) {
+ if (isResizing()) {
+ if (mHasDragResized) {
+ DragPositioningCallbackUtility.changeBounds(
+ mCtrlType, mRepositionTaskBounds, mTaskBoundsAtDragStart, mStableBounds,
+ delta, mDisplayController, mDesktopWindowDecoration);
+ DragPositioningCallbackUtility.applyTaskBoundsChange(
+ new WindowContainerTransaction(), mDesktopWindowDecoration,
+ mRepositionTaskBounds, mTaskOrganizer);
+ }
+ // TODO: (b/279062291) Synchronize the start of hide to the end of the draw triggered
+ // above.
mDesktopWindowDecoration.updateResizeVeil(mRepositionTaskBounds);
mDesktopWindowDecoration.hideResizeVeil();
+ } else if (!mDisallowedAreaForEndBounds.contains((int) x, (int) y)) {
+ DragPositioningCallbackUtility.updateTaskBounds(mRepositionTaskBounds,
+ mTaskBoundsAtDragStart, mRepositionStartPoint, x, y);
+ DragPositioningCallbackUtility.applyTaskBoundsChange(new WindowContainerTransaction(),
+ mDesktopWindowDecoration, mRepositionTaskBounds, mTaskOrganizer);
}
+
mCtrlType = CTRL_TYPE_UNDEFINED;
mTaskBoundsAtDragStart.setEmpty();
mRepositionStartPoint.set(0, 0);
- mHasMoved = false;
+ mHasDragResized = false;
}
+
+ private boolean isResizing() {
+ return (mCtrlType & CTRL_TYPE_TOP) != 0 || (mCtrlType & CTRL_TYPE_BOTTOM) != 0
+ || (mCtrlType & CTRL_TYPE_LEFT) != 0 || (mCtrlType & CTRL_TYPE_RIGHT) != 0;
+ }
+
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index 11c5951faa1f..61781565270b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -18,15 +18,18 @@ package com.android.wm.shell.flicker.appcompat
import android.content.Context
import android.system.helpers.CommandsHelper
+import android.tools.common.traces.component.ComponentNameMatcher
import android.tools.device.flicker.legacy.FlickerBuilder
import android.tools.device.flicker.legacy.FlickerTest
+import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.helpers.LetterboxAppHelper
import android.tools.device.flicker.legacy.FlickerTestFactory
import android.tools.device.flicker.legacy.IFlickerTestData
-import com.android.server.wm.flicker.helpers.LetterboxAppHelper
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.wm.shell.flicker.BaseTest
-import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
+import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.layerKeepVisible
+import org.junit.After
import org.junit.Assume
import org.junit.Before
import org.junit.runners.Parameterized
@@ -35,7 +38,7 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
protected val context: Context = instrumentation.context
protected val letterboxApp = LetterboxAppHelper(instrumentation)
lateinit var cmdHelper: CommandsHelper
- lateinit var letterboxStyle: HashMap<String, String>
+ private lateinit var letterboxStyle: HashMap<String, String>
/** {@inheritDoc} */
override val transition: FlickerBuilder.() -> Unit
@@ -45,12 +48,22 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
letterboxApp.launchViaIntent(wmHelper)
setEndRotation()
}
+ teardown {
+ letterboxApp.exit(wmHelper)
+ }
}
@Before
fun before() {
cmdHelper = CommandsHelper.getInstance(instrumentation)
Assume.assumeTrue(tapl.isTablet && isIgnoreOrientationRequest())
+ letterboxStyle = mapLetterboxStyle()
+ setLetterboxEducationEnabled(false)
+ }
+
+ @After
+ fun after() {
+ resetLetterboxEducationEnabled()
}
private fun mapLetterboxStyle(): HashMap<String, String> {
@@ -67,6 +80,22 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
return map
}
+ private fun getLetterboxStyle(): HashMap<String, String> {
+ if (!::letterboxStyle.isInitialized) {
+ letterboxStyle = mapLetterboxStyle()
+ }
+ return letterboxStyle
+ }
+
+ private fun resetLetterboxEducationEnabled() {
+ val enabled = getLetterboxStyle().getValue("Is education enabled")
+ cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
+ }
+
+ private fun setLetterboxEducationEnabled(enabled: Boolean) {
+ cmdHelper.executeShellCommand("wm set-letterbox-style --isEducationEnabled $enabled")
+ }
+
private fun isIgnoreOrientationRequest(): Boolean {
val res = cmdHelper.executeShellCommand("wm get-ignore-orientation-request")
return res != null && res.contains("true")
@@ -89,10 +118,7 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
/** Only run on tests with config_letterboxActivityCornersRadius != 0 in devices */
private fun assumeLetterboxRoundedCornersEnabled() {
- if (!::letterboxStyle.isInitialized) {
- letterboxStyle = mapLetterboxStyle()
- }
- Assume.assumeTrue(letterboxStyle.getValue("Corner radius") != "0")
+ Assume.assumeTrue(getLetterboxStyle().getValue("Corner radius") != "0")
}
fun assertLetterboxAppVisibleAtStartAndEnd() {
@@ -100,12 +126,20 @@ abstract class BaseAppCompat(flicker: FlickerTest) : BaseTest(flicker) {
flicker.appWindowIsVisibleAtEnd(letterboxApp)
}
+ fun assertAppLetterboxedAtEnd() =
+ flicker.assertLayersEnd { isVisible(ComponentNameMatcher.LETTERBOX) }
+
+ fun assertAppLetterboxedAtStart() =
+ flicker.assertLayersStart { isVisible(ComponentNameMatcher.LETTERBOX) }
+
+ fun assertLetterboxAppLayerKeepVisible() = flicker.layerKeepVisible(letterboxApp)
+
companion object {
/**
* Creates the test configurations.
*
- * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation
- * modes.
+ * See [FlickerTestFactory.rotationTests] for configuring screen orientation and
+ * navigation modes.
*/
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index f212a4e0417e..c2141a370f10 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -70,6 +70,10 @@ class OpenAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flicker)
@Test
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtEndHasRoundedCorners()
+ @Postsubmit
+ @Test
+ fun appIsLetterboxedAtEnd() = assertAppLetterboxedAtEnd()
+
/**
* Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
* flicker, and disappears before the transition is complete
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index 8e75439889b2..b0e1a42306df 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -53,25 +53,32 @@ class RestartAppInSizeCompatModeTest(flicker: FlickerTest) : BaseAppCompat(flick
get() = {
super.transition(this)
transitions { letterboxApp.clickRestart(wmHelper) }
- teardown { letterboxApp.exit(wmHelper) }
}
@Postsubmit @Test fun appVisibleAtStartAndEnd() = assertLetterboxAppVisibleAtStartAndEnd()
@Postsubmit
@Test
- fun appLayerVisibilityChanges() {
- flicker.assertLayers {
- this.isVisible(letterboxApp)
+ fun appWindowVisibilityChanges() {
+ flicker.assertWm {
+ this.isAppWindowVisible(letterboxApp)
.then()
- .isInvisible(letterboxApp)
+ .isAppWindowInvisible(letterboxApp) // animatingExit true
.then()
- .isVisible(letterboxApp)
+ .isAppWindowVisible(letterboxApp) // Activity finish relaunching
}
}
@Postsubmit
@Test
+ fun appLayerKeepVisible() = assertLetterboxAppLayerKeepVisible()
+
+ @Postsubmit
+ @Test
+ fun appIsLetterboxedAtStart() = assertAppLetterboxedAtStart()
+
+ @Postsubmit
+ @Test
fun letterboxedAppHasRoundedCorners() = assertLetterboxAppAtStartHasRoundedCorners()
/** Checks that the visible region of [letterboxApp] is still within display bounds */
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
index 6199e0b05059..8592dea19289 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandlerTest.java
@@ -94,7 +94,7 @@ public class EnterDesktopTaskTransitionHandlerTest {
WindowContainerTransaction wct = new WindowContainerTransaction();
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
- mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+ mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
@@ -115,7 +115,7 @@ public class EnterDesktopTaskTransitionHandlerTest {
WindowContainerTransaction wct = new WindowContainerTransaction();
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mEnterDesktopTaskTransitionHandler);
- mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+ mEnterDesktopTaskTransitionHandler.startTransition(transitionType, wct, null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FREEFORM);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
index 4fad05433d1c..0d0a08cb0ffb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/ExitDesktopTaskTransitionHandlerTest.java
@@ -31,6 +31,7 @@ import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Point;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.view.SurfaceControl;
@@ -75,6 +76,7 @@ public class ExitDesktopTaskTransitionHandlerTest extends ShellTestCase {
@Mock
ShellExecutor mExecutor;
+ private Point mPoint;
private ExitDesktopTaskTransitionHandler mExitDesktopTaskTransitionHandler;
@Before
@@ -90,6 +92,7 @@ public class ExitDesktopTaskTransitionHandlerTest extends ShellTestCase {
mExitDesktopTaskTransitionHandler = new ExitDesktopTaskTransitionHandler(mTransitions,
mContext);
+ mPoint = new Point(0, 0);
}
@Test
@@ -100,7 +103,8 @@ public class ExitDesktopTaskTransitionHandlerTest extends ShellTestCase {
doReturn(mToken).when(mTransitions)
.startTransition(transitionType, wct, mExitDesktopTaskTransitionHandler);
- mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct);
+ mExitDesktopTaskTransitionHandler.startTransition(transitionType, wct, mPoint,
+ null);
TransitionInfo.Change change =
createChange(WindowManager.TRANSIT_CHANGE, taskId, WINDOWING_MODE_FULLSCREEN);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
index 45590951dd1d..9d566860c1cd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java
@@ -179,4 +179,23 @@ public class TaskViewTransitionsTest extends ShellTestCase {
mTaskViewTransitions.findPending(mTaskViewTaskController, TRANSIT_CHANGE);
assertThat(pendingBounds2).isNull();
}
+
+ @Test
+ public void testSetTaskVisibility_taskRemoved_noNPE() {
+ mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
+
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskViewTransitions.setTaskViewVisible(mTaskViewTaskController, false);
+ }
+
+ @Test
+ public void testSetTaskBounds_taskRemoved_noNPE() {
+ mTaskViewTransitions.removeTaskView(mTaskViewTaskController);
+
+ assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS);
+
+ mTaskViewTransitions.setTaskBounds(mTaskViewTaskController,
+ new Rect(0, 0, 100, 100));
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
index 9a90996b786c..4c27706a39a3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -29,6 +30,7 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.WindowConfiguration;
+import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.input.InputManager;
@@ -47,6 +49,7 @@ import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.desktopmode.DesktopModeController;
import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -68,6 +71,7 @@ import java.util.function.Supplier;
public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
private static final String TAG = "DesktopModeWindowDecorViewModelTests";
+ private static final Rect STABLE_INSETS = new Rect(0, 100, 0, 0);
@Mock private DesktopModeWindowDecoration mDesktopModeWindowDecoration;
@Mock private DesktopModeWindowDecoration.Factory mDesktopModeWindowDecorFactory;
@@ -76,6 +80,7 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
@Mock private Choreographer mMainChoreographer;
@Mock private ShellTaskOrganizer mTaskOrganizer;
@Mock private DisplayController mDisplayController;
+ @Mock private DisplayLayout mDisplayLayout;
@Mock private SplitScreenController mSplitScreenController;
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private DesktopModeController mDesktopModeController;
@@ -113,6 +118,8 @@ public class DesktopModeWindowDecorViewModelTests extends ShellTestCase {
.when(mDesktopModeWindowDecorFactory)
.create(any(), any(), any(), any(), any(), any(), any(), any());
doReturn(mTransaction).when(mTransactionFactory).get();
+ doReturn(mDisplayLayout).when(mDisplayController).getDisplayLayout(anyInt());
+ doReturn(STABLE_INSETS).when(mDisplayLayout).stableInsets();
when(mMockInputMonitorFactory.create(any(), any())).thenReturn(mInputMonitor);
// InputChannel cannot be mocked because it passes to InputEventReceiver.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index 348b3659e864..de46b31879ed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -85,7 +85,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsDoesNotChangeHeightWhenLessThanMin() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Resize to width of 95px and height of 5px with min width of 10px
val newX = STARTING_BOUNDS.right.toFloat() - 5
@@ -93,8 +93,8 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
- mockDisplayController, mockWindowDecoration)
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
@@ -105,7 +105,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsDoesNotChangeWidthWhenLessThanMin() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Resize to height of 95px and width of 5px with min width of 10px
val newX = STARTING_BOUNDS.right.toFloat() - 95
@@ -113,8 +113,8 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
- mockDisplayController, mockWindowDecoration)
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top + 5)
@@ -125,7 +125,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsDoesNotChangeHeightWhenNegative() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Resize to width of 95px and width of -5px with minimum of 10px
val newX = STARTING_BOUNDS.right.toFloat() - 5
@@ -133,8 +133,8 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
- mockDisplayController, mockWindowDecoration)
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
@@ -145,7 +145,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsRunsWhenResizeBoundsValid() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Shrink to height 20px and width 20px with both min height/width equal to 10px
val newX = STARTING_BOUNDS.right.toFloat() - 80
@@ -153,7 +153,7 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top + 80)
@@ -164,7 +164,7 @@ class DragPositioningCallbackUtilityTest {
@Test
fun testChangeBoundsDoesNotRunWithNegativeHeightAndWidth() {
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(), STARTING_BOUNDS.top.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Shrink to height -5px and width -5px with both min height/width equal to 10px
val newX = STARTING_BOUNDS.right.toFloat() - 105
val newY = STARTING_BOUNDS.top.toFloat() + 105
@@ -172,7 +172,7 @@ class DragPositioningCallbackUtilityTest {
val delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_TOP,
- false /* hasMoved */, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
mockDisplayController, mockWindowDecoration)
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
@@ -185,21 +185,21 @@ class DragPositioningCallbackUtilityTest {
var hasMoved = false
val startingPoint = PointF(STARTING_BOUNDS.right.toFloat(),
STARTING_BOUNDS.bottom.toFloat())
- val repositionTaskBounds = Rect()
+ val repositionTaskBounds = Rect(STARTING_BOUNDS)
// Initial resize to width and height 110px.
var newX = STARTING_BOUNDS.right.toFloat() + 10
var newY = STARTING_BOUNDS.bottom.toFloat() + 10
var delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
assertTrue(DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
- hasMoved, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
- mockDisplayController, mockWindowDecoration))
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ mockDisplayController, mockWindowDecoration))
hasMoved = true
// Resize width to 120px, height to disallowed area which should not result in a change.
newX += 10
newY = DISALLOWED_RESIZE_AREA.top.toFloat()
delta = DragPositioningCallbackUtility.calculateDelta(newX, newY, startingPoint)
assertTrue(DragPositioningCallbackUtility.changeBounds(CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM,
- hasMoved, repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
+ repositionTaskBounds, STARTING_BOUNDS, STABLE_BOUNDS, delta,
mockDisplayController, mockWindowDecoration))
assertThat(repositionTaskBounds.left).isEqualTo(STARTING_BOUNDS.left)
assertThat(repositionTaskBounds.top).isEqualTo(STARTING_BOUNDS.top)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 5bea8f2d1c45..282a19e8e9a5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -6,14 +6,16 @@ import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
import android.view.Display
+import android.view.SurfaceControl
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.Change.CHANGE_DRAG_RESIZING
import androidx.test.filters.SmallTest
-import com.android.wm.shell.common.DisplayController
-import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
+import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
@@ -21,12 +23,14 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import java.util.function.Supplier
+import org.mockito.Mockito.`when` as whenever
/**
* Tests for [FluidResizeTaskPositioner].
@@ -56,6 +60,10 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
private lateinit var mockDisplayLayout: DisplayLayout
@Mock
private lateinit var mockDisplay: Display
+ @Mock
+ private lateinit var mockTransactionFactory: Supplier<SurfaceControl.Transaction>
+ @Mock
+ private lateinit var mockTransaction: SurfaceControl.Transaction
private lateinit var taskPositioner: FluidResizeTaskPositioner
@@ -68,8 +76,10 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
mockShellTaskOrganizer,
mockWindowDecoration,
mockDisplayController,
- mockDragStartListener
- )
+ DISALLOWED_AREA_FOR_END_BOUNDS,
+ mockDragStartListener,
+ mockTransactionFactory
+ )
whenever(taskToken.asBinder()).thenReturn(taskBinder)
whenever(mockDisplayController.getDisplayLayout(DISPLAY_ID)).thenReturn(mockDisplayLayout)
@@ -77,6 +87,8 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(STABLE_BOUNDS)
}
+ `when`(mockDisplayLayout.stableInsets()).thenReturn(STABLE_INSETS)
+ `when`(mockTransactionFactory.get()).thenReturn(mockTransaction)
mockWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
taskId = TASK_ID
@@ -236,6 +248,318 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
})
}
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenLessThanMin() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to width of 95px and height of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.top ==
+ STARTING_BOUNDS.top &&
+ change.configuration.windowConfiguration.bounds.bottom ==
+ STARTING_BOUNDS.bottom
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenLessThanMin() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to height of 95px and width of 5px with min width of 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.right ==
+ STARTING_BOUNDS.right &&
+ change.configuration.windowConfiguration.bounds.left ==
+ STARTING_BOUNDS.left
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeHeightWhenNegative() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to height of -5px and width of 95px
+ val newX = STARTING_BOUNDS.right.toFloat() - 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 105
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.top ==
+ STARTING_BOUNDS.top &&
+ change.configuration.windowConfiguration.bounds.bottom ==
+ STARTING_BOUNDS.bottom
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotChangeWidthWhenNegative() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Resize to width of -5px and height of 95px
+ val newX = STARTING_BOUNDS.right.toFloat() - 105
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS)
+ != 0) && change.configuration.windowConfiguration.bounds.right ==
+ STARTING_BOUNDS.right &&
+ change.configuration.windowConfiguration.bounds.left ==
+ STARTING_BOUNDS.left
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsRunsWhenResizeBoundsValid() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to height 20px and width 20px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 80
+ val newY = STARTING_BOUNDS.top.toFloat() + 80
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_setBoundsDoesNotRunWithNegativeHeightAndWidth() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to height 5px and width 5px with both min height/width equal to 10px
+ val newX = STARTING_BOUNDS.right.toFloat() - 95
+ val newY = STARTING_BOUNDS.top.toFloat() + 95
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_useDefaultMinWhenMinWidthInvalid() {
+ mockWindowDecoration.mTaskInfo.minWidth = -1
+
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to width and height of 3px with invalid minWidth = -1 and defaultMinSize = 5px
+ val newX = STARTING_BOUNDS.right.toFloat() - 97
+ val newY = STARTING_BOUNDS.top.toFloat() + 97
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_resize_useMinWidthWhenValid() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_TOP, // Resize right and top
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ // Shrink to width and height of 7px with valid minWidth = 10px and defaultMinSize = 5px
+ val newX = STARTING_BOUNDS.right.toFloat() - 93
+ val newY = STARTING_BOUNDS.top.toFloat() + 93
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
+ fun testDragResize_toDisallowedBounds_freezesAtLimit() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_RIGHT or CTRL_TYPE_BOTTOM, // Resize right-bottom corner
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.bottom.toFloat()
+ )
+
+ // Resize the task by 10px to the right and bottom, a valid destination
+ val newBounds = Rect(
+ STARTING_BOUNDS.left,
+ STARTING_BOUNDS.top,
+ STARTING_BOUNDS.right + 10,
+ STARTING_BOUNDS.bottom + 10)
+ taskPositioner.onDragPositioningMove(
+ newBounds.right.toFloat(),
+ newBounds.bottom.toFloat()
+ )
+
+ // Resize the task by another 10px to the right (allowed) and to just in the disallowed
+ // area of the Y coordinate.
+ val newBounds2 = Rect(
+ newBounds.left,
+ newBounds.top,
+ newBounds.right + 10,
+ DISALLOWED_RESIZE_AREA.top
+ )
+ taskPositioner.onDragPositioningMove(
+ newBounds2.right.toFloat(),
+ newBounds2.bottom.toFloat()
+ )
+
+ taskPositioner.onDragPositioningEnd(newBounds2.right.toFloat(), newBounds2.bottom.toFloat())
+
+ // The first resize falls in the allowed area, verify there's a change for it.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(newBounds)
+ }
+ })
+ // The second resize falls in the disallowed area, verify there's no change for it.
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(newBounds2)
+ }
+ })
+ // Instead, there should be a change for its allowed portion (the X movement) with the Y
+ // staying frozen in the last valid resize position.
+ verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder && change.ofBounds(
+ Rect(
+ newBounds2.left,
+ newBounds2.top,
+ newBounds2.right,
+ newBounds.bottom // Stayed at the first resize destination.
+ )
+ )
+ }
+ })
+ }
+
+ @Test
+ fun testDragResize_drag_setBoundsNotRunIfDragEndsInDisallowedEndArea() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ STARTING_BOUNDS.right.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ val newX = STARTING_BOUNDS.right.toFloat() + 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
private fun WindowContainerTransaction.Change.ofBounds(bounds: Rect): Boolean {
return ((windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) &&
bounds == configuration.windowConfiguration.bounds
@@ -251,6 +575,8 @@ class FluidResizeTaskPositionerTest : ShellTestCase() {
private const val NAVBAR_HEIGHT = 50
private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val STABLE_INSETS = Rect(0, 50, 0, 0)
+ private val DISALLOWED_AREA_FOR_END_BOUNDS = Rect(0, 0, 300, 300)
private val DISALLOWED_RESIZE_AREA = Rect(
DISPLAY_BOUNDS.left,
DISPLAY_BOUNDS.bottom - NAVBAR_HEIGHT,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 498082bd53e5..217bdbb07447 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -21,12 +21,13 @@ import android.graphics.Rect
import android.os.IBinder
import android.testing.AndroidTestingRunner
import android.view.Display
+import android.view.SurfaceControl
import android.window.WindowContainerToken
import androidx.test.filters.SmallTest
-import com.android.wm.shell.common.DisplayController
-import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP
import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED
@@ -34,13 +35,16 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.`when` as whenever
import org.mockito.Mockito.any
import org.mockito.Mockito.argThat
+import org.mockito.Mockito.eq
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
+import java.util.function.Supplier
+import org.mockito.Mockito.`when` as whenever
/**
* Tests for [VeiledResizeTaskPositioner].
@@ -70,6 +74,10 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
private lateinit var mockDisplayLayout: DisplayLayout
@Mock
private lateinit var mockDisplay: Display
+ @Mock
+ private lateinit var mockTransactionFactory: Supplier<SurfaceControl.Transaction>
+ @Mock
+ private lateinit var mockTransaction: SurfaceControl.Transaction
private lateinit var taskPositioner: VeiledResizeTaskPositioner
@@ -82,7 +90,9 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
mockShellTaskOrganizer,
mockDesktopWindowDecoration,
mockDisplayController,
- mockDragStartListener
+ DISALLOWED_AREA_FOR_END_BOUNDS,
+ mockDragStartListener,
+ mockTransactionFactory
)
whenever(taskToken.asBinder()).thenReturn(taskBinder)
@@ -91,6 +101,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
whenever(mockDisplayLayout.getStableBounds(any())).thenAnswer { i ->
(i.arguments.first() as Rect).set(STABLE_BOUNDS)
}
+ `when`(mockTransactionFactory.get()).thenReturn(mockTransaction)
mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply {
taskId = TASK_ID
@@ -125,36 +136,31 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
fun testDragResize_movesTask_doesNotShowResizeVeil() {
taskPositioner.onDragPositioningStart(
CTRL_TYPE_UNDEFINED,
- STARTING_BOUNDS.left.toFloat() + 50,
+ STARTING_BOUNDS.left.toFloat(),
STARTING_BOUNDS.top.toFloat()
)
taskPositioner.onDragPositioningMove(
STARTING_BOUNDS.left.toFloat() + 60,
- STARTING_BOUNDS.top.toFloat() + 10
+ STARTING_BOUNDS.top.toFloat() + 100
)
val rectAfterMove = Rect(STARTING_BOUNDS)
- rectAfterMove.left += 10
- rectAfterMove.right += 10
- rectAfterMove.top += 10
- rectAfterMove.bottom += 10
- verify(mockShellTaskOrganizer).applyTransaction(argThat { wct ->
- return@argThat wct.changes.any { (token, change) ->
- token == taskBinder &&
- (change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0 &&
- change.configuration.windowConfiguration.bounds == rectAfterMove
- }
- })
+ rectAfterMove.left += 60
+ rectAfterMove.right += 60
+ rectAfterMove.top += 100
+ rectAfterMove.bottom += 100
+ verify(mockTransaction).setPosition(any(), eq(rectAfterMove.left.toFloat()),
+ eq(rectAfterMove.top.toFloat()))
taskPositioner.onDragPositioningEnd(
STARTING_BOUNDS.left.toFloat() + 70,
STARTING_BOUNDS.top.toFloat() + 20
)
- val rectAfterEnd = Rect(rectAfterMove)
- rectAfterEnd.left += 10
- rectAfterEnd.top += 10
- rectAfterEnd.right += 10
- rectAfterEnd.bottom += 10
+ val rectAfterEnd = Rect(STARTING_BOUNDS)
+ rectAfterEnd.left += 70
+ rectAfterEnd.right += 70
+ rectAfterEnd.top += 20
+ rectAfterEnd.bottom += 20
verify(mockDesktopWindowDecoration, never()).createResizeVeil()
verify(mockDesktopWindowDecoration, never()).hideResizeVeil()
@@ -239,6 +245,32 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
})
}
+
+ @Test
+ fun testDragResize_drag_setBoundsNotRunIfDragEndsInDisallowedEndArea() {
+ taskPositioner.onDragPositioningStart(
+ CTRL_TYPE_UNDEFINED, // drag
+ STARTING_BOUNDS.left.toFloat(),
+ STARTING_BOUNDS.top.toFloat()
+ )
+
+ val newX = STARTING_BOUNDS.left.toFloat() + 5
+ val newY = STARTING_BOUNDS.top.toFloat() + 5
+ taskPositioner.onDragPositioningMove(
+ newX,
+ newY
+ )
+
+ taskPositioner.onDragPositioningEnd(newX, newY)
+
+ verify(mockShellTaskOrganizer, never()).applyTransaction(argThat { wct ->
+ return@argThat wct.changes.any { (token, change) ->
+ token == taskBinder &&
+ ((change.windowSetMask and WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)
+ }
+ })
+ }
+
companion object {
private const val TASK_ID = 5
private const val MIN_WIDTH = 10
@@ -249,6 +281,7 @@ class VeiledResizeTaskPositionerTest : ShellTestCase() {
private const val NAVBAR_HEIGHT = 50
private val DISPLAY_BOUNDS = Rect(0, 0, 2400, 1600)
private val STARTING_BOUNDS = Rect(0, 0, 100, 100)
+ private val DISALLOWED_AREA_FOR_END_BOUNDS = Rect(0, 0, 50, 50)
private val STABLE_BOUNDS = Rect(
DISPLAY_BOUNDS.left,
DISPLAY_BOUNDS.top,
diff --git a/libs/hwui/Tonemapper.cpp b/libs/hwui/Tonemapper.cpp
index 0d39f0e33298..974a5d05aa84 100644
--- a/libs/hwui/Tonemapper.cpp
+++ b/libs/hwui/Tonemapper.cpp
@@ -97,7 +97,6 @@ void tonemapPaint(const SkImageInfo& source, const SkImageInfo& destination, flo
.inputDataspace = sourceDataspace,
.outputDataspace = destinationDataspace,
.undoPremultipliedAlpha = source.alphaType() == kPremul_SkAlphaType,
- .fakeInputDataspace = destinationDataspace,
.type = shaders::LinearEffect::SkSLType::ColorFilter};
constexpr float kMaxDisplayBrightnessNits = 1000.f;
constexpr float kCurrentDisplayBrightnessNits = 500.f;
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 7e9d44fbdbd1..c00a2707e0a2 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -29,6 +29,7 @@
#include "Layer.h"
#include "Properties.h"
#include "RenderThread.h"
+#include "VulkanManager.h"
#include "pipeline/skia/ATraceMemoryDump.h"
#include "pipeline/skia/ShaderCache.h"
#include "pipeline/skia/SkiaMemoryTracer.h"
@@ -182,8 +183,14 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState)
}
log.appendFormat("Contexts: %zu (stopped = %zu)\n", mCanvasContexts.size(), stoppedContexts);
+ auto vkInstance = VulkanManager::peekInstance();
if (!mGrContext) {
- log.appendFormat("No GPU context.\n");
+ if (!vkInstance) {
+ log.appendFormat("No GPU context.\n");
+ } else {
+ log.appendFormat("No GrContext; however %d remaining Vulkan refs",
+ vkInstance->getStrongCount() - 1);
+ }
return;
}
std::vector<skiapipeline::ResourcePair> cpuResourceMap = {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index f198bca9060c..4cffc6c2efe3 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -107,11 +107,11 @@ GrVkGetProc VulkanManager::sSkiaGetProp = [](const char* proc_name, VkInstance i
#define GET_INST_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(mInstance, "vk" #F)
#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(mDevice, "vk" #F)
-sp<VulkanManager> VulkanManager::getInstance() {
- // cache a weakptr to the context to enable a second thread to share the same vulkan state
- static wp<VulkanManager> sWeakInstance = nullptr;
- static std::mutex sLock;
+// cache a weakptr to the context to enable a second thread to share the same vulkan state
+static wp<VulkanManager> sWeakInstance = nullptr;
+static std::mutex sLock;
+sp<VulkanManager> VulkanManager::getInstance() {
std::lock_guard _lock{sLock};
sp<VulkanManager> vulkanManager = sWeakInstance.promote();
if (!vulkanManager.get()) {
@@ -122,6 +122,11 @@ sp<VulkanManager> VulkanManager::getInstance() {
return vulkanManager;
}
+sp<VulkanManager> VulkanManager::peekInstance() {
+ std::lock_guard _lock{sLock};
+ return sWeakInstance.promote();
+}
+
VulkanManager::~VulkanManager() {
if (mDevice != VK_NULL_HANDLE) {
mDeviceWaitIdle(mDevice);
@@ -404,9 +409,13 @@ void VulkanManager::initialize() {
}
}
-sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options,
- ContextType contextType) {
+static void onGrContextReleased(void* context) {
+ VulkanManager* manager = (VulkanManager*)context;
+ manager->decStrong((void*)onGrContextReleased);
+}
+sk_sp<GrDirectContext> VulkanManager::createContext(GrContextOptions& options,
+ ContextType contextType) {
GrVkBackendContext backendContext;
backendContext.fInstance = mInstance;
backendContext.fPhysicalDevice = mPhysicalDevice;
@@ -418,6 +427,11 @@ sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& opti
backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
backendContext.fGetProc = sSkiaGetProp;
+ LOG_ALWAYS_FATAL_IF(options.fContextDeleteProc != nullptr, "Conflicting fContextDeleteProcs!");
+ this->incStrong((void*)onGrContextReleased);
+ options.fContextDeleteContext = this;
+ options.fContextDeleteProc = onGrContextReleased;
+
return GrDirectContext::MakeVulkan(backendContext, options);
}
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index c5196eeccea3..00a40c0c85c3 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -66,6 +66,7 @@ class RenderThread;
class VulkanManager final : public RefBase {
public:
static sp<VulkanManager> getInstance();
+ static sp<VulkanManager> peekInstance();
// Sets up the vulkan context that is shared amonst all clients of the VulkanManager. This must
// be call once before use of the VulkanManager. Multiple calls after the first will simiply
@@ -109,7 +110,7 @@ public:
};
// returns a Skia graphic context used to draw content on the specified thread
- sk_sp<GrDirectContext> createContext(const GrContextOptions& options,
+ sk_sp<GrDirectContext> createContext(GrContextOptions& options,
ContextType contextType = ContextType::kRenderThread);
uint32_t getDriverVersion() const { return mDriverVersion; }
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index bffe137c2bd3..913af8ac3474 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -284,7 +284,9 @@ sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
case HAL_DATASPACE_TRANSFER_GAMMA2_8:
return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
case HAL_DATASPACE_TRANSFER_ST2084:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+ return SkColorSpace::MakeRGB({-2.0, -1.555223, 1.860454, 32 / 2523.0, 2413 / 128.0,
+ -2392 / 128.0, 8192 / 1305.0},
+ gamut);
case HAL_DATASPACE_TRANSFER_SMPTE_170M:
return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut);
case HAL_DATASPACE_TRANSFER_UNSPECIFIED:
@@ -427,10 +429,10 @@ skcms_TransferFunction GetExtendedTransferFunction(float sdrHdrRatio) {
}
// Skia skcms' default HLG maps encoded [0, 1] to linear [1, 12] in order to follow ARIB
-// but LinearEffect expects a decoded [0, 1] range instead to follow Rec 2100.
+// but LinearEffect expects to map 1.0 == 203 nits
std::optional<skcms_TransferFunction> GetHLGScaleTransferFunction() {
skcms_TransferFunction hlgFn;
- if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 1.f / 12.f, 2.f, 2.f, 1.f / 0.17883277f,
+ if (skcms_TransferFunction_makeScaledHLGish(&hlgFn, 0.314509843, 2.f, 2.f, 1.f / 0.17883277f,
0.28466892f, 0.55991073f)) {
return std::make_optional<skcms_TransferFunction>(hlgFn);
}