Fix the jelly effect when scrolling the a11y floating menu.

Root cause:
The default scroll mode of RecyclerView is scrollable.

Solution:
Set OVER_SCROLL_ALWAYS when the actual height of target list exceed the
available height, otherwise OVER_SCROLL_NEVER.

Bug: 184817161
Test: atest AccessibilityFloatingMenuViewTest
Change-Id: I9a2bfd674141475e5546b1ed5450e65132ffd384
This commit is contained in:
Peter_Liang
2021-04-13 15:55:51 +08:00
parent 463493f57d
commit b6545c449d
2 changed files with 49 additions and 2 deletions

View File

@@ -371,6 +371,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
mAdapter.notifyDataSetChanged();
updateRadiusWith(mSizeType, mRadiusType, mTargets.size());
updateScrollModeWith(hasExceededMaxLayoutHeight());
setSystemGestureExclusion();
fadeOut();
@@ -614,6 +615,7 @@ public class AccessibilityFloatingMenuView extends FrameLayout
updateColor();
updateStrokeWith(newConfig.uiMode, mAlignment);
updateLocationWith(mAlignment, mPercentageY);
updateScrollModeWith(hasExceededMaxLayoutHeight());
}
@VisibleForTesting
@@ -679,6 +681,12 @@ public class AccessibilityFloatingMenuView extends FrameLayout
mListView.setLayoutParams(layoutParams);
}
private void updateScrollModeWith(boolean hasExceededMaxLayoutHeight) {
mListView.setOverScrollMode(hasExceededMaxLayoutHeight
? OVER_SCROLL_ALWAYS
: OVER_SCROLL_NEVER);
}
private void updateColor() {
final int menuColorResId = R.color.accessibility_floating_menu_background;
getMenuGradientDrawable().setColor(getResources().getColor(menuColorResId));
@@ -726,6 +734,11 @@ public class AccessibilityFloatingMenuView extends FrameLayout
layerDrawable.setLayerInset(INDEX_MENU_ITEM, left, 0, right, 0);
}
@VisibleForTesting
boolean hasExceededMaxLayoutHeight() {
return calculateActualLayoutHeight() > getMaxLayoutHeight();
}
@Alignment
private int calculateCurrentAlignment() {
return mCurrentLayoutParams.x >= ((MIN_WINDOW_X + getMaxWindowX()) / 2)
@@ -737,6 +750,10 @@ public class AccessibilityFloatingMenuView extends FrameLayout
return mCurrentLayoutParams.y / (float) getMaxWindowY();
}
private int calculateActualLayoutHeight() {
return (mPadding + mIconHeight) * mTargets.size() + mPadding;
}
private @DimenRes int getRadiusResId(@SizeType int sizeType, int itemCount) {
return sizeType == SizeType.SMALL
? getSmallSizeResIdWith(itemCount)
@@ -760,13 +777,16 @@ public class AccessibilityFloatingMenuView extends FrameLayout
return new Rect(0, 0, mScreenWidth - getWindowWidth(), mScreenHeight - getWindowHeight());
}
private int getMaxLayoutHeight() {
return mScreenHeight - mMargin * 2;
}
private int getLayoutWidth() {
return mPadding * 2 + mIconWidth;
}
private int getLayoutHeight() {
return Math.min(mScreenHeight - mMargin * 2,
(mPadding + mIconHeight) * mTargets.size() + mPadding);
return Math.min(getMaxLayoutHeight(), calculateActualLayoutHeight());
}
private int getWindowWidth() {

View File

@@ -16,6 +16,9 @@
package com.android.systemui.accessibility.floatingmenu;
import static android.view.View.OVER_SCROLL_ALWAYS;
import static android.view.View.OVER_SCROLL_NEVER;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -437,6 +440,30 @@ public class AccessibilityFloatingMenuViewTest extends SysuiTestCase {
action -> action.getId() == R.id.action_move_to_edge_and_hide)).isTrue();
}
@Test
public void onTargetsChanged_exceedAvailableHeight_overScrollAlways() {
final RecyclerView listView = new RecyclerView(mContext);
final AccessibilityFloatingMenuView menuView =
spy(new AccessibilityFloatingMenuView(mContext, listView));
doReturn(true).when(menuView).hasExceededMaxLayoutHeight();
menuView.onTargetsChanged(mTargets);
assertThat(listView.getOverScrollMode()).isEqualTo(OVER_SCROLL_ALWAYS);
}
@Test
public void onTargetsChanged_notExceedAvailableHeight_overScrollNever() {
final RecyclerView listView = new RecyclerView(mContext);
final AccessibilityFloatingMenuView menuView =
spy(new AccessibilityFloatingMenuView(mContext, listView));
doReturn(false).when(menuView).hasExceededMaxLayoutHeight();
mMenuView.onTargetsChanged(mTargets);
assertThat(mListView.getOverScrollMode()).isEqualTo(OVER_SCROLL_NEVER);
}
@After
public void tearDown() {
mInterceptMotionEvent = null;