Loading core/java/android/view/View.java +13 −6 Original line number Diff line number Diff line Loading @@ -34071,14 +34071,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } private float convertVelocityToFrameRate(float velocityPps) { // From UXR study, premium experience is: // 1500+ dp/s: 120fps // 0 - 1500 dp/s: 80fps // OEMs are likely to modify this to balance battery and user experience for their // specific device. // Internal testing has shown that this gives a premium experience: // above 300dp/s => 120fps // between 300dp/s and 125fps => 80fps // below 125dp/s => 60fps float density = mAttachInfo.mDensity; float velocityDps = velocityPps / density; return (velocityDps >= 1500f) ? MAX_FRAME_RATE : 80f; float frameRate; if (velocityDps > 300f) { frameRate = MAX_FRAME_RATE; // Use maximum at fast motion } else if (velocityDps > 125f) { frameRate = 80f; // Use medium frame rate when motion is slower } else { frameRate = 60f; // Use minimum frame rate when motion is very slow } return frameRate; } /** core/tests/coretests/src/android/view/ViewFrameRateTest.java +28 −3 Original line number Diff line number Diff line Loading @@ -278,7 +278,7 @@ public class ViewFrameRateTest { @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API, FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY, FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) public void lowVelocity80() throws Throwable { public void lowVelocity60() throws Throwable { if (!ViewProperties.vrr_enabled().orElse(true)) { return; } Loading @@ -292,6 +292,31 @@ public class ViewFrameRateTest { mActivityRule.runOnUiThread(() -> { mMovingView.setFrameContentVelocity(1f); mMovingView.invalidate(); runAfterDraw(() -> assertEquals(60f, mViewRoot.getLastPreferredFrameRate(), 0f)); }); waitForAfterDraw(); } @Test @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API, FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY, FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) public void midVelocity80() throws Throwable { if (!ViewProperties.vrr_enabled().orElse(true)) { return; } mActivityRule.runOnUiThread(() -> { ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams(); layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; mMovingView.setLayoutParams(layoutParams); }); waitForFrameRateCategoryToSettle(); mActivityRule.runOnUiThread(() -> { float midSpeed = 200f * mMovingView.getContext().getResources().getDisplayMetrics().density; mMovingView.setFrameContentVelocity(midSpeed); mMovingView.invalidate(); runAfterDraw(() -> assertEquals(80f, mViewRoot.getLastPreferredFrameRate(), 0f)); }); waitForAfterDraw(); Loading Loading @@ -321,7 +346,7 @@ public class ViewFrameRateTest { frameLayout.setFrameContentVelocity(1f); mMovingView.offsetTopAndBottom(100); frameLayout.invalidate(); runAfterDraw(() -> assertEquals(80f, mViewRoot.getLastPreferredFrameRate(), 0f)); runAfterDraw(() -> assertEquals(60f, mViewRoot.getLastPreferredFrameRate(), 0f)); }); waitForAfterDraw(); } Loading Loading @@ -590,7 +615,7 @@ public class ViewFrameRateTest { runAfterDraw(() -> { assertEquals(FRAME_RATE_CATEGORY_LOW, mViewRoot.getLastPreferredFrameRateCategory()); assertEquals(80f, mViewRoot.getLastPreferredFrameRate()); assertEquals(60f, mViewRoot.getLastPreferredFrameRate()); }); }); waitForAfterDraw(); Loading Loading
core/java/android/view/View.java +13 −6 Original line number Diff line number Diff line Loading @@ -34071,14 +34071,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } private float convertVelocityToFrameRate(float velocityPps) { // From UXR study, premium experience is: // 1500+ dp/s: 120fps // 0 - 1500 dp/s: 80fps // OEMs are likely to modify this to balance battery and user experience for their // specific device. // Internal testing has shown that this gives a premium experience: // above 300dp/s => 120fps // between 300dp/s and 125fps => 80fps // below 125dp/s => 60fps float density = mAttachInfo.mDensity; float velocityDps = velocityPps / density; return (velocityDps >= 1500f) ? MAX_FRAME_RATE : 80f; float frameRate; if (velocityDps > 300f) { frameRate = MAX_FRAME_RATE; // Use maximum at fast motion } else if (velocityDps > 125f) { frameRate = 80f; // Use medium frame rate when motion is slower } else { frameRate = 60f; // Use minimum frame rate when motion is very slow } return frameRate; } /**
core/tests/coretests/src/android/view/ViewFrameRateTest.java +28 −3 Original line number Diff line number Diff line Loading @@ -278,7 +278,7 @@ public class ViewFrameRateTest { @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API, FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY, FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) public void lowVelocity80() throws Throwable { public void lowVelocity60() throws Throwable { if (!ViewProperties.vrr_enabled().orElse(true)) { return; } Loading @@ -292,6 +292,31 @@ public class ViewFrameRateTest { mActivityRule.runOnUiThread(() -> { mMovingView.setFrameContentVelocity(1f); mMovingView.invalidate(); runAfterDraw(() -> assertEquals(60f, mViewRoot.getLastPreferredFrameRate(), 0f)); }); waitForAfterDraw(); } @Test @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API, FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY, FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY}) public void midVelocity80() throws Throwable { if (!ViewProperties.vrr_enabled().orElse(true)) { return; } mActivityRule.runOnUiThread(() -> { ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams(); layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; mMovingView.setLayoutParams(layoutParams); }); waitForFrameRateCategoryToSettle(); mActivityRule.runOnUiThread(() -> { float midSpeed = 200f * mMovingView.getContext().getResources().getDisplayMetrics().density; mMovingView.setFrameContentVelocity(midSpeed); mMovingView.invalidate(); runAfterDraw(() -> assertEquals(80f, mViewRoot.getLastPreferredFrameRate(), 0f)); }); waitForAfterDraw(); Loading Loading @@ -321,7 +346,7 @@ public class ViewFrameRateTest { frameLayout.setFrameContentVelocity(1f); mMovingView.offsetTopAndBottom(100); frameLayout.invalidate(); runAfterDraw(() -> assertEquals(80f, mViewRoot.getLastPreferredFrameRate(), 0f)); runAfterDraw(() -> assertEquals(60f, mViewRoot.getLastPreferredFrameRate(), 0f)); }); waitForAfterDraw(); } Loading Loading @@ -590,7 +615,7 @@ public class ViewFrameRateTest { runAfterDraw(() -> { assertEquals(FRAME_RATE_CATEGORY_LOW, mViewRoot.getLastPreferredFrameRateCategory()); assertEquals(80f, mViewRoot.getLastPreferredFrameRate()); assertEquals(60f, mViewRoot.getLastPreferredFrameRate()); }); }); waitForAfterDraw(); Loading