summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt5
-rw-r--r--core/java/android/view/ViewRootImpl.java44
-rw-r--r--core/java/android/view/Window.java36
-rw-r--r--core/java/android/view/WindowManager.java44
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java7
-rw-r--r--core/res/res/values/attrs.xml7
-rw-r--r--core/res/res/values/public-staging.xml2
-rw-r--r--core/tests/coretests/res/values/styles.xml6
-rw-r--r--core/tests/coretests/src/android/view/ViewRootImplTest.java16
-rw-r--r--core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java60
10 files changed, 220 insertions, 7 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index ed05047d546e..60eeea002705 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1893,6 +1893,7 @@ package android {
field public static final int windowFullscreen = 16843277; // 0x101020d
field public static final int windowHideAnimation = 16842935; // 0x10100b7
field public static final int windowIsFloating = 16842839; // 0x1010057
+ field @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public static final int windowIsFrameRatePowerSavingsBalanced;
field public static final int windowIsTranslucent = 16842840; // 0x1010058
field public static final int windowLayoutAffinity = 16844313; // 0x1010619
field public static final int windowLayoutInDisplayCutoutMode = 16844166; // 0x1010586
@@ -54088,6 +54089,7 @@ package android.view {
method public abstract void invalidatePanelMenu(int);
method public final boolean isActive();
method public abstract boolean isFloating();
+ method @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public boolean isFrameRatePowerSavingsBalanced();
method public boolean isNavigationBarContrastEnforced();
method public abstract boolean isShortcutKey(int, android.view.KeyEvent);
method @Deprecated public boolean isStatusBarContrastEnforced();
@@ -54137,6 +54139,7 @@ package android.view {
method public void setFlags(int, int);
method public void setFormat(int);
method @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public void setFrameRateBoostOnTouchEnabled(boolean);
+ method @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public void setFrameRatePowerSavingsBalanced(boolean);
method public void setGravity(int);
method @RequiresPermission(android.Manifest.permission.HIDE_OVERLAY_WINDOWS) public final void setHideOverlayWindows(boolean);
method public void setIcon(@DrawableRes int);
@@ -54506,6 +54509,7 @@ package android.view {
method @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public boolean getFrameRateBoostOnTouchEnabled();
method public final CharSequence getTitle();
method public boolean isFitInsetsIgnoringVisibility();
+ method @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public boolean isFrameRatePowerSavingsBalanced();
method public boolean isHdrConversionEnabled();
method public static boolean mayUseInputMethod(int);
method public void setBlurBehindRadius(@IntRange(from=0) int);
@@ -54516,6 +54520,7 @@ package android.view {
method public void setFitInsetsSides(int);
method public void setFitInsetsTypes(int);
method @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public void setFrameRateBoostOnTouchEnabled(boolean);
+ method @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") public void setFrameRatePowerSavingsBalanced(boolean);
method public void setHdrConversionEnabled(boolean);
method public final void setTitle(CharSequence);
method public void setWallpaperTouchEventsEnabled(boolean);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9474a698c1a9..3780464f7b6b 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1022,6 +1022,11 @@ public final class ViewRootImpl implements ViewParent,
// Used to check if there is a message in the message queue
// for idleness handling.
private boolean mHasIdledMessage = false;
+ // Used to allow developers to opt out Toolkit dVRR feature.
+ // This feature allows device to adjust refresh rate
+ // as needed and can be useful for power saving.
+ // Should not enable the dVRR feature if the value is false.
+ private boolean mIsFrameRatePowerSavingsBalanced = true;
// time for touch boost period.
private static final int FRAME_RATE_TOUCH_BOOST_TIME = 3000;
// time for checking idle status periodically.
@@ -2533,8 +2538,10 @@ public final class ViewRootImpl implements ViewParent,
// Set the frame rate selection strategy to FRAME_RATE_SELECTION_STRATEGY_SELF
// This strategy ensures that the frame rate specifications do not cascade down to
// the descendant layers. This is particularly important for applications like Chrome,
- // where child surfaces should adhere to default behavior instead of no preference
- if (sToolkitSetFrameRateReadOnlyFlagValue) {
+ // where child surfaces should adhere to default behavior instead of no preference.
+ // This issue only happens when ViewRootImpl calls setFrameRateCategory. This is
+ // no longer needed if the dVRR feature is disabled.
+ if (shouldEnableDvrr()) {
try {
mFrameRateTransaction.setFrameRateSelectionStrategy(sc,
sc.FRAME_RATE_SELECTION_STRATEGY_SELF).applyAsyncUnsafe();
@@ -3258,7 +3265,7 @@ public final class ViewRootImpl implements ViewParent,
destroyHardwareResources();
}
- if (sToolkitSetFrameRateReadOnlyFlagValue && viewVisibility == View.VISIBLE) {
+ if (shouldEnableDvrr() && viewVisibility == View.VISIBLE) {
// Boost frame rate when the viewVisibility becomes true.
// This is mainly for lanuchers that lanuch new windows.
boostFrameRate(FRAME_RATE_TOUCH_BOOST_TIME);
@@ -3973,7 +3980,7 @@ public final class ViewRootImpl implements ViewParent,
}
}
- if (sToolkitSetFrameRateReadOnlyFlagValue) {
+ if (shouldEnableDvrr()) {
// Boost the frame rate when the ViewRootImpl first becomes available.
boostFrameRate(FRAME_RATE_TOUCH_BOOST_TIME);
}
@@ -12340,12 +12347,12 @@ public final class ViewRootImpl implements ViewParent,
private boolean shouldSetFrameRateCategory() {
// use toolkitSetFrameRate flag to gate the change
- return mSurface.isValid() && sToolkitSetFrameRateReadOnlyFlagValue;
+ return mSurface.isValid() && shouldEnableDvrr();
}
private boolean shouldSetFrameRate() {
// use toolkitSetFrameRate flag to gate the change
- return sToolkitSetFrameRateReadOnlyFlagValue;
+ return mSurface.isValid() && mPreferredFrameRate > 0 && shouldEnableDvrr();
}
private boolean shouldTouchBoost(int motionEventAction, int windowType) {
@@ -12354,7 +12361,7 @@ public final class ViewRootImpl implements ViewParent,
|| motionEventAction == MotionEvent.ACTION_UP;
boolean undesiredType = windowType == TYPE_INPUT_METHOD && mShouldSuppressBoostOnTyping;
// use toolkitSetFrameRate flag to gate the change
- return desiredAction && !undesiredType && sToolkitSetFrameRateReadOnlyFlagValue
+ return desiredAction && !undesiredType && shouldEnableDvrr()
&& getFrameRateBoostOnTouchEnabled();
}
@@ -12476,4 +12483,27 @@ public final class ViewRootImpl implements ViewParent,
// Record the largest view of percentage to the display size.
mLargestChildPercentage = Math.max(percentage, mLargestChildPercentage);
}
+
+ /**
+ * Get the value of mIsFrameRatePowerSavingsBalanced
+ * Can be used to checked if toolkit dVRR feature is enabled. The default value is true.
+ */
+ @VisibleForTesting
+ public boolean isFrameRatePowerSavingsBalanced() {
+ return mIsFrameRatePowerSavingsBalanced;
+ }
+
+ /**
+ * Set the value of mIsFrameRatePowerSavingsBalanced
+ * Can be used to checked if toolkit dVRR feature is enabled.
+ */
+ public void setFrameRatePowerSavingsBalanced(boolean enabled) {
+ if (sToolkitSetFrameRateReadOnlyFlagValue) {
+ mIsFrameRatePowerSavingsBalanced = enabled;
+ }
+ }
+
+ private boolean shouldEnableDvrr() {
+ return sToolkitSetFrameRateReadOnlyFlagValue && mIsFrameRatePowerSavingsBalanced;
+ }
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 4ba4ee3ffff7..6b427fc00766 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1409,6 +1409,42 @@ public abstract class Window {
}
/**
+ * Set whether frameratepowersavingsbalance is enabled for this Window.
+ * This allows device to adjust refresh rate
+ * as needed and can be useful for power saving.
+ *
+ * @param enabled whether the frameratepowersavingsbalance is enabled.
+ * @see #isFrameRatePowerSavingsBalanced()
+ * @see WindowManager.LayoutParams#setFrameRatePowerSavingsBalanced(boolean)
+ */
+ @FlaggedApi(android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void setFrameRatePowerSavingsBalanced(boolean enabled) {
+ if (sToolkitSetFrameRateReadOnlyFlagValue) {
+ final WindowManager.LayoutParams attrs = getAttributes();
+ attrs.setFrameRatePowerSavingsBalanced(enabled);
+ dispatchWindowAttributesChanged(attrs);
+ }
+ }
+
+ /**
+ * Get whether frameratepowersavingsbalance is enabled for this Window.
+ * This allows device to adjust refresh rate
+ * as needed and can be useful for power saving.
+ * {@link #setFrameRateBoostOnTouchEnabled(boolean)}
+ *
+ * @return whether the frameratepowersavingsbalance is enabled.
+ * @see #setFrameRatePowerSavingsBalanced(boolean)
+ * @see WindowManager.LayoutParams#isFrameRatePowerSavingsBalanced()
+ */
+ @FlaggedApi(android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public boolean isFrameRatePowerSavingsBalanced() {
+ if (sToolkitSetFrameRateReadOnlyFlagValue) {
+ return getAttributes().isFrameRatePowerSavingsBalanced();
+ }
+ return false;
+ }
+
+ /**
* If {@code isPreferred} is true, this method requests that the connected display does minimal
* post processing when this window is visible on the screen. Otherwise, it requests that the
* display switches back to standard image processing.
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index bc9b4fe37a2f..71eb8a29dc4c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -4397,6 +4397,7 @@ public interface WindowManager extends ViewManager {
* For variable refresh rate project.
*/
private boolean mFrameRateBoostOnTouch = true;
+ private boolean mIsFrameRatePowerSavingsBalanced = true;
private static boolean sToolkitSetFrameRateReadOnlyFlagValue =
android.view.flags.Flags.toolkitSetFrameRateReadOnly();
@@ -4861,6 +4862,36 @@ public interface WindowManager extends ViewManager {
}
/**
+ * Set the value whether frameratepowersavingsbalance is enabled for this Window.
+ * This allows device to adjust refresh rate
+ * as needed and can be useful for power saving.
+ *
+ * @param enabled Whether we should enable frameratepowersavingsbalance.
+ */
+ @FlaggedApi(android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void setFrameRatePowerSavingsBalanced(boolean enabled) {
+ if (sToolkitSetFrameRateReadOnlyFlagValue) {
+ mIsFrameRatePowerSavingsBalanced = enabled;
+ }
+ }
+
+ /**
+ * Get the value whether frameratepowersavingsbalance is enabled for this Window.
+ * This allows device to adjust refresh rate
+ * as needed and can be useful for power saving.
+ * by {@link #setFrameRatePowerSavingsBalanced(boolean)}
+ *
+ * @return Whether we should enable frameratepowersavingsbalance.
+ */
+ @FlaggedApi(android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public boolean isFrameRatePowerSavingsBalanced() {
+ if (sToolkitSetFrameRateReadOnlyFlagValue) {
+ return mIsFrameRatePowerSavingsBalanced;
+ }
+ return true;
+ }
+
+ /**
* <p>
* Blurs the screen behind the window. The effect is similar to that of {@link #dimAmount},
* but instead of dimmed, the content behind the window will be blurred (or combined with
@@ -5013,6 +5044,7 @@ public interface WindowManager extends ViewManager {
out.writeFloat(mDesiredHdrHeadroom);
if (sToolkitSetFrameRateReadOnlyFlagValue) {
out.writeBoolean(mFrameRateBoostOnTouch);
+ out.writeBoolean(mIsFrameRatePowerSavingsBalanced);
}
}
@@ -5088,6 +5120,7 @@ public interface WindowManager extends ViewManager {
mDesiredHdrHeadroom = in.readFloat();
if (sToolkitSetFrameRateReadOnlyFlagValue) {
mFrameRateBoostOnTouch = in.readBoolean();
+ mIsFrameRatePowerSavingsBalanced = in.readBoolean();
}
}
@@ -5431,6 +5464,12 @@ public interface WindowManager extends ViewManager {
changes |= LAYOUT_CHANGED;
}
+ if (sToolkitSetFrameRateReadOnlyFlagValue
+ && mIsFrameRatePowerSavingsBalanced != o.mIsFrameRatePowerSavingsBalanced) {
+ mIsFrameRatePowerSavingsBalanced = o.mIsFrameRatePowerSavingsBalanced;
+ changes |= LAYOUT_CHANGED;
+ }
+
return changes;
}
@@ -5658,6 +5697,11 @@ public interface WindowManager extends ViewManager {
sb.append(prefix).append(" frameRateBoostOnTouch=");
sb.append(mFrameRateBoostOnTouch);
}
+ if (sToolkitSetFrameRateReadOnlyFlagValue && mIsFrameRatePowerSavingsBalanced) {
+ sb.append(System.lineSeparator());
+ sb.append(prefix).append(" dvrrWindowFrameRateHint=");
+ sb.append(mIsFrameRatePowerSavingsBalanced);
+ }
if (paramsForRotation != null && paramsForRotation.length != 0) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" paramsForRotation:");
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 523924566dd7..0dd01e48db0a 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -363,6 +363,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private boolean mUseDecorContext = false;
+ private boolean mIsFrameRatePowerSavingsBalanced = true;
+
/** @see ViewRootImpl#mActivityConfigCallback */
private ActivityConfigCallback mActivityConfigCallback;
@@ -2211,6 +2213,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
void onViewRootImplSet(ViewRootImpl viewRoot) {
viewRoot.setActivityConfigCallback(mActivityConfigCallback);
viewRoot.getOnBackInvokedDispatcher().updateContext(getContext());
+ viewRoot.setFrameRatePowerSavingsBalanced(mIsFrameRatePowerSavingsBalanced);
mProxyOnBackInvokedDispatcher.setActualDispatcher(viewRoot.getOnBackInvokedDispatcher());
applyDecorFitsSystemWindows();
}
@@ -2559,6 +2562,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (a.getBoolean(R.styleable.Window_windowActivityTransitions, false)) {
requestFeature(FEATURE_ACTIVITY_TRANSITIONS);
}
+ if (a.hasValue(R.styleable.Window_windowIsFrameRatePowerSavingsBalanced)) {
+ mIsFrameRatePowerSavingsBalanced =
+ a.getBoolean(R.styleable.Window_windowIsFrameRatePowerSavingsBalanced, true);
+ }
mIsTranslucent = a.getBoolean(R.styleable.Window_windowIsTranslucent, false);
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index cc6460ea7d4d..c1fd61948e68 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2514,6 +2514,13 @@
<!-- The icon is shown unless the launching app specified SPLASH_SCREEN_STYLE_EMPTY -->
<enum name="icon_preferred" value="1" />
</attr>
+ <!-- Offer Window the ability to opt out the UI Toolkit discrete variable refresh rate.
+ This feature allows device to adjust refresh rate as needed and
+ can be useful for power saving.
+ Set to false to reduce the frame rate optimizations on devices with
+ variable refresh rate screens.
+ The default is true. -->
+ <attr name="windowIsFrameRatePowerSavingsBalanced" format="boolean"/>
<!-- Flag indicating whether this window would opt-out the edge-to-edge enforcement.
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 8af8cb84a217..c797210345a2 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -165,6 +165,8 @@
<public name="allowCrossUidActivitySwitchFromBelow"/>
<!-- @FlaggedApi("com.android.text.flags.use_bounds_for_width") -->
<public name="shiftDrawingOffsetForStartOverhang" />
+ <!-- @FlaggedApi("android.view.flags.toolkit_set_frame_rate_read_only") -->
+ <public name="windowIsFrameRatePowerSavingsBalanced"/>
</staging-public-group>
<staging-public-group type="id" first-id="0x01bc0000">
diff --git a/core/tests/coretests/res/values/styles.xml b/core/tests/coretests/res/values/styles.xml
index 32eebb35e0c3..78cd1e1e47e8 100644
--- a/core/tests/coretests/res/values/styles.xml
+++ b/core/tests/coretests/res/values/styles.xml
@@ -55,4 +55,10 @@
<style name="ViewDefaultBackground">
<item name="android:background">#00000000</item>
</style>
+ <style name="IsFrameRatePowerSavingsBalancedDisabled">
+ <item name="android:windowIsFrameRatePowerSavingsBalanced">false</item>
+ </style>
+ <style name="IsFrameRatePowerSavingsBalancedEnabled">
+ <item name="android:windowIsFrameRatePowerSavingsBalanced">true</item>
+ </style>
</resources>
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 433d353e5074..038c00e3823c 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -953,6 +953,22 @@ public class ViewRootImplTest {
});
}
+ /**
+ * Test the IsFrameRatePowerSavingsBalanced values are properly set
+ */
+ @UiThreadTest
+ @Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void votePreferredFrameRate_isFrameRatePowerSavingsBalanced() {
+ ViewRootImpl viewRootImpl = new ViewRootImpl(sContext,
+ sContext.getDisplayNoVerify());
+ assertEquals(viewRootImpl.isFrameRatePowerSavingsBalanced(), true);
+ viewRootImpl.setFrameRatePowerSavingsBalanced(false);
+ assertEquals(viewRootImpl.isFrameRatePowerSavingsBalanced(), false);
+ viewRootImpl.setFrameRatePowerSavingsBalanced(true);
+ assertEquals(viewRootImpl.isFrameRatePowerSavingsBalanced(), true);
+ }
+
@Test
public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() {
mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
index 3df3b9d2c555..b9841ff997e7 100644
--- a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java
@@ -21,17 +21,28 @@ import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_M
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_EDGE_TO_EDGE_ENFORCED;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY;
import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import android.app.Instrumentation;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Binder;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.view.ActionMode;
import android.view.ContextThemeWrapper;
+import android.view.ViewRootImpl;
+import android.view.WindowManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -40,6 +51,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -54,6 +66,12 @@ public final class PhoneWindowTest {
private PhoneWindow mPhoneWindow;
private Context mContext;
+ private static Instrumentation sInstrumentation =
+ InstrumentationRegistry.getInstrumentation();
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getContext();
@@ -154,6 +172,48 @@ public final class PhoneWindowTest {
assertThat(colorDrawable.getColor(), is(Color.BLUE));
}
+ @Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void testWindowFrameRateHint_disabled() {
+ createPhoneWindowWithTheme(R.style.IsFrameRatePowerSavingsBalancedDisabled);
+ installDecor();
+
+ DecorView decorView = (DecorView) mPhoneWindow.getDecorView();
+
+ WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+ wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
+
+ sInstrumentation.runOnMainSync(() -> {
+ WindowManager wm = mContext.getSystemService(WindowManager.class);
+ wm.addView(decorView, wmlp);
+ });
+ sInstrumentation.waitForIdleSync();
+
+ ViewRootImpl viewRootImpl = decorView.getViewRootImpl();
+ assertFalse(viewRootImpl.isFrameRatePowerSavingsBalanced());
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+ public void testWindowFrameRateHint_enabled() {
+ createPhoneWindowWithTheme(R.style.IsFrameRatePowerSavingsBalancedEnabled);
+ installDecor();
+
+ DecorView decorView = (DecorView) mPhoneWindow.getDecorView();
+
+ WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+ wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
+
+ sInstrumentation.runOnMainSync(() -> {
+ WindowManager wm = mContext.getSystemService(WindowManager.class);
+ wm.addView(decorView, wmlp);
+ });
+ sInstrumentation.waitForIdleSync();
+
+ ViewRootImpl viewRootImpl = decorView.getViewRootImpl();
+ assertTrue(viewRootImpl.isFrameRatePowerSavingsBalanced());
+ }
+
private void createPhoneWindowWithTheme(int theme) {
mPhoneWindow = new PhoneWindow(new ContextThemeWrapper(mContext, theme));
}