diff options
7 files changed, 105 insertions, 3 deletions
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 11a3168daa0e..1f8f0820ca3a 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -372,4 +372,14 @@ interface IWindowSession { */ 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 5b4b5300cef4..072a835eb664 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2514,12 +2514,16 @@ public final class ViewRootImpl implements ViewParent, @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 65e993049979..72a595d95ec2 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -679,6 +679,11 @@ public class WindowlessWindowManager implements IWindowSession { @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 e4c34ed52359..5ce8a32aa141 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 @@ class RefreshRatePolicy { 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 @@ class RefreshRatePolicy { 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 @@ class RefreshRatePolicy { 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 0f66b93ca273..07de489d9ff4 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 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { } } } + + @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 6009848f9308..d7128afb43a3 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.SystemClock; 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } 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 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } 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 3d08ca2905f3..cc38f02ccc4c 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 @@ public class RefreshRatePolicyTest extends WindowTestsBase { } @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"; |