summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_move_down.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_move_left.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_move_right.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/pip_ic_move_up.xml25
-rw-r--r--libs/WindowManager/Shell/res/layout/tv_pip_menu.xml16
-rw-r--r--libs/WindowManager/Shell/res/values-fr-rCA/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-pt-rPT/strings.xml2
-rw-r--r--libs/WindowManager/Shell/res/values-tvdpi/dimen.xml4
-rw-r--r--libs/WindowManager/Shell/res/values/colors_tv.xml4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java38
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java60
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java128
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java8
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java33
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java10
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java74
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java56
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java98
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java21
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java25
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java14
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/util/TransitionUtil.java12
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java141
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt181
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java2
-rw-r--r--libs/hwui/MemoryPolicy.h6
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp5
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp19
-rw-r--r--libs/hwui/renderthread/CacheManager.h1
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp9
-rw-r--r--libs/hwui/renderthread/RenderProxy.h1
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp5
-rw-r--r--libs/hwui/renderthread/RenderThread.h1
50 files changed, 717 insertions, 472 deletions
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_move_down.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_move_down.xml
deleted file mode 100644
index d8f356164358..000000000000
--- a/libs/WindowManager/Shell/res/drawable/pip_ic_move_down.xml
+++ /dev/null
@@ -1,25 +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.
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="@color/tv_pip_menu_focus_border"
- android:pathData="M7,10l5,5 5,-5H7z"/>
-</vector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_move_left.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_move_left.xml
deleted file mode 100644
index 3e0011c65942..000000000000
--- a/libs/WindowManager/Shell/res/drawable/pip_ic_move_left.xml
+++ /dev/null
@@ -1,25 +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.
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="@color/tv_pip_menu_focus_border"
- android:pathData="M14,7l-5,5 5,5V7z"/>
-</vector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_move_right.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_move_right.xml
deleted file mode 100644
index f6b3c72e3cb5..000000000000
--- a/libs/WindowManager/Shell/res/drawable/pip_ic_move_right.xml
+++ /dev/null
@@ -1,25 +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.
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="@color/tv_pip_menu_focus_border"
- android:pathData="M10,17l5,-5 -5,-5v10z"/>
-</vector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/pip_ic_move_up.xml b/libs/WindowManager/Shell/res/drawable/pip_ic_move_up.xml
deleted file mode 100644
index 1a3446249573..000000000000
--- a/libs/WindowManager/Shell/res/drawable/pip_ic_move_up.xml
+++ /dev/null
@@ -1,25 +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.
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="@color/tv_pip_menu_focus_border"
- android:pathData="M7,14l5,-5 5,5H7z"/>
-</vector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
index ab64f9e359b0..82a358cf68d6 100644
--- a/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/tv_pip_menu.xml
@@ -104,9 +104,7 @@
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:alpha="0"
- android:contentDescription="@string/a11y_action_pip_move_up"
- android:elevation="@dimen/pip_menu_arrow_elevation"
- android:src="@drawable/pip_ic_move_up" />
+ android:contentDescription="@string/a11y_action_pip_move_up"/>
<ImageView
android:id="@+id/tv_pip_menu_arrow_right"
@@ -115,9 +113,7 @@
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:alpha="0"
- android:contentDescription="@string/a11y_action_pip_move_right"
- android:elevation="@dimen/pip_menu_arrow_elevation"
- android:src="@drawable/pip_ic_move_right" />
+ android:contentDescription="@string/a11y_action_pip_move_right"/>
<ImageView
android:id="@+id/tv_pip_menu_arrow_down"
@@ -126,9 +122,7 @@
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:alpha="0"
- android:contentDescription="@string/a11y_action_pip_move_down"
- android:elevation="@dimen/pip_menu_arrow_elevation"
- android:src="@drawable/pip_ic_move_down" />
+ android:contentDescription="@string/a11y_action_pip_move_down"/>
<ImageView
android:id="@+id/tv_pip_menu_arrow_left"
@@ -137,7 +131,5 @@
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:alpha="0"
- android:contentDescription="@string/a11y_action_pip_move_left"
- android:elevation="@dimen/pip_menu_arrow_elevation"
- android:src="@drawable/pip_ic_move_left" />
+ android:contentDescription="@string/a11y_action_pip_move_left"/>
</RelativeLayout>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 7814b7d38fed..6d19e55217f6 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/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 ignorée."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Touchez pour redémarrer cette application afin d\'obtenir un meilleur affichage."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Pour obtenir un meilleur affichage, touchez pour redémarrer cette application."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo?\nTouchez pour réajuster"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index ed0cdb61dacf..04ee54046439 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -79,7 +79,7 @@
<string name="notification_bubble_title" msgid="6082910224488253378">"Balão"</string>
<string name="manage_bubbles_text" msgid="7730624269650594419">"Gerir"</string>
<string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balão ignorado."</string>
- <string name="restart_button_description" msgid="6712141648865547958">"Toque para reiniciar esta app e ficar com uma melhor visão."</string>
+ <string name="restart_button_description" msgid="6712141648865547958">"Toque para reiniciar esta app e ver melhor."</string>
<string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmara?\nToque aqui para reajustar"</string>
<string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Não foi corrigido?\nToque para reverter"</string>
<string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nenhum problema com a câmara? Toque para ignorar."</string>
diff --git a/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml
index adbf65648dd1..fd825639f1e8 100644
--- a/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml
+++ b/libs/WindowManager/Shell/res/values-tvdpi/dimen.xml
@@ -33,8 +33,8 @@
<!-- outer space minus border width -->
<dimen name="pip_menu_outer_space_frame">20dp</dimen>
- <dimen name="pip_menu_arrow_size">24dp</dimen>
- <dimen name="pip_menu_arrow_elevation">5dp</dimen>
+ <dimen name="pip_menu_arrow_size">12dp</dimen>
+ <dimen name="pip_menu_arrow_elevation">1dp</dimen>
<dimen name="pip_menu_elevation_no_menu">1dp</dimen>
<dimen name="pip_menu_elevation_move_menu">7dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/colors_tv.xml b/libs/WindowManager/Shell/res/values/colors_tv.xml
index e6933ca3fce6..5f7fb12c3002 100644
--- a/libs/WindowManager/Shell/res/values/colors_tv.xml
+++ b/libs/WindowManager/Shell/res/values/colors_tv.xml
@@ -27,6 +27,10 @@
<color name="tv_pip_menu_focus_border">#E8EAED</color>
<color name="tv_pip_menu_dim_layer">#990E0E0F</color>
<color name="tv_pip_menu_background">#1E232C</color>
+ <!-- Normally, the arrow color would be the same as the focus border color. But due to
+ optical illusion that looks too dark on the screen. That's why we define a separate
+ (lighter) arrow color. -->
+ <color name="tv_pip_menu_arrow_color">#F1F3F4</color>
<color name="tv_pip_edu_text">#99D2E3FC</color>
<color name="tv_pip_edu_text_home_icon">#D2E3FC</color>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index 53a438ec2fde..c98090638010 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -54,10 +54,42 @@ public interface BackAnimation {
void setTriggerBack(boolean triggerBack);
/**
- * Sets the threshold values that defining edge swipe behavior.
- * @param progressThreshold the max threshold to keep linear progressing back animation.
+ * Sets the threshold values that define edge swipe behavior.<br>
+ * <br>
+ * <h1>How does {@code nonLinearFactor} work?</h1>
+ * <pre>
+ * screen screen screen
+ * width width width
+ * |——————| |————————————| |————————————————————|
+ * A B A B C A
+ * 1 +——————+—————+ 1 +————————————+ 1 +————————————+———————+
+ * | / | | —/| | | —————/|
+ * | / | | —/ | | ——/ |
+ * | / | | —/ | | ——/ | |
+ * | / | | —/ | | ——/ | |
+ * | / | | —/ | | ——/ | |
+ * |/ | |—/ | |—/ | |
+ * 0 +————————————+ 0 +————————————+ 0 +————————————+———————+
+ * B B B
+ * </pre>
+ * Three devices with different widths (smaller, equal, and wider) relative to the progress
+ * threshold are shown in the graphs.<br>
+ * - A is the width of the screen<br>
+ * - B is the progress threshold (horizontal swipe distance where progress is linear)<br>
+ * - C equals B + (A - B) * nonLinearFactor<br>
+ * <br>
+ * If A is less than or equal to B, {@code progress} for the swipe distance between:<br>
+ * - [0, A] will scale linearly between [0, 1].<br>
+ * If A is greater than B, {@code progress} for swipe distance between:<br>
+ * - [0, B] will scale linearly between [0, B / C]<br>
+ * - (B, A] will scale non-linearly and reach 1.
+ *
+ * @param linearDistance up to this distance progress continues linearly. B in the graph above.
+ * @param maxDistance distance at which the progress will be 1f. A in the graph above.
+ * @param nonLinearFactor This value is used to calculate the target if the screen is wider
+ * than the progress threshold.
*/
- void setSwipeThresholds(float progressThreshold);
+ void setSwipeThresholds(float linearDistance, float maxDistance, float nonLinearFactor);
/**
* Sets the system bar listener to control the system bar color.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 6d879b830e2e..bb543f24a8ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -301,9 +301,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
}
@Override
- public void setSwipeThresholds(float progressThreshold) {
+ public void setSwipeThresholds(
+ float linearDistance,
+ float maxDistance,
+ float nonLinearFactor) {
mShellExecutor.execute(() -> BackAnimationController.this.setSwipeThresholds(
- progressThreshold));
+ linearDistance, maxDistance, nonLinearFactor));
}
@Override
@@ -509,7 +512,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
// Constraints - absolute values
float minVelocity = mFlingAnimationUtils.getMinVelocityPxPerSecond();
float maxVelocity = mFlingAnimationUtils.getHighVelocityPxPerSecond();
- float maxX = mTouchTracker.getMaxX(); // px
+ float maxX = mTouchTracker.getMaxDistance(); // px
float maxFlingDistance = maxX * MAX_FLING_PROGRESS; // px
// Current state
@@ -605,8 +608,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mTouchTracker.setTriggerBack(triggerBack);
}
- private void setSwipeThresholds(float progressThreshold) {
- mTouchTracker.setProgressThreshold(progressThreshold);
+ private void setSwipeThresholds(
+ float linearDistance,
+ float maxDistance,
+ float nonLinearFactor) {
+ mTouchTracker.setProgressThresholds(linearDistance, maxDistance, nonLinearFactor);
}
private void invokeOrCancelBack() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index 7a00f5b9bab4..a0ada39b459e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -28,11 +28,13 @@ import android.window.BackMotionEvent;
* Helper class to record the touch location for gesture and generate back events.
*/
class TouchTracker {
- private static final String PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP =
- "persist.wm.debug.predictive_back_progress_threshold";
- private static final int PROGRESS_THRESHOLD = SystemProperties
- .getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1);
- private float mProgressThreshold;
+ private static final String PREDICTIVE_BACK_LINEAR_DISTANCE_PROP =
+ "persist.wm.debug.predictive_back_linear_distance";
+ private static final int LINEAR_DISTANCE = SystemProperties
+ .getInt(PREDICTIVE_BACK_LINEAR_DISTANCE_PROP, -1);
+ private float mLinearDistance = LINEAR_DISTANCE;
+ private float mMaxDistance;
+ private float mNonLinearFactor;
/**
* Location of the latest touch event
*/
@@ -125,17 +127,42 @@ class TouchTracker {
// the location everytime back is restarted after being cancelled.
float startX = mTriggerBack ? mInitTouchX : mStartThresholdX;
float deltaX = Math.abs(startX - touchX);
- float maxX = getMaxX();
- maxX = maxX == 0 ? 1 : maxX;
- return MathUtils.constrain(deltaX / maxX, 0, 1);
+ float linearDistance = mLinearDistance;
+ float maxDistance = getMaxDistance();
+ maxDistance = maxDistance == 0 ? 1 : maxDistance;
+ float progress;
+ if (linearDistance < maxDistance) {
+ // Up to linearDistance it behaves linearly, then slowly reaches 1f.
+
+ // maxDistance is composed of linearDistance + nonLinearDistance
+ float nonLinearDistance = maxDistance - linearDistance;
+ float initialTarget = linearDistance + nonLinearDistance * mNonLinearFactor;
+
+ boolean isLinear = deltaX <= linearDistance;
+ if (isLinear) {
+ progress = deltaX / initialTarget;
+ } else {
+ float nonLinearDeltaX = deltaX - linearDistance;
+ float nonLinearProgress = nonLinearDeltaX / nonLinearDistance;
+ float currentTarget = MathUtils.lerp(
+ /* start = */ initialTarget,
+ /* stop = */ maxDistance,
+ /* amount = */ nonLinearProgress);
+ progress = deltaX / currentTarget;
+ }
+ } else {
+ // Always linear behavior.
+ progress = deltaX / maxDistance;
+ }
+ return MathUtils.constrain(progress, 0, 1);
}
/**
- * Maximum X value (in pixels).
+ * Maximum distance in pixels.
* Progress is considered to be completed (1f) when this limit is exceeded.
*/
- float getMaxX() {
- return PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold;
+ float getMaxDistance() {
+ return mMaxDistance;
}
BackMotionEvent createProgressEvent(float progress) {
@@ -149,7 +176,14 @@ class TouchTracker {
/* departingAnimationTarget = */ null);
}
- public void setProgressThreshold(float progressThreshold) {
- mProgressThreshold = progressThreshold;
+ public void setProgressThresholds(float linearDistance, float maxDistance,
+ float nonLinearFactor) {
+ if (LINEAR_DISTANCE >= 0) {
+ mLinearDistance = LINEAR_DISTANCE;
+ } else {
+ mLinearDistance = linearDistance;
+ }
+ mMaxDistance = maxDistance;
+ mNonLinearFactor = nonLinearFactor;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 698681029595..3eb9fa2eef6b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -17,18 +17,12 @@
package com.android.wm.shell.bubbles;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS;
-import static android.content.pm.ActivityInfo.CONFIG_DENSITY;
-import static android.content.pm.ActivityInfo.CONFIG_FONT_SCALE;
-import static android.content.pm.ActivityInfo.CONFIG_LAYOUT_DIRECTION;
-import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
@@ -53,7 +47,6 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
-import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -81,6 +74,7 @@ import android.util.Pair;
import android.util.SparseArray;
import android.view.IWindowManager;
import android.view.SurfaceControl;
+import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowInsets;
@@ -108,7 +102,6 @@ import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
-import com.android.wm.shell.common.annotations.ExternalMainThread;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
@@ -116,6 +109,7 @@ import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
+import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
@@ -141,7 +135,7 @@ import java.util.function.IntConsumer;
*
* The controller manages addition, removal, and visible state of bubbles on screen.
*/
-public class BubbleController implements ComponentCallbacks2,
+public class BubbleController implements ConfigurationChangeListener,
RemoteCallable<BubbleController> {
private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
@@ -159,6 +153,7 @@ public class BubbleController implements ComponentCallbacks2,
private static final boolean BUBBLE_BAR_ENABLED =
SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
+
/**
* Common interface to send updates to bubble views.
*/
@@ -242,17 +237,17 @@ public class BubbleController implements ComponentCallbacks2,
/** Whether or not the BubbleStackView has been added to the WindowManager. */
private boolean mAddedToWindowManager = false;
- /**
- * Saved configuration, used to detect changes in
- * {@link #onConfigurationChanged(Configuration)}
- */
- private final Configuration mLastConfiguration = new Configuration();
+ /** Saved screen density, used to detect display size changes in {@link #onConfigChanged}. */
+ private int mDensityDpi = Configuration.DENSITY_DPI_UNDEFINED;
- /**
- * Saved screen bounds, used to detect screen size changes in
- * {@link #onConfigurationChanged(Configuration)}.
- */
- private final Rect mScreenBounds = new Rect();
+ /** Saved screen bounds, used to detect screen size changes in {@link #onConfigChanged}. **/
+ private Rect mScreenBounds = new Rect();
+
+ /** Saved font scale, used to detect font size changes in {@link #onConfigChanged}. */
+ private float mFontScale = 0;
+
+ /** Saved direction, used to detect layout direction changes @link #onConfigChanged}. */
+ private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;
/** Saved insets, used to detect WindowInset changes. */
private WindowInsets mWindowInsets;
@@ -298,8 +293,7 @@ public class BubbleController implements ComponentCallbacks2,
TaskViewTransitions taskViewTransitions,
SyncTransactionQueue syncQueue,
IWindowManager wmService) {
- mContext = context.createWindowContext(TYPE_APPLICATION_OVERLAY, null);
- mLastConfiguration.setTo(mContext.getResources().getConfiguration());
+ mContext = context;
mShellCommandHandler = shellCommandHandler;
mShellController = shellController;
mLauncherApps = launcherApps;
@@ -323,11 +317,11 @@ public class BubbleController implements ComponentCallbacks2,
mBubblePositioner = positioner;
mBubbleData = data;
mSavedUserBubbleData = new SparseArray<>();
- mBubbleIconFactory = new BubbleIconFactory(mContext,
- mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
- mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
- mContext.getResources().getColor(R.color.important_conversation),
- mContext.getResources().getDimensionPixelSize(
+ mBubbleIconFactory = new BubbleIconFactory(context,
+ context.getResources().getDimensionPixelSize(R.dimen.bubble_size),
+ context.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
+ context.getResources().getColor(R.color.important_conversation),
+ context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width));
mDisplayController = displayController;
mTaskViewTransitions = taskViewTransitions;
@@ -488,6 +482,7 @@ public class BubbleController implements ComponentCallbacks2,
}
mCurrentProfiles = userProfiles;
+ mShellController.addConfigurationChangeListener(this);
mShellController.addExternalInterface(KEY_EXTRA_SHELL_BUBBLES,
this::createExternalInterface, this);
mShellCommandHandler.addDumpCallback(this::dump, this);
@@ -779,7 +774,6 @@ public class BubbleController implements ComponentCallbacks2,
try {
mAddedToWindowManager = true;
registerBroadcastReceiver();
- mContext.registerComponentCallbacks(this);
mBubbleData.getOverflow().initialize(this);
// (TODO: b/273314541) some duplication in the inset listener
if (isShowingAsBubbleBar()) {
@@ -837,7 +831,6 @@ public class BubbleController implements ComponentCallbacks2,
// Put on background for this binder call, was causing jank
mBackgroundExecutor.execute(() -> {
try {
- mContext.unregisterComponentCallbacks(this);
mContext.unregisterReceiver(mBroadcastReceiver);
} catch (IllegalArgumentException e) {
// Not sure if this happens in production, but was happening in tests
@@ -937,7 +930,8 @@ public class BubbleController implements ComponentCallbacks2,
mSavedUserBubbleData.remove(userId);
}
- private void onThemeChanged() {
+ @Override
+ public void onThemeChanged() {
if (mStackView != null) {
mStackView.onThemeChanged();
}
@@ -969,60 +963,34 @@ public class BubbleController implements ComponentCallbacks2,
}
}
- // Note: Component callbacks are always called on the main thread of the process
- @ExternalMainThread
@Override
public void onConfigurationChanged(Configuration newConfig) {
- mMainExecutor.execute(() -> {
- final int diff = newConfig.diff(mLastConfiguration);
- final boolean themeChanged = (diff & CONFIG_ASSETS_PATHS) != 0
- || (diff & CONFIG_UI_MODE) != 0;
- if (themeChanged) {
- onThemeChanged();
- }
- if (mBubblePositioner != null) {
- mBubblePositioner.update();
+ if (mBubblePositioner != null) {
+ mBubblePositioner.update();
+ }
+ if (mStackView != null && newConfig != null) {
+ if (newConfig.densityDpi != mDensityDpi
+ || !newConfig.windowConfiguration.getBounds().equals(mScreenBounds)) {
+ mDensityDpi = newConfig.densityDpi;
+ mScreenBounds.set(newConfig.windowConfiguration.getBounds());
+ mBubbleData.onMaxBubblesChanged();
+ mBubbleIconFactory = new BubbleIconFactory(mContext,
+ mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
+ mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
+ mContext.getResources().getColor(R.color.important_conversation),
+ mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.importance_ring_stroke_width));
+ mStackView.onDisplaySizeChanged();
+ }
+ if (newConfig.fontScale != mFontScale) {
+ mFontScale = newConfig.fontScale;
+ mStackView.updateFontScale();
+ }
+ if (newConfig.getLayoutDirection() != mLayoutDirection) {
+ mLayoutDirection = newConfig.getLayoutDirection();
+ mStackView.onLayoutDirectionChanged(mLayoutDirection);
}
- if (mStackView != null) {
- final boolean densityChanged = (diff & CONFIG_DENSITY) != 0;
- final boolean fontScaleChanged = (diff & CONFIG_FONT_SCALE) != 0;
- final boolean layoutDirectionChanged = (diff & CONFIG_LAYOUT_DIRECTION) != 0;
- if (densityChanged
- || !newConfig.windowConfiguration.getBounds().equals(mScreenBounds)) {
- mScreenBounds.set(newConfig.windowConfiguration.getBounds());
- mBubbleData.onMaxBubblesChanged();
- mBubbleIconFactory = new BubbleIconFactory(mContext,
- mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
- mContext.getResources().getDimensionPixelSize(
- R.dimen.bubble_badge_size),
- mContext.getResources().getColor(R.color.important_conversation),
- mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.importance_ring_stroke_width));
- mStackView.onDisplaySizeChanged();
- }
- if (fontScaleChanged) {
- mStackView.updateFontScale();
- }
- if (layoutDirectionChanged) {
- mStackView.onLayoutDirectionChanged(newConfig.getLayoutDirection());
- }
- }
- mLastConfiguration.setTo(newConfig);
- });
- }
-
- // Note: Component callbacks are always called on the main thread of the process
- @ExternalMainThread
- @Override
- public void onTrimMemory(int level) {
- // Do nothing
- }
-
- // Note: Component callbacks are always called on the main thread of the process
- @ExternalMainThread
- @Override
- public void onLowMemory() {
- // Do nothing
+ }
}
private void onNotificationPanelExpandedChanged(boolean expanded) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index adc0c9c4322a..9fcd207dc370 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -46,6 +46,7 @@ import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.PointF;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.os.RemoteException;
@@ -479,13 +480,18 @@ public class BubbleExpandedView extends LinearLayout {
void applyThemeAttrs() {
final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
android.R.attr.dialogCornerRadius,
- com.android.internal.R.attr.materialColorSurfaceBright});
+ com.android.internal.R.attr.materialColorSurfaceBright,
+ com.android.internal.R.attr.materialColorSurfaceContainerHigh});
boolean supportsRoundedCorners = ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
mContext.getResources());
mCornerRadius = supportsRoundedCorners ? ta.getDimensionPixelSize(0, 0) : 0;
mBackgroundColorFloating = ta.getColor(1, Color.WHITE);
mExpandedViewContainer.setBackgroundColor(mBackgroundColorFloating);
+ final int manageMenuBg = ta.getColor(2, Color.WHITE);
ta.recycle();
+ if (mManageButton != null) {
+ mManageButton.getBackground().setColorFilter(manageMenuBg, PorterDuff.Mode.SRC_IN);
+ }
if (mTaskView != null) {
mTaskView.setCornerRadius(mCornerRadius);
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 8e9fc1131e4a..91c7cc0c6e89 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
@@ -38,8 +38,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.Outline;
import android.graphics.PointF;
+import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
@@ -1203,6 +1205,12 @@ public class BubbleStackView extends FrameLayout
R.layout.bubble_manage_menu, this, false);
mManageMenu.setVisibility(View.INVISIBLE);
+ final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
+ com.android.internal.R.attr.materialColorSurfaceBright});
+ final int menuBackgroundColor = ta.getColor(0, Color.WHITE);
+ ta.recycle();
+ mManageMenu.getBackground().setColorFilter(menuBackgroundColor, PorterDuff.Mode.SRC_IN);
+
PhysicsAnimator.getInstance(mManageMenu).setDefaultSpringConfig(mManageSpringConfig);
mManageMenu.setOutlineProvider(new ViewOutlineProvider() {
@@ -1338,7 +1346,7 @@ public class BubbleStackView extends FrameLayout
// Recreates & shows the education views. Call when a theme/config change happens.
private void updateUserEdu() {
- if (isStackEduVisible()) {
+ if (isStackEduVisible() && !mStackEduView.isHiding()) {
removeView(mStackEduView);
mStackEduView = new StackEducationView(mContext, mPositioner, mBubbleController);
addView(mStackEduView);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
index 627273f093f3..d0598cd28582 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/StackEducationView.kt
@@ -37,8 +37,7 @@ class StackEducationView constructor(
context: Context,
positioner: BubblePositioner,
controller: BubbleController
-)
- : LinearLayout(context) {
+) : LinearLayout(context) {
private val TAG = if (BubbleDebugConfig.TAG_WITH_CLASS_NAME) "BubbleStackEducationView"
else BubbleDebugConfig.TAG_BUBBLES
@@ -53,7 +52,8 @@ class StackEducationView constructor(
private val titleTextView by lazy { findViewById<TextView>(R.id.stack_education_title) }
private val descTextView by lazy { findViewById<TextView>(R.id.stack_education_description) }
- private var isHiding = false
+ var isHiding = false
+ private set
init {
LayoutInflater.from(context).inflate(R.layout.bubble_stack_user_education, this)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 9a2ec15238a7..ab8e7e63ef7f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -709,7 +709,8 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange
return context.getSystemService(WindowManager.class)
.getMaximumWindowMetrics()
.getWindowInsets()
- .getInsets(WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout())
+ .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()
+ | WindowInsets.Type.displayCutout())
.toRect();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 74ef57e4baae..5a9c25f7a710 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -732,10 +732,11 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
- static ShellController provideShellController(ShellInit shellInit,
+ static ShellController provideShellController(Context context,
+ ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
@ShellMainThread ShellExecutor mainExecutor) {
- return new ShellController(shellInit, shellCommandHandler, mainExecutor);
+ return new ShellController(context, shellInit, shellCommandHandler, mainExecutor);
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
index 78de5f3e7a1f..3906599b7581 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -57,27 +57,35 @@ interface IPip {
in Rect destinationBounds, in SurfaceControl overlay) = 2;
/**
+ * Notifies the swiping Activity to PiP onto home transition is aborted
+ *
+ * @param taskId the Task id that the Activity and overlay are currently in.
+ * @param componentName ComponentName represents the Activity
+ */
+ oneway void abortSwipePipToHome(int taskId, in ComponentName componentName) = 3;
+
+ /**
* Sets listener to get pinned stack animation callbacks.
*/
- oneway void setPipAnimationListener(IPipAnimationListener listener) = 3;
+ oneway void setPipAnimationListener(IPipAnimationListener listener) = 4;
/**
* Sets the shelf height and visibility.
*/
- oneway void setShelfHeight(boolean visible, int shelfHeight) = 4;
+ oneway void setShelfHeight(boolean visible, int shelfHeight) = 5;
/**
* Sets the next pip animation type to be the alpha animation.
*/
- oneway void setPipAnimationTypeToAlpha() = 5;
+ oneway void setPipAnimationTypeToAlpha() = 6;
/**
* Sets the height and visibility of the Launcher keep clear area.
*/
- oneway void setLauncherKeepClearAreaHeight(boolean visible, int height) = 6;
+ oneway void setLauncherKeepClearAreaHeight(boolean visible, int height) = 7;
/**
* Sets the app icon size in pixel used by Launcher
*/
- oneway void setLauncherAppIconSize(int iconSizePx) = 7;
+ oneway void setLauncherAppIconSize(int iconSizePx) = 8;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index bbfeb90704db..57cc28d1dde5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -328,6 +328,8 @@ public class PipAnimationController {
private PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private @TransitionDirection int mTransitionDirection;
protected PipContentOverlay mContentOverlay;
+ // Flag to avoid double-end
+ private boolean mHasRequestedEnd;
private PipTransitionAnimator(TaskInfo taskInfo, SurfaceControl leash,
@AnimationType int animationType,
@@ -357,6 +359,7 @@ public class PipAnimationController {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
+ if (mHasRequestedEnd) return;
applySurfaceControlTransaction(mLeash,
mSurfaceControlTransactionFactory.getTransaction(),
animation.getAnimatedFraction());
@@ -364,6 +367,8 @@ public class PipAnimationController {
@Override
public void onAnimationEnd(Animator animation) {
+ if (mHasRequestedEnd) return;
+ mHasRequestedEnd = true;
mCurrentValue = mEndValue;
final SurfaceControl.Transaction tx =
mSurfaceControlTransactionFactory.getTransaction();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
index 9fa57cacb11f..c701b9581ca2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipContentOverlay.java
@@ -206,6 +206,7 @@ public abstract class PipContentOverlay {
tx.show(mLeash);
tx.setLayer(mLeash, Integer.MAX_VALUE);
tx.setBuffer(mLeash, mBitmap.getHardwareBuffer());
+ tx.setAlpha(mLeash, 0f);
tx.reparent(mLeash, parentLeash);
tx.apply();
}
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 58bc81dd3007..db7c3fc9c9ec 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
@@ -462,13 +462,29 @@ public class PipTaskOrganizer implements ShellTaskOrganizer.TaskListener,
// to the actual Task surface now.
// PipTransition is responsible to fade it out and cleanup when finishing the enter PIP
// transition.
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ final SurfaceControl.Transaction t = mSurfaceControlTransactionFactory.getTransaction();
mTaskOrganizer.reparentChildSurfaceToTask(taskId, overlay, t);
t.setLayer(overlay, Integer.MAX_VALUE);
t.apply();
}
}
+ /**
+ * Callback when launcher aborts swipe-pip-to-home operation.
+ */
+ public void abortSwipePipToHome(int taskId, ComponentName componentName) {
+ if (!mPipTransitionState.getInSwipePipToHomeTransition()) {
+ return;
+ }
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "Abort swipe-pip-to-home for %s", componentName);
+ sendOnPipTransitionCancelled(TRANSITION_DIRECTION_TO_PIP);
+ // Cleanup internal states
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
+ mPictureInPictureParams = null;
+ mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
+ }
+
public ActivityManager.RunningTaskInfo getTaskInfo() {
return mTaskInfo;
}
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 9677728d1d18..bfc1fb905ade 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
@@ -26,6 +26,7 @@ import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PIP;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.transitTypeToString;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
@@ -92,6 +93,8 @@ public class PipTransition extends PipTransitionController {
private final Rect mExitDestinationBounds = new Rect();
@Nullable
private IBinder mExitTransition;
+ @Nullable
+ private IBinder mMoveToBackTransition;
private IBinder mRequestedEnterTransition;
private WindowContainerToken mRequestedEnterTask;
/** The Task window that is currently in PIP windowing mode. */
@@ -171,9 +174,10 @@ public class PipTransition extends PipTransitionController {
// Exiting PIP.
final int type = info.getType();
- if (transition.equals(mExitTransition)) {
+ if (transition.equals(mExitTransition) || transition.equals(mMoveToBackTransition)) {
mExitDestinationBounds.setEmpty();
mExitTransition = null;
+ mMoveToBackTransition = null;
mHasFadeOut = false;
if (mFinishCallback != null) {
callFinishCallback(null /* wct */);
@@ -201,6 +205,8 @@ public class PipTransition extends PipTransitionController {
startExitToSplitAnimation(info, startTransaction, finishTransaction,
finishCallback, pipTaskInfo);
break;
+ case TRANSIT_TO_BACK:
+ // pass through here is intended
case TRANSIT_REMOVE_PIP:
removePipImmediately(info, startTransaction, finishTransaction, finishCallback,
pipTaskInfo);
@@ -273,6 +279,15 @@ public class PipTransition extends PipTransitionController {
WindowContainerTransaction wct = new WindowContainerTransaction();
augmentRequest(transition, request, wct);
return wct;
+ } else if (request.getType() == TRANSIT_TO_BACK && request.getTriggerTask() != null
+ && request.getTriggerTask().getWindowingMode() == WINDOWING_MODE_PINNED) {
+ // if we receive a TRANSIT_TO_BACK type of request while in PiP
+ mMoveToBackTransition = transition;
+ // update the transition state to avoid {@link PipTaskOrganizer#onTaskVanished()} calls
+ mPipTransitionState.setTransitionState(PipTransitionState.EXITING_PIP);
+
+ // return an empty WindowContainerTransaction so that we don't check other handlers
+ return new WindowContainerTransaction();
} else {
return null;
}
@@ -1015,6 +1030,16 @@ public class PipTransition extends PipTransitionController {
mPipOrganizer.onExitPipFinished(prevPipTaskChange.getTaskInfo());
}
+ @Override
+ public boolean syncPipSurfaceState(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction) {
+ final TransitionInfo.Change pipChange = findCurrentPipTaskChange(info);
+ if (pipChange == null) return false;
+ updatePipForUnhandledTransition(pipChange, startTransaction, finishTransaction);
+ return true;
+ }
+
private void updatePipForUnhandledTransition(@NonNull TransitionInfo.Change pipChange,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction) {
@@ -1025,10 +1050,12 @@ public class PipTransition extends PipTransitionController {
final boolean isInPip = mPipTransitionState.isInPip();
mSurfaceTransactionHelper
.crop(startTransaction, leash, destBounds)
- .round(startTransaction, leash, isInPip);
+ .round(startTransaction, leash, isInPip)
+ .shadow(startTransaction, leash, isInPip);
mSurfaceTransactionHelper
.crop(finishTransaction, leash, destBounds)
- .round(finishTransaction, leash, isInPip);
+ .round(finishTransaction, leash, isInPip)
+ .shadow(finishTransaction, leash, isInPip);
}
/** Hides and shows the existing PIP during fixed rotation transition of other activities. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 949d6f558c32..2fff0e469f3d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -240,6 +240,18 @@ public abstract class PipTransitionController implements Transitions.TransitionH
@NonNull final Transitions.TransitionFinishCallback finishCallback) {
}
+ /**
+ * Applies the proper surface states (rounded corners/shadows) to pip surfaces in `info`.
+ * This is intended to be used when PiP is part of another animation but isn't, itself,
+ * animating (eg. unlocking).
+ * @return `true` if there was a pip in `info`.
+ */
+ public boolean syncPipSurfaceState(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction) {
+ return false;
+ }
+
/** End the currently-playing PiP animation. */
public void end() {
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 9e6bd4760900..63181da46b02 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -1017,6 +1017,10 @@ public class PipController implements PipTransitionController.PipTransitionCallb
mPipTaskOrganizer.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay);
}
+ private void abortSwipePipToHome(int taskId, ComponentName componentName) {
+ mPipTaskOrganizer.abortSwipePipToHome(taskId, componentName);
+ }
+
private String getTransitionTag(int direction) {
switch (direction) {
case TRANSITION_DIRECTION_TO_PIP:
@@ -1313,6 +1317,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb
}
@Override
+ public void abortSwipePipToHome(int taskId, ComponentName componentName) {
+ executeRemoteCallWithTaskPermission(mController, "abortSwipePipToHome",
+ (controller) -> controller.abortSwipePipToHome(taskId, componentName));
+ }
+
+ @Override
public void setShelfHeight(boolean visible, int height) {
executeRemoteCallWithTaskPermission(mController, "setShelfHeight",
(controller) -> controller.setShelfHeight(visible, height));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index d07641892552..613791ccc062 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -31,12 +31,19 @@ import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_MOVE_MENU;
import static com.android.wm.shell.pip.tv.TvPipMenuController.MODE_NO_MENU;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Outline;
+import android.graphics.Path;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.PathShape;
import android.os.Handler;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -91,6 +98,8 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L
private final ImageView mArrowLeft;
private final TvWindowMenuActionButton mA11yDoneButton;
+ private final int mArrowElevation;
+
private @TvPipMenuController.TvPipMenuMode int mCurrentMenuMode = MODE_NO_MENU;
private final Rect mCurrentPipBounds = new Rect();
private int mCurrentPipGravity;
@@ -131,21 +140,70 @@ public class TvPipMenuView extends FrameLayout implements TvPipActionsProvider.L
mArrowLeft = findViewById(R.id.tv_pip_menu_arrow_left);
mA11yDoneButton = findViewById(R.id.tv_pip_menu_done_button);
- mResizeAnimationDuration = context.getResources().getInteger(
- R.integer.config_pipResizeAnimationDuration);
- mPipMenuFadeAnimationDuration = context.getResources()
- .getInteger(R.integer.tv_window_menu_fade_animation_duration);
+ final Resources res = context.getResources();
+ mResizeAnimationDuration = res.getInteger(R.integer.config_pipResizeAnimationDuration);
+ mPipMenuFadeAnimationDuration =
+ res.getInteger(R.integer.tv_window_menu_fade_animation_duration);
+ mPipMenuOuterSpace = res.getDimensionPixelSize(R.dimen.pip_menu_outer_space);
+ mPipMenuBorderWidth = res.getDimensionPixelSize(R.dimen.pip_menu_border_width);
+ mArrowElevation = res.getDimensionPixelSize(R.dimen.pip_menu_arrow_elevation);
- mPipMenuOuterSpace = context.getResources()
- .getDimensionPixelSize(R.dimen.pip_menu_outer_space);
- mPipMenuBorderWidth = context.getResources()
- .getDimensionPixelSize(R.dimen.pip_menu_border_width);
+ initMoveArrows();
mEduTextDrawer = new TvPipMenuEduTextDrawer(mContext, mainHandler, this);
mEduTextContainer = (ViewGroup) findViewById(R.id.tv_pip_menu_edu_text_container);
mEduTextContainer.addView(mEduTextDrawer);
}
+ private void initMoveArrows() {
+ final int arrowSize =
+ mContext.getResources().getDimensionPixelSize(R.dimen.pip_menu_arrow_size);
+ final Path arrowPath = createArrowPath(arrowSize);
+
+ final ShapeDrawable arrowDrawable = new ShapeDrawable();
+ arrowDrawable.setShape(new PathShape(arrowPath, arrowSize, arrowSize));
+ arrowDrawable.setTint(mContext.getResources().getColor(R.color.tv_pip_menu_arrow_color));
+
+ final ViewOutlineProvider arrowOutlineProvider = new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setPath(createArrowPath(view.getMeasuredHeight()));
+ }
+ };
+
+ initArrow(mArrowRight, arrowOutlineProvider, arrowDrawable, 0);
+ initArrow(mArrowDown, arrowOutlineProvider, arrowDrawable, 90);
+ initArrow(mArrowLeft, arrowOutlineProvider, arrowDrawable, 180);
+ initArrow(mArrowUp, arrowOutlineProvider, arrowDrawable, 270);
+ }
+
+ /**
+ * Creates a Path for a movement arrow in the MODE_MOVE_MENU. The resulting Path is a simple
+ * right-pointing triangle with its tip in the center of a size x size square:
+ * _ _ _ _ _
+ * |* |
+ * |* * |
+ * |* * |
+ * |* * |
+ * |* _ _ _ _|
+ *
+ */
+ private Path createArrowPath(int size) {
+ final Path triangle = new Path();
+ triangle.lineTo(0, size);
+ triangle.lineTo(size / 2, size / 2);
+ triangle.close();
+ return triangle;
+ }
+
+ private void initArrow(View v, ViewOutlineProvider arrowOutlineProvider, Drawable arrowDrawable,
+ int rotation) {
+ v.setOutlineProvider(arrowOutlineProvider);
+ v.setBackground(arrowDrawable);
+ v.setRotation(rotation);
+ v.setElevation(mArrowElevation);
+ }
+
void onPipTransitionToTargetBoundsStarted(Rect targetBounds) {
if (targetBounds == null) {
return;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 387d39056ffc..a9ad3c90949f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -301,7 +301,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
try {
for (int i = 0; i < mPausingTasks.size(); ++i) {
snapshots[i] = ActivityTaskManager.getService().takeTaskSnapshot(
- mPausingTasks.get(0).mTaskInfo.taskId);
+ mPausingTasks.get(0).mTaskInfo.taskId, false /* updateCache */);
}
} catch (RemoteException e) {
taskIds = null;
@@ -671,7 +671,8 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler {
try {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.screenshotTask: taskId=%d", mInstanceId, taskId);
- return ActivityTaskManager.getService().takeTaskSnapshot(taskId);
+ return ActivityTaskManager.getService().takeTaskSnapshot(taskId,
+ true /* updateCache */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to screenshot task", e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 38c420a15231..14ea86a8c0e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -20,8 +20,9 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
+import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
import static com.android.wm.shell.common.split.SplitScreenConstants.FADE_DURATION;
import static com.android.wm.shell.common.split.SplitScreenConstants.FLAG_IS_DIVIDER_BAR;
import static com.android.wm.shell.splitscreen.SplitScreen.stageTypeToString;
@@ -86,6 +87,7 @@ class SplitScreenTransitions {
mStageCoordinator = stageCoordinator;
}
+ /** Play animation for enter transition or dismiss transition. */
void playAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@@ -116,6 +118,7 @@ class SplitScreenTransitions {
playInternalAnimation(transition, info, startTransaction, mainRoot, sideRoot, topRoot);
}
+ /** Internal funcation of playAnimation. */
private void playInternalAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull WindowContainerToken mainRoot,
@NonNull WindowContainerToken sideRoot, @NonNull WindowContainerToken topRoot) {
@@ -126,8 +129,8 @@ class SplitScreenTransitions {
final SurfaceControl leash = change.getLeash();
final int mode = info.getChanges().get(i).getMode();
+ final int rootIdx = TransitionUtil.rootIndexFor(change, info);
if (mode == TRANSIT_CHANGE) {
- final int rootIdx = TransitionUtil.rootIndexFor(change, info);
if (change.getParent() != null) {
// This is probably reparented, so we want the parent to be immediately visible
final TransitionInfo.Change parentChange = info.getChange(change.getParent());
@@ -155,7 +158,7 @@ class SplitScreenTransitions {
mFinishTransaction.setPosition(leash,
change.getEndRelOffset().x, change.getEndRelOffset().y);
mFinishTransaction.setCrop(leash, null);
- } else if (isEnter && isTopRoot) {
+ } else if (isTopRoot) {
// Ensure top root is visible at start.
t.setAlpha(leash, 1.f);
t.show(leash);
@@ -168,40 +171,56 @@ class SplitScreenTransitions {
t.setLayer(leash, Integer.MAX_VALUE);
t.show(leash);
}
- // These container changes we don't want to animate them.
- // We should only animate stage root, divider and child tasks are not under stage root.
- if (isTopRoot || isMainChild || isSideChild || change.getTaskInfo() == null) {
+
+ // We want to use child tasks to animate so ignore split root container and non task
+ // except divider change.
+ if (isTopRoot || isMainRoot || isSideRoot
+ || (change.getTaskInfo() == null && !isDivider)) {
continue;
}
-
if (isEnter && mPendingEnter.mResizeAnim) {
// We will run animation in next transition so skip anim here
continue;
- } else if (isEnter && isMainRoot) {
- // Main stage already on top so skip fade in animation to reduce flicker.
+ } else if (isPendingDismiss(transition)
+ && mPendingDismiss.mReason == EXIT_REASON_DRAG_DIVIDER) {
+ // TODO(b/280020345): need to refine animation for this but just skip anim now.
continue;
}
+ // Because cross fade might be looked more flicker during animation
+ // (surface become black in middle of animation), we only do fade-out
+ // and show opening surface directly.
boolean isOpening = TransitionUtil.isOpeningType(info.getType());
- if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
- // fade in
- startFadeAnimation(leash, true /* show */);
- } else if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
+ if (!isOpening && (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK)) {
// fade out
- if (info.getType() == TRANSIT_SPLIT_DISMISS_SNAP) {
- // Dismissing via snap-to-top/bottom means that the dismissed task is already
- // not-visible (usually cropped to oblivion) so immediately set its alpha to 0
- // and don't animate it so it doesn't pop-in when reparented.
- t.setAlpha(leash, 0.f);
+ if (change.getSnapshot() != null) {
+ // This case is happened if task is going to reparent to TDA, the origin leash
+ // doesn't rendor so we use snapshot to replace it animating.
+ t.reparent(change.getSnapshot(), info.getRoot(rootIdx).getLeash());
+ // Use origin leash layer.
+ t.setLayer(change.getSnapshot(), info.getChanges().size() - i);
+ t.setPosition(change.getSnapshot(), change.getStartAbsBounds().left,
+ change.getStartAbsBounds().top);
+ t.show(change.getSnapshot());
+ startFadeAnimation(change.getSnapshot(), false /* show */);
} else {
startFadeAnimation(leash, false /* show */);
}
+ } else if (mode == TRANSIT_CHANGE && change.getSnapshot() != null) {
+ t.reparent(change.getSnapshot(), info.getRoot(rootIdx).getLeash());
+ // Ensure snapshot it on the top of all transition surfaces
+ t.setLayer(change.getSnapshot(), info.getChanges().size() + 1);
+ t.setPosition(change.getSnapshot(), change.getStartAbsBounds().left,
+ change.getStartAbsBounds().top);
+ t.show(change.getSnapshot());
+ startFadeAnimation(change.getSnapshot(), false /* show */);
}
}
t.apply();
onFinish(null /* wct */, null /* wctCB */);
}
+ /** Play animation for resize transition. */
void playResizeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@@ -437,6 +456,7 @@ class SplitScreenTransitions {
final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
final ValueAnimator va = ValueAnimator.ofFloat(start, end);
va.setDuration(FADE_DURATION);
+ va.setInterpolator(show ? ALPHA_IN : ALPHA_OUT);
va.addUpdateListener(animation -> {
float fraction = animation.getAnimatedFraction();
transaction.setAlpha(leash, start * (1.f - fraction) + end * fraction);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 087e3a2384d6..bf20567834e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -582,7 +582,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
- prepareEvictChildTasksIfSplitActive(wct);
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
@@ -604,7 +603,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
- prepareEvictChildTasksIfSplitActive(wct);
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
@@ -625,7 +623,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
return;
}
- prepareEvictChildTasksIfSplitActive(wct);
setSideStagePosition(splitPosition, wct);
options1 = options1 != null ? options1 : new Bundle();
addActivityOptions(options1, mSideStage);
@@ -691,7 +688,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mMainStage.activate(wct, false /* reparent */);
}
- prepareEvictChildTasksIfSplitActive(wct);
mSplitLayout.setDivideRatio(splitRatio);
updateWindowBounds(mSplitLayout, wct);
wct.reorder(mRootTaskInfo.token, true);
@@ -1075,24 +1071,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
- prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct);
- prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct);
+ mMainStage.evictNonOpeningChildren(apps, evictWct);
+ mSideStage.evictNonOpeningChildren(apps, evictWct);
mSyncQueue.queue(evictWct);
}
-
- /**
- * Collects all the current child tasks of a specific split and prepares transaction to evict
- * them to display.
- */
- void prepareEvictChildTasks(@SplitPosition int position, WindowContainerTransaction wct) {
- if (position == mSideStagePosition) {
- mSideStage.evictAllChildren(wct);
- } else {
- mMainStage.evictAllChildren(wct);
- }
- }
-
void prepareEvictNonOpeningChildTasks(@SplitPosition int position, RemoteAnimationTarget[] apps,
WindowContainerTransaction wct) {
if (position == mSideStagePosition) {
@@ -1107,13 +1090,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSideStage.evictInvisibleChildren(wct);
}
- void prepareEvictChildTasksIfSplitActive(WindowContainerTransaction wct) {
- if (mMainStage.isActive()) {
- mMainStage.evictAllChildren(wct);
- mSideStage.evictAllChildren(wct);
- }
- }
-
Bundle resolveStartStage(@StageType int stage, @SplitPosition int position,
@Nullable Bundle options, @Nullable WindowContainerTransaction wct) {
switch (stage) {
@@ -1500,10 +1476,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
wct.startTask(taskInfo.taskId,
resolveStartStage(STAGE_TYPE_UNDEFINED, startPosition, null, wct));
}
- // If running background, we need to reparent current top visible task to another stage
- // and evict all tasks current under its.
+ // If running background, we need to reparent current top visible task to main stage.
if (!isSplitScreenVisible()) {
- // Recreate so we need to reset position rather than keep position of background split.
mMainStage.reparentTopTask(wct);
prepareSplitLayout(wct);
}
@@ -2061,18 +2035,16 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// Reset this flag every time onLayoutSizeChanged.
mShowDecorImmediately = false;
- if (!ENABLE_SHELL_TRANSITIONS) {
- // Only need screenshot for legacy case because shell transition should screenshot
- // itself during transition.
- final SurfaceControl.Transaction startT = mTransactionPool.acquire();
- mMainStage.screenshotIfNeeded(startT);
- mSideStage.screenshotIfNeeded(startT);
- mTransactionPool.release(startT);
- }
-
final WindowContainerTransaction wct = new WindowContainerTransaction();
boolean sizeChanged = updateWindowBounds(layout, wct);
- if (!sizeChanged) return;
+ if (!sizeChanged) {
+ // We still need to resize on decor for ensure all current status clear.
+ final SurfaceControl.Transaction t = mTransactionPool.acquire();
+ mMainStage.onResized(t);
+ mSideStage.onResized(t);
+ mTransactionPool.release(t);
+ return;
+ }
sendOnBoundsChanged();
if (ENABLE_SHELL_TRANSITIONS) {
@@ -2080,6 +2052,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitTransitions.startResizeTransition(wct, this, (finishWct, t) ->
mSplitLayout.setDividerInteractive(true, false, "onSplitResizeFinish"));
} else {
+ // Only need screenshot for legacy case because shell transition should screenshot
+ // itself during transition.
+ final SurfaceControl.Transaction startT = mTransactionPool.acquire();
+ mMainStage.screenshotIfNeeded(startT);
+ mSideStage.screenshotIfNeeded(startT);
+ mTransactionPool.release(startT);
+
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
updateSurfaceBounds(layout, t, false /* applyResizingOffset */);
@@ -2337,7 +2316,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
prepareEnterSplitScreen(out);
mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
null /* consumedCallback */, null /* finishedCallback */,
- 0 /* extraTransitType */, !mIsDropEntering);
+ TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, !mIsDropEntering);
}
}
return out;
@@ -2604,7 +2583,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
== TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
if (mainChild == null && sideChild == null) {
Log.w(TAG, "Launched a task in split, but didn't receive any task in transition.");
- mSplitTransitions.mPendingEnter.cancel(null /* finishedCb */);
+ mSplitTransitions.mPendingEnter.cancel((cancelWct, cancelT)
+ -> prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, cancelWct));
return true;
}
} else {
@@ -2614,10 +2594,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final int dismissTop = mainChild != null ? STAGE_TYPE_MAIN :
(sideChild != null ? STAGE_TYPE_SIDE : STAGE_TYPE_UNDEFINED);
mSplitTransitions.mPendingEnter.cancel(
- (cancelWct, cancelT) -> {
- mSideStage.removeAllTasks(cancelWct, dismissTop == STAGE_TYPE_SIDE);
- mMainStage.deactivate(cancelWct, dismissTop == STAGE_TYPE_MAIN);
- });
+ (cancelWct, cancelT) -> prepareExitSplitScreen(dismissTop, cancelWct));
return true;
}
}
@@ -2626,14 +2603,19 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
// transitions locally, but remotes (like Launcher) may get confused if they were
// depending on listener callbacks. This can happen because task-organizer callbacks
// aren't serialized with transition callbacks.
+ // This usually occurred on app use trampoline launch new task and finish itself.
// TODO(b/184679596): Find a way to either include task-org information in
// the transition, or synchronize task-org callbacks.
- if (mainChild != null && !mMainStage.containsTask(mainChild.getTaskInfo().taskId)) {
+ final boolean mainNotContainOpenTask =
+ mainChild != null && !mMainStage.containsTask(mainChild.getTaskInfo().taskId);
+ final boolean sideNotContainOpenTask =
+ sideChild != null && !mSideStage.containsTask(sideChild.getTaskInfo().taskId);
+ if (mainNotContainOpenTask) {
Log.w(TAG, "Expected onTaskAppeared on " + mMainStage
+ " to have been called with " + mainChild.getTaskInfo().taskId
+ " before startAnimation().");
}
- if (sideChild != null && !mSideStage.containsTask(sideChild.getTaskInfo().taskId)) {
+ if (sideNotContainOpenTask) {
Log.w(TAG, "Expected onTaskAppeared on " + mSideStage
+ " to have been called with " + sideChild.getTaskInfo().taskId
+ " before startAnimation().");
@@ -2642,10 +2624,18 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final TransitionInfo.Change finalSideChild = sideChild;
enterTransition.setFinishedCallback((callbackWct, callbackT) -> {
if (finalMainChild != null) {
- mMainStage.evictOtherChildren(callbackWct, finalMainChild.getTaskInfo().taskId);
+ if (!mainNotContainOpenTask) {
+ mMainStage.evictOtherChildren(callbackWct, finalMainChild.getTaskInfo().taskId);
+ } else {
+ mMainStage.evictInvisibleChildren(callbackWct);
+ }
}
if (finalSideChild != null) {
- mSideStage.evictOtherChildren(callbackWct, finalSideChild.getTaskInfo().taskId);
+ if (!sideNotContainOpenTask) {
+ mSideStage.evictOtherChildren(callbackWct, finalSideChild.getTaskInfo().taskId);
+ } else {
+ mSideStage.evictInvisibleChildren(callbackWct);
+ }
}
if (enterTransition.mResizeAnim) {
mShowDecorImmediately = true;
@@ -2904,9 +2894,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
if (!isSplitScreenVisible()) {
mIsDropEntering = true;
}
- if (!isSplitScreenVisible()) {
+ if (!isSplitScreenVisible() && !ENABLE_SHELL_TRANSITIONS) {
// If split running background, exit split first.
- // TODO(b/280392203) : skip doing this on shell transition once this bug is fixed.
+ // Skip this on shell transition due to we could evict existing tasks on transition
+ // finished.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
}
mLogger.enterRequestedByDrag(position, dragSessionId);
@@ -2916,9 +2907,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
* Sets info to be logged when splitscreen is next entered.
*/
public void onRequestToSplit(InstanceId sessionId, int enterReason) {
- if (!isSplitScreenVisible()) {
+ if (!isSplitScreenVisible() && !ENABLE_SHELL_TRANSITIONS) {
// If split running background, exit split first.
- // TODO(b/280392203) : skip doing this on shell transition once this bug is fixed.
+ // Skip this on shell transition due to we could evict existing tasks on transition
+ // finished.
exitSplitScreen(null /* childrenToTop */, EXIT_REASON_RECREATE_SPLIT);
}
mLogger.enterRequested(sessionId, enterReason);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
index 3f944cb6d628..0eb7c2d98e0a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
@@ -32,6 +32,7 @@ import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.ArrayMap;
+import android.view.SurfaceControlRegistry;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -52,6 +53,7 @@ import java.util.function.Supplier;
public class ShellController {
private static final String TAG = ShellController.class.getSimpleName();
+ private final Context mContext;
private final ShellInit mShellInit;
private final ShellCommandHandler mShellCommandHandler;
private final ShellExecutor mMainExecutor;
@@ -72,8 +74,11 @@ public class ShellController {
private Configuration mLastConfiguration;
- public ShellController(ShellInit shellInit, ShellCommandHandler shellCommandHandler,
+ public ShellController(Context context,
+ ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
ShellExecutor mainExecutor) {
+ mContext = context;
mShellInit = shellInit;
mShellCommandHandler = shellCommandHandler;
mMainExecutor = mainExecutor;
@@ -254,6 +259,16 @@ public class ShellController {
}
}
+ private void handleInit() {
+ SurfaceControlRegistry.createProcessInstance(mContext);
+ mShellInit.init();
+ }
+
+ private void handleDump(PrintWriter pw) {
+ mShellCommandHandler.dump(pw);
+ SurfaceControlRegistry.dump(100 /* limit */, false /* runGc */, pw);
+ }
+
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
@@ -279,7 +294,7 @@ public class ShellController {
@Override
public void onInit() {
try {
- mMainExecutor.executeBlocking(() -> mShellInit.init());
+ mMainExecutor.executeBlocking(() -> ShellController.this.handleInit());
} catch (InterruptedException e) {
throw new RuntimeException("Failed to initialize the Shell in 2s", e);
}
@@ -344,7 +359,7 @@ public class ShellController {
@Override
public void dump(PrintWriter pw) {
try {
- mMainExecutor.executeBlocking(() -> mShellCommandHandler.dump(pw));
+ mMainExecutor.executeBlocking(() -> ShellController.this.handleDump(pw));
} catch (InterruptedException e) {
throw new RuntimeException("Failed to dump the Shell in 2s", e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 42633b722649..863b5ab73a7d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -304,8 +304,8 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
return animateRecentsDuringSplit(mixed, info, startTransaction, finishTransaction,
finishCallback);
} else if (mixed.mType == MixedTransition.TYPE_KEYGUARD) {
- return mKeyguardHandler.startAnimation(
- transition, info, startTransaction, finishTransaction, finishCallback);
+ return animateKeyguard(mixed, info, startTransaction, finishTransaction,
+ finishCallback);
} else {
mActiveTransitions.remove(mixed);
throw new IllegalStateException("Starting mixed animation without a known mixed type? "
@@ -557,6 +557,27 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
return handled;
}
+ private boolean animateKeyguard(@NonNull final MixedTransition mixed,
+ @NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ boolean consumed = mKeyguardHandler.startAnimation(
+ mixed.mTransition, info, startTransaction, finishTransaction, finishCallback);
+ if (!consumed) {
+ return false;
+ }
+ // Sync pip state.
+ if (mPipHandler != null) {
+ // We don't know when to apply `startTransaction` so use a separate transaction here.
+ // This should be fine because these surface properties are independent.
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ mPipHandler.syncPipSurfaceState(info, t, finishTransaction);
+ t.apply();
+ }
+ return true;
+ }
+
@Override
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index f33b0778a1b2..d16b497b5aca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -492,6 +492,10 @@ public class Transitions implements RemoteCallable<Transitions>,
finishT.show(leash);
} else if (mode == TRANSIT_CLOSE || mode == TRANSIT_TO_BACK) {
finishT.hide(leash);
+ } else if (isOpening && mode == TRANSIT_CHANGE) {
+ // Just in case there is a race with another animation (eg. recents finish()).
+ // Changes are visible->visible so it's a problem if it isn't visible.
+ t.show(leash);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index 5d7b62905d3b..bb0eba6a0fc7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -18,6 +18,8 @@ package com.android.wm.shell.unfold;
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
+
import android.os.IBinder;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -27,6 +29,7 @@ import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
@@ -36,6 +39,7 @@ import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener;
import com.android.wm.shell.unfold.animation.FullscreenUnfoldTaskAnimator;
import com.android.wm.shell.unfold.animation.SplitTaskUnfoldAnimator;
import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator;
+import com.android.wm.shell.util.TransitionUtil;
import java.util.ArrayList;
import java.util.List;
@@ -105,8 +109,14 @@ public class UnfoldTransitionHandler implements TransitionHandler, UnfoldListene
animator.clearTasks();
info.getChanges().forEach(change -> {
- if (change.getTaskInfo() != null
- && change.getMode() == TRANSIT_CHANGE
+ if (change.getTaskInfo() != null) {
+ ProtoLog.v(WM_SHELL_TRANSITIONS,
+ "startAnimation, check taskInfo: %s, mode: %s, isApplicableTask: %s",
+ change.getTaskInfo(), TransitionInfo.modeToString(change.getMode()),
+ animator.isApplicableTask(change.getTaskInfo()));
+ }
+ if (change.getTaskInfo() != null && (change.getMode() == TRANSIT_CHANGE
+ || TransitionUtil.isOpeningType(change.getMode()))
&& animator.isApplicableTask(change.getTaskInfo())) {
animator.onTaskAppeared(change.getTaskInfo(), change.getLeash());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
index 123bf3bfca2e..a4cf149cc3b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
@@ -213,7 +213,7 @@ public class SplitTaskUnfoldAnimator implements UnfoldTaskAnimator,
@Override
public boolean isApplicableTask(TaskInfo taskInfo) {
return taskInfo.hasParentTask()
- && taskInfo.isVisible
+ && taskInfo.isRunning
&& taskInfo.realActivity != null // to filter out parents created by organizer
&& taskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW;
}
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 6d37e58c59ad..143b42a1ec96 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
@@ -24,9 +24,7 @@ import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -178,7 +176,14 @@ public class TransitionUtil {
}
// Put all the OPEN/SHOW on top
- if (TransitionUtil.isOpeningType(mode)) {
+ if ((change.getFlags() & FLAG_IS_WALLPAPER) != 0) {
+ // Wallpaper is always at the bottom, opening wallpaper on top of closing one.
+ if (mode == WindowManager.TRANSIT_OPEN || mode == WindowManager.TRANSIT_TO_FRONT) {
+ t.setLayer(leash, -zSplitLine + info.getChanges().size() - layer);
+ } else {
+ t.setLayer(leash, -zSplitLine - layer);
+ }
+ } else if (TransitionUtil.isOpeningType(mode)) {
if (isOpening) {
t.setLayer(leash, zSplitLine + info.getChanges().size() - layer);
if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) == 0) {
@@ -312,6 +317,7 @@ public class TransitionUtil {
target.setWillShowImeOnTarget(
(change.getFlags() & TransitionInfo.FLAG_WILL_IME_SHOWN) != 0);
target.setRotationChange(change.getEndRotation() - change.getStartRotation());
+ target.backgroundColor = change.getBackgroundColor();
return target;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
deleted file mode 100644
index d62e6601723a..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.back;
-
-import static org.junit.Assert.assertEquals;
-
-import android.window.BackEvent;
-import android.window.BackMotionEvent;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class TouchTrackerTest {
- private static final float FAKE_THRESHOLD = 400;
- private static final float INITIAL_X_LEFT_EDGE = 5;
- private static final float INITIAL_X_RIGHT_EDGE = FAKE_THRESHOLD - INITIAL_X_LEFT_EDGE;
- private TouchTracker mTouchTracker;
-
- @Before
- public void setUp() throws Exception {
- mTouchTracker = new TouchTracker();
- mTouchTracker.setProgressThreshold(FAKE_THRESHOLD);
- }
-
- @Test
- public void generatesProgress_onStart() {
- mTouchTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0, BackEvent.EDGE_LEFT);
- BackMotionEvent event = mTouchTracker.createStartEvent(null);
- assertEquals(event.getProgress(), 0f, 0f);
- }
-
- @Test
- public void generatesProgress_leftEdge() {
- mTouchTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0, BackEvent.EDGE_LEFT);
- float touchX = 10;
- float velocityX = 0;
- float velocityY = 0;
-
- // Pre-commit
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f);
-
- // Post-commit
- touchX += 100;
- mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f);
-
- // Cancel
- touchX -= 10;
- mTouchTracker.setTriggerBack(false);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Cancel more
- touchX -= 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Restart
- touchX += 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Restarted, but pre-commit
- float restartX = touchX;
- touchX += 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (touchX - restartX) / FAKE_THRESHOLD, 0f);
-
- // Restarted, post-commit
- touchX += 10;
- mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (touchX - INITIAL_X_LEFT_EDGE) / FAKE_THRESHOLD, 0f);
- }
-
- @Test
- public void generatesProgress_rightEdge() {
- mTouchTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0, BackEvent.EDGE_RIGHT);
- float touchX = INITIAL_X_RIGHT_EDGE - 10; // Fake right edge
- float velocityX = 0f;
- float velocityY = 0f;
-
- // Pre-commit
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f);
-
- // Post-commit
- touchX -= 100;
- mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f);
-
- // Cancel
- touchX += 10;
- mTouchTracker.setTriggerBack(false);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Cancel more
- touchX += 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Restart
- touchX -= 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), 0, 0f);
-
- // Restarted, but pre-commit
- float restartX = touchX;
- touchX -= 10;
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (restartX - touchX) / FAKE_THRESHOLD, 0f);
-
- // Restarted, post-commit
- touchX -= 10;
- mTouchTracker.setTriggerBack(true);
- mTouchTracker.update(touchX, 0, velocityX, velocityY);
- assertEquals(getProgress(), (INITIAL_X_RIGHT_EDGE - touchX) / FAKE_THRESHOLD, 0f);
- }
-
- private float getProgress() {
- return mTouchTracker.createProgressEvent().getProgress();
- }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt
new file mode 100644
index 000000000000..9088e8997e79
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.kt
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.back
+
+import android.util.MathUtils
+import android.window.BackEvent
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class TouchTrackerTest {
+ private fun linearTouchTracker(): TouchTracker = TouchTracker().apply {
+ setProgressThresholds(MAX_DISTANCE, MAX_DISTANCE, NON_LINEAR_FACTOR)
+ }
+
+ private fun nonLinearTouchTracker(): TouchTracker = TouchTracker().apply {
+ setProgressThresholds(LINEAR_DISTANCE, MAX_DISTANCE, NON_LINEAR_FACTOR)
+ }
+
+ private fun TouchTracker.assertProgress(expected: Float) {
+ val actualProgress = createProgressEvent().progress
+ assertEquals(expected, actualProgress, /* delta = */ 0f)
+ }
+
+ @Test
+ fun generatesProgress_onStart() {
+ val linearTracker = linearTouchTracker()
+ linearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
+ val event = linearTracker.createStartEvent(null)
+ assertEquals(0f, event.progress, 0f)
+ }
+
+ @Test
+ fun generatesProgress_leftEdge() {
+ val linearTracker = linearTouchTracker()
+ linearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
+ var touchX = 10f
+ val velocityX = 0f
+ val velocityY = 0f
+
+ // Pre-commit
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
+
+ // Post-commit
+ touchX += 100f
+ linearTracker.setTriggerBack(true)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
+
+ // Cancel
+ touchX -= 10f
+ linearTracker.setTriggerBack(false)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Cancel more
+ touchX -= 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Restart
+ touchX += 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Restarted, but pre-commit
+ val restartX = touchX
+ touchX += 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((touchX - restartX) / MAX_DISTANCE)
+
+ // Restarted, post-commit
+ touchX += 10f
+ linearTracker.setTriggerBack(true)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / MAX_DISTANCE)
+ }
+
+ @Test
+ fun generatesProgress_rightEdge() {
+ val linearTracker = linearTouchTracker()
+ linearTracker.setGestureStartLocation(INITIAL_X_RIGHT_EDGE, 0f, BackEvent.EDGE_RIGHT)
+ var touchX = INITIAL_X_RIGHT_EDGE - 10 // Fake right edge
+ val velocityX = 0f
+ val velocityY = 0f
+ val target = MAX_DISTANCE
+
+ // Pre-commit
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
+
+ // Post-commit
+ touchX -= 100f
+ linearTracker.setTriggerBack(true)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
+
+ // Cancel
+ touchX += 10f
+ linearTracker.setTriggerBack(false)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Cancel more
+ touchX += 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Restart
+ touchX -= 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress(0f)
+
+ // Restarted, but pre-commit
+ val restartX = touchX
+ touchX -= 10f
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((restartX - touchX) / target)
+
+ // Restarted, post-commit
+ touchX -= 10f
+ linearTracker.setTriggerBack(true)
+ linearTracker.update(touchX, 0f, velocityX, velocityY)
+ linearTracker.assertProgress((INITIAL_X_RIGHT_EDGE - touchX) / target)
+ }
+
+ @Test
+ fun generatesNonLinearProgress_leftEdge() {
+ val nonLinearTracker = nonLinearTouchTracker()
+ nonLinearTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0f, BackEvent.EDGE_LEFT)
+ var touchX = 10f
+ val velocityX = 0f
+ val velocityY = 0f
+ val linearTarget = LINEAR_DISTANCE + (MAX_DISTANCE - LINEAR_DISTANCE) * NON_LINEAR_FACTOR
+
+ // Pre-commit: linear progress
+ nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
+
+ // Post-commit: still linear progress
+ touchX += 100f
+ nonLinearTracker.setTriggerBack(true)
+ nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
+
+ // still linear progress
+ touchX = INITIAL_X_LEFT_EDGE + LINEAR_DISTANCE
+ nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / linearTarget)
+
+ // non linear progress
+ touchX += 10
+ nonLinearTracker.update(touchX, 0f, velocityX, velocityY)
+ val nonLinearTouch = (touchX - INITIAL_X_LEFT_EDGE) - LINEAR_DISTANCE
+ val nonLinearProgress = nonLinearTouch / NON_LINEAR_DISTANCE
+ val nonLinearTarget = MathUtils.lerp(linearTarget, MAX_DISTANCE, nonLinearProgress)
+ nonLinearTracker.assertProgress((touchX - INITIAL_X_LEFT_EDGE) / nonLinearTarget)
+ }
+
+ companion object {
+ private const val MAX_DISTANCE = 500f
+ private const val LINEAR_DISTANCE = 400f
+ private const val NON_LINEAR_DISTANCE = MAX_DISTANCE - LINEAR_DISTANCE
+ private const val NON_LINEAR_FACTOR = 0.2f
+ private const val INITIAL_X_LEFT_EDGE = 5f
+ private const val INITIAL_X_RIGHT_EDGE = MAX_DISTANCE - INITIAL_X_LEFT_EDGE
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 04f2c99783da..85167cb97501 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -129,7 +129,7 @@ public class PipControllerTest extends ShellTestCase {
return null;
}).when(mMockExecutor).execute(any());
mShellInit = spy(new ShellInit(mMockExecutor));
- mShellController = spy(new ShellController(mShellInit, mMockShellCommandHandler,
+ mShellController = spy(new ShellController(mContext, mShellInit, mMockShellCommandHandler,
mMockExecutor));
mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler,
mShellController, mMockDisplayController, mMockPipAnimationController,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index b542fae060d1..2c69522413d5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -107,7 +107,7 @@ public class RecentTasksControllerTest extends ShellTestCase {
mMainExecutor = new TestShellExecutor();
when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
mShellInit = spy(new ShellInit(mMainExecutor));
- mShellController = spy(new ShellController(mShellInit, mShellCommandHandler,
+ mShellController = spy(new ShellController(mContext, mShellInit, mShellCommandHandler,
mMainExecutor));
mRecentTasksControllerReal = new RecentTasksController(mContext, mShellInit,
mShellController, mShellCommandHandler, mTaskStackListener, mActivityTaskManager,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index c37a497c5d40..9189d3dd0327 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -111,7 +111,7 @@ public class SplitScreenControllerTests extends ShellTestCase {
public void setup() {
assumeTrue(ActivityTaskManager.supportsSplitScreenMultiWindow(mContext));
MockitoAnnotations.initMocks(this);
- mShellController = spy(new ShellController(mShellInit, mShellCommandHandler,
+ mShellController = spy(new ShellController(mContext, mShellInit, mShellCommandHandler,
mMainExecutor));
mSplitScreenController = spy(new SplitScreenController(mContext, mShellInit,
mShellCommandHandler, mShellController, mTaskOrganizer, mSyncQueue,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
index 10dec9ef12f9..a9082a6e2585 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
@@ -81,7 +81,7 @@ public class StartingWindowControllerTests extends ShellTestCase {
doReturn(mock(Display.class)).when(mDisplayManager).getDisplay(anyInt());
doReturn(mDisplayManager).when(mContext).getSystemService(eq(DisplayManager.class));
mShellInit = spy(new ShellInit(mMainExecutor));
- mShellController = spy(new ShellController(mShellInit, mShellCommandHandler,
+ mShellController = spy(new ShellController(mContext, mShellInit, mShellCommandHandler,
mMainExecutor));
mController = new StartingWindowController(mContext, mShellInit, mShellController,
mTaskOrganizer, mMainExecutor, mTypeAlgorithm, mIconProvider, mTransactionPool);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
index 8d92d0864338..7c520c34b29d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
@@ -78,7 +78,7 @@ public class ShellControllerTest extends ShellTestCase {
mConfigChangeListener = new TestConfigurationChangeListener();
mUserChangeListener = new TestUserChangeListener();
mExecutor = new TestShellExecutor();
- mController = new ShellController(mShellInit, mShellCommandHandler, mExecutor);
+ mController = new ShellController(mContext, mShellInit, mShellCommandHandler, mExecutor);
mController.onConfigurationChanged(getConfigurationCopy());
}
diff --git a/libs/hwui/MemoryPolicy.h b/libs/hwui/MemoryPolicy.h
index 139cdde5c0d2..347daf34f52a 100644
--- a/libs/hwui/MemoryPolicy.h
+++ b/libs/hwui/MemoryPolicy.h
@@ -31,6 +31,12 @@ enum class TrimLevel {
RUNNING_MODERATE = 5,
};
+enum class CacheTrimLevel {
+ ALL_CACHES = 0,
+ FONT_CACHE = 1,
+ RESOURCE_CACHE = 2,
+};
+
struct MemoryPolicy {
// The initial scale factor applied to the display resolution. The default is 1, but
// lower values may be used to start with a smaller initial cache size. The cache will
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 6a7411f5d859..d04de37f6961 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -362,6 +362,10 @@ static void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
RenderProxy::trimMemory(level);
}
+static void android_view_ThreadedRenderer_trimCaches(JNIEnv* env, jobject clazz, jint level) {
+ RenderProxy::trimCaches(level);
+}
+
static void android_view_ThreadedRenderer_overrideProperty(JNIEnv* env, jobject clazz,
jstring name, jstring value) {
const char* nameCharArray = env->GetStringUTFChars(name, NULL);
@@ -1018,6 +1022,7 @@ static const JNINativeMethod gMethods[] = {
(void*)android_view_ThreadedRenderer_notifyCallbackPending},
{"nNotifyExpensiveFrame", "(J)V",
(void*)android_view_ThreadedRenderer_notifyExpensiveFrame},
+ {"nTrimCaches", "(I)V", (void*)android_view_ThreadedRenderer_trimCaches},
};
static JavaVM* mJvm = nullptr;
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index c00a2707e0a2..babce88b8e1e 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -139,6 +139,25 @@ void CacheManager::trimMemory(TrimLevel mode) {
}
}
+void CacheManager::trimCaches(CacheTrimLevel mode) {
+ switch (mode) {
+ case CacheTrimLevel::FONT_CACHE:
+ SkGraphics::PurgeFontCache();
+ break;
+ case CacheTrimLevel::RESOURCE_CACHE:
+ SkGraphics::PurgeResourceCache();
+ break;
+ case CacheTrimLevel::ALL_CACHES:
+ SkGraphics::PurgeAllCaches();
+ if (mGrContext) {
+ mGrContext->purgeUnlockedResources(false);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
void CacheManager::trimStaleResources() {
if (!mGrContext) {
return;
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index d21ac9badc43..5e43ac209696 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -48,6 +48,7 @@ public:
void configureContext(GrContextOptions* context, const void* identity, ssize_t size);
#endif
void trimMemory(TrimLevel mode);
+ void trimCaches(CacheTrimLevel mode);
void trimStaleResources();
void dumpMemoryUsage(String8& log, const RenderState* renderState = nullptr);
void getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 31b4b203c670..224c878bf43d 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -231,6 +231,15 @@ void RenderProxy::trimMemory(int level) {
}
}
+void RenderProxy::trimCaches(int level) {
+ // Avoid creating a RenderThread to do a trimMemory.
+ if (RenderThread::hasInstance()) {
+ RenderThread& thread = RenderThread::getInstance();
+ const auto trimLevel = static_cast<CacheTrimLevel>(level);
+ thread.queue().post([&thread, trimLevel]() { thread.trimCaches(trimLevel); });
+ }
+}
+
void RenderProxy::purgeCaches() {
if (RenderThread::hasInstance()) {
RenderThread& thread = RenderThread::getInstance();
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 82072a6e2499..47c1b0cd28e5 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -105,6 +105,7 @@ public:
void destroyHardwareResources();
static void trimMemory(int level);
+ static void trimCaches(int level);
static void purgeCaches();
static void overrideProperty(const char* name, const char* value);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 9ba67a2110c1..eb28c080c056 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -521,6 +521,11 @@ void RenderThread::trimMemory(TrimLevel level) {
cacheManager().trimMemory(level);
}
+void RenderThread::trimCaches(CacheTrimLevel level) {
+ ATRACE_CALL();
+ cacheManager().trimCaches(level);
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index c77cd4134d1e..79e57de9d66f 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -174,6 +174,7 @@ public:
}
void trimMemory(TrimLevel level);
+ void trimCaches(CacheTrimLevel level);
/**
* isCurrent provides a way to query, if the caller is running on