Merge "Notify WindowSession about insets animation" into main
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 11a3168..1f8f0820 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -372,4 +372,14 @@
*/
oneway void notifyImeWindowVisibilityChangedFromClient(IWindow window, boolean visible,
in ImeTracker.Token statsToken);
+
+ /**
+ * Notifies WindowState whether inset animations are currently running within the Window.
+ * This value is used by the server to vote for refresh rate.
+ * see {@link com.android.server.wm.WindowState#mInsetsAnimationRunning).
+ *
+ * @param window The window that is insets animaiton is running.
+ * @param running Indicates the insets animation state.
+ */
+ oneway void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5b4b5300..072a835 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2514,12 +2514,16 @@
@VisibleForTesting
public void notifyInsetsAnimationRunningStateChanged(boolean running) {
if (sToolkitSetFrameRateReadOnlyFlagValue) {
- mInsetsAnimationRunning = running;
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.instant(Trace.TRACE_TAG_VIEW,
TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)",
Boolean.toString(running)));
}
+ mInsetsAnimationRunning = running;
+ try {
+ mWindowSession.notifyInsetsAnimationRunningStateChanged(mWindow, running);
+ } catch (RemoteException e) {
+ }
}
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 65e9930..72a595d 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -679,6 +679,11 @@
@NonNull ImeTracker.Token statsToken) {
}
+ @Override
+ public void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running) {
+ // NO-OP
+ }
+
void setParentInterface(@Nullable ISurfaceControlViewHostParent parentInterface) {
IBinder oldInterface = mParentInterface == null ? null : mParentInterface.asBinder();
IBinder newInterface = parentInterface == null ? null : parentInterface.asBinder();
diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
index e4c34ed..5ce8a32 100644
--- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java
+++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java
@@ -234,6 +234,12 @@
return w.mFrameRateVote.reset();
}
+ // If insets animation is running, do not convey the preferred app refresh rate to let VRI
+ // to control the refresh rate.
+ if (w.isInsetsAnimationRunning()) {
+ return w.mFrameRateVote.reset();
+ }
+
// If the app set a preferredDisplayModeId, the preferred refresh rate is the refresh rate
// of that mode id.
if (refreshRateSwitchingType != SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY) {
@@ -272,7 +278,7 @@
float getPreferredMinRefreshRate(WindowState w) {
// If app is animating, it's not able to control refresh rate because we want the animation
// to run in default refresh rate.
- if (w.isAnimationRunningSelfOrParent()) {
+ if (w.isAnimationRunningSelfOrParent() || w.isInsetsAnimationRunning()) {
return 0;
}
@@ -295,7 +301,7 @@
float getPreferredMaxRefreshRate(WindowState w) {
// If app is animating, it's not able to control refresh rate because we want the animation
// to run in default refresh rate.
- if (w.isAnimationRunningSelfOrParent()) {
+ if (w.isAnimationRunningSelfOrParent() || w.isInsetsAnimationRunning()) {
return 0;
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 0f66b93..07de489 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -1012,4 +1012,15 @@
}
}
}
+
+ @Override
+ public void notifyInsetsAnimationRunningStateChanged(IWindow window, boolean running) {
+ synchronized (mService.mGlobalLock) {
+ final WindowState win = mService.windowForClientLocked(this, window,
+ false /* throwOnError */);
+ if (win != null) {
+ win.notifyInsetsAnimationRunningStateChanged(running);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6009848..d7128af 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -212,6 +212,7 @@
import android.os.Trace;
import android.os.WorkSource;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.MergedConfiguration;
@@ -792,6 +793,16 @@
}
private final List<DrawHandler> mDrawHandlers = new ArrayList<>();
+ /**
+ * Indicates whether inset animations are currently running within the Window.
+ * This value is used by (@link com.android.server.wm.RefreshRatePolicy.java)
+ * to omit setting a frame rate on the WindowState. Insets Animation is unique in that
+ * sense that an app might drive an insets animation for a Window owned by a different
+ * app (such as IME). In that case, we need the app that drives the insets animation
+ * to be able to vote for high refresh rate from VRI.
+ */
+ private boolean mInsetsAnimationRunning;
+
private final Consumer<SurfaceControl.Transaction> mSeamlessRotationFinishedConsumer = t -> {
finishSeamlessRotation(t);
updateSurfacePosition(t);
@@ -6180,4 +6191,19 @@
}
mWmService.scheduleAnimationLocked();
}
+
+ void notifyInsetsAnimationRunningStateChanged(boolean running) {
+ if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
+ Trace.instant(TRACE_TAG_WINDOW_MANAGER,
+ TextUtils.formatSimple("%s: notifyInsetsAnimationRunningStateChanged(%s)",
+ getName(),
+ Boolean.toString(running)));
+ }
+ mInsetsAnimationRunning = running;
+ mWmService.scheduleAnimationLocked();
+ }
+
+ boolean isInsetsAnimationRunning() {
+ return mInsetsAnimationRunning;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index 3d08ca2..cc38f02 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -270,6 +270,46 @@
}
@Test
+ public void testInsetsAnimationAppOverridePreferredModeId() {
+ final WindowState overrideWindow = createWindow("overrideWindow");
+ overrideWindow.mAttrs.packageName = "com.android.test";
+ overrideWindow.mAttrs.preferredDisplayModeId = LOW_MODE_ID;
+ parcelLayoutParams(overrideWindow);
+ assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
+ assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
+ assertEquals(FRAME_RATE_VOTE_LOW_EXACT, overrideWindow.mFrameRateVote);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+
+ overrideWindow.notifyInsetsAnimationRunningStateChanged(true);
+ assertEquals(LOW_MODE_ID, mPolicy.getPreferredModeId(overrideWindow));
+ assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
+ assertEquals(FRAME_RATE_VOTE_NONE, overrideWindow.mFrameRateVote);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ }
+
+ @Test
+ public void testInsetsAnimationAppOverridePreferredRefreshRate() {
+ final WindowState overrideWindow = createWindow("overrideWindow");
+ overrideWindow.mAttrs.packageName = "com.android.test";
+ overrideWindow.mAttrs.preferredRefreshRate = LOW_REFRESH_RATE;
+ parcelLayoutParams(overrideWindow);
+ assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
+ assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
+ assertEquals(FRAME_RATE_VOTE_LOW_PREFERRED, overrideWindow.mFrameRateVote);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+
+ overrideWindow.notifyInsetsAnimationRunningStateChanged(true);
+ assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
+ assertTrue(mPolicy.updateFrameRateVote(overrideWindow));
+ assertEquals(FRAME_RATE_VOTE_NONE, overrideWindow.mFrameRateVote);
+ assertEquals(0, mPolicy.getPreferredMinRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ assertEquals(0, mPolicy.getPreferredMaxRefreshRate(overrideWindow), FLOAT_TOLERANCE);
+ }
+
+ @Test
public void testAnimatingCamera() {
final WindowState cameraUsingWindow = createWindow("cameraUsingWindow");
cameraUsingWindow.mAttrs.packageName = "com.android.test";