diff options
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 37 | ||||
| -rw-r--r-- | core/java/android/view/flags/refresh_rate_flags.aconfig | 7 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/ViewFrameRateTest.java | 71 |
3 files changed, 112 insertions, 3 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 23c43f56f2bc..350906818cb4 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -123,6 +123,7 @@ import static android.view.flags.Flags.toolkitFrameRateTouchBoost25q1; import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly; import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly; import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly; +import static android.view.flags.Flags.toolkitInitialTouchBoost; import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER; @@ -1113,9 +1114,13 @@ public final class ViewRootImpl implements ViewParent, private boolean mIsFrameRateConflicted = false; // Used to check whether SurfaceControl has been replaced. private boolean mSurfaceReplaced = false; + // Indicates whether a draw operation occurred during this frame while a touch event was active. + private boolean mTouchAndDrawn = false; // Used to set frame rate compatibility. @Surface.FrameRateCompatibility int mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; + // time for initial touch boost period. + private static final int FRAME_RATE_INITIAL_TOUCH_BOOST_TIME = 30; // time for touch boost period. private static final int FRAME_RATE_TOUCH_BOOST_TIME = 3000; // Timeout for the other frame rate boosts other than touch boost. @@ -1213,6 +1218,7 @@ public final class ViewRootImpl implements ViewParent, private static boolean sSurfaceFlingerBugfixFlagValue = com.android.graphics.surfaceflinger.flags.Flags.vrrBugfix24q4(); private static final boolean sEnableVrr = ViewProperties.vrr_enabled().orElse(true); + private static final boolean sToolkitInitialTouchBoostFlagValue = toolkitInitialTouchBoost(); static { sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); @@ -4435,6 +4441,10 @@ public final class ViewRootImpl implements ViewParent, // We set the preferred frame rate and frame rate category at the end of performTraversals // when the values are applicable. if (mDrawnThisFrame) { + if (sToolkitInitialTouchBoostFlagValue && mIsTouchBoosting) { + mTouchAndDrawn = true; + } + mDrawnThisFrame = false; if (!mInvalidationIdleMessagePosted && sSurfaceFlingerBugfixFlagValue) { mInvalidationIdleMessagePosted = true; @@ -6718,6 +6728,7 @@ public final class ViewRootImpl implements ViewParent, private static final int MSG_REFRESH_POINTER_ICON = 41; private static final int MSG_FRAME_RATE_SETTING = 42; private static final int MSG_SURFACE_REPLACED_TIMEOUT = 43; + private static final int MSG_INITIAL_TOUCH_BOOST_TIMEOUT = 44; final class ViewRootHandler extends Handler { @Override @@ -6791,6 +6802,8 @@ public final class ViewRootImpl implements ViewParent, return "MSG_FRAME_RATE_SETTING"; case MSG_SURFACE_REPLACED_TIMEOUT: return "MSG_SURFACE_REPLACED_TIMEOUT"; + case MSG_INITIAL_TOUCH_BOOST_TIMEOUT: + return "MSG_INITIAL_TOUCH_BOOST_TIMEOUT"; } return super.getMessageName(message); } @@ -7066,6 +7079,17 @@ public final class ViewRootImpl implements ViewParent, setPreferredFrameRateCategory(FRAME_RATE_CATEGORY_NO_PREFERENCE); } break; + case MSG_INITIAL_TOUCH_BOOST_TIMEOUT: + if (mTouchAndDrawn) { + mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); + mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT, + FRAME_RATE_TOUCH_BOOST_TIME); + } else { + mIsTouchBoosting = false; + setPreferredFrameRateCategory(FRAME_RATE_CATEGORY_NO_PREFERENCE); + } + mTouchAndDrawn = false; + break; case MSG_REFRESH_POINTER_ICON: if (mPointerIconEvent == null) { break; @@ -8130,9 +8154,16 @@ public final class ViewRootImpl implements ViewParent, */ if (mIsTouchBoosting && (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)) { - mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); - mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT, - FRAME_RATE_TOUCH_BOOST_TIME); + + if (sToolkitInitialTouchBoostFlagValue) { + mHandler.removeMessages(MSG_INITIAL_TOUCH_BOOST_TIMEOUT); + mHandler.sendEmptyMessageDelayed(MSG_INITIAL_TOUCH_BOOST_TIMEOUT, + FRAME_RATE_INITIAL_TOUCH_BOOST_TIME); + } else { + mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT); + mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT, + FRAME_RATE_TOUCH_BOOST_TIME); + } } return handled ? FINISH_HANDLED : FORWARD; } diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig index 675e5a1b4804..3bc2205f8e1c 100644 --- a/core/java/android/view/flags/refresh_rate_flags.aconfig +++ b/core/java/android/view/flags/refresh_rate_flags.aconfig @@ -136,4 +136,11 @@ flag { description: "Feature flag to not suppress touch boost for specific windowTypes in VRR V QPR2" bug: "335874198" is_exported: true +} + +flag { + name: "toolkit_initial_touch_boost" + namespace: "toolkit" + description: "Feature flag to update initial touch boost logic" + bug: "393004744" }
\ No newline at end of file diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java index 8b4f714fbf65..45f1a096aa85 100644 --- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java +++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java @@ -26,6 +26,7 @@ import static android.view.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_ANIMATION_BUGFIX_ import static android.view.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY; import static android.view.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_TOUCH_BOOST_25Q1; import static android.view.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY; +import static android.view.flags.Flags.FLAG_TOOLKIT_INITIAL_TOUCH_BOOST; import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY; import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API; import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly; @@ -34,6 +35,7 @@ import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly; import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import android.annotation.NonNull; @@ -180,6 +182,75 @@ public class ViewFrameRateTest { } @Test + @RequiresFlagsEnabled(FLAG_TOOLKIT_INITIAL_TOUCH_BOOST) + public void initialTouchBoost() 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); + mMovingView.setOnClickListener((v) -> {}); + }); + waitForFrameRateCategoryToSettle(); + + int[] position = new int[2]; + mActivityRule.runOnUiThread(() -> { + mMovingView.getLocationOnScreen(position); + position[0] += mMovingView.getWidth() / 2; + position[1] += mMovingView.getHeight() / 2; + }); + final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + + assertFalse(mViewRoot.getIsTouchBoosting()); + + long now = SystemClock.uptimeMillis(); + MotionEvent down = MotionEvent.obtain( + now, // downTime + now, // eventTime + MotionEvent.ACTION_DOWN, // action + position[0], // x + position[1], // y + 0 // metaState + ); + + mActivityRule.runOnUiThread(() -> { + mMovingView.getViewRootImpl().dispatchAppVisibility(false); + }); + + down.setSource(InputDevice.SOURCE_TOUCHSCREEN); + instrumentation.sendPointerSync(down); + down.recycle(); + + Thread.sleep(100); + // should have touch boost + assertTrue(mViewRoot.getIsTouchBoosting()); + + MotionEvent up = MotionEvent.obtain( + now, // downTime + now, // eventTime + MotionEvent.ACTION_UP, // action + position[0], // x + position[1], // y + 0 // metaState + ); + up.setSource(InputDevice.SOURCE_TOUCHSCREEN); + instrumentation.sendPointerSync(up); + up.recycle(); + + // Should not be boosted if nothing is drawn + Thread.sleep(30); + assertFalse(mViewRoot.getIsTouchBoosting()); + + mActivityRule.runOnUiThread(() -> { + mMovingView.getViewRootImpl().dispatchAppVisibility(true); + }); + } + + @Test @RequiresFlagsEnabled(FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY) public void inputMethodWithContentMoves() throws Throwable { if (!ViewProperties.vrr_enabled().orElse(true)) { |