diff options
author | Michael Hoisie <hoisie@google.com> | 2024-04-18 17:33:40 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-04-18 17:34:30 -0700 |
commit | 43a7f0b102a9350cdb379cf88329858a150a2e12 (patch) | |
tree | 5b1e0dc56fe3e014d269c105b75ef261123d3bf5 | |
parent | 1920a4cbbf574f775bd360b901b3e4102b7ad8b4 (diff) | |
download | robolectric-43a7f0b102a9350cdb379cf88329858a150a2e12.tar.gz |
Use correct scroll bar sizes in ShadowViewConfiguration
The scroll bar size logic in ShadowViewConfiguration was likely copied from Ice
Cream Sandwich (SDK 14), or perhaps earlier.
In O_MR1 (SDK 27), the scroll bar size went from 10dp to 4dp.
Update the logic ShadowViewConfiguration to reflect this. Also add a ctesque
test to ensure consistency between Robolectric and real Android.
This is part of the effort to eventually eliminate ShadowViewConfiguration
entirely.
PiperOrigin-RevId: 626199502
3 files changed, 92 insertions, 20 deletions
diff --git a/integration_tests/ctesque/src/sharedTest/java/android/view/ViewConfigurationTest.java b/integration_tests/ctesque/src/sharedTest/java/android/view/ViewConfigurationTest.java new file mode 100644 index 000000000..afc2edbbb --- /dev/null +++ b/integration_tests/ctesque/src/sharedTest/java/android/view/ViewConfigurationTest.java @@ -0,0 +1,45 @@ +package android.view; + +import static android.os.Build.VERSION_CODES.O_MR1; +import static com.google.common.truth.Truth.assertThat; + +import android.os.Build; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.internal.DoNotInstrument; + +/** Tests that {@link android.view.ViewConfiguration} behavior is consistent with real Android. */ +@DoNotInstrument +@RunWith(AndroidJUnit4.class) +public final class ViewConfigurationTest { + + private float density; + + @Before + public void setUp() { + density = + ApplicationProvider.getApplicationContext().getResources().getDisplayMetrics().density; + } + + @Test + public void scrollbar_configuration() { + ViewConfiguration viewConfiguration = + ViewConfiguration.get(ApplicationProvider.getApplicationContext()); + int scrollBarSize = ViewConfiguration.getScrollBarSize(); + int scaledScrollBarSizeDp = pxToDp(viewConfiguration.getScaledScrollBarSize()); + if (Build.VERSION.SDK_INT >= O_MR1) { + assertThat(scrollBarSize).isEqualTo(4); + assertThat(scaledScrollBarSizeDp).isEqualTo(4); + } else { + assertThat(scrollBarSize).isEqualTo(10); + assertThat(scaledScrollBarSizeDp).isEqualTo(10); + } + } + + public int pxToDp(int px) { + return Math.round(px / density); + } +} diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewConfigurationTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewConfigurationTest.java index d0dfeadfb..fd98c1a5e 100644 --- a/robolectric/src/test/java/org/robolectric/shadows/ShadowViewConfigurationTest.java +++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowViewConfigurationTest.java @@ -1,5 +1,6 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.O_MR1; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.robolectric.Shadows.shadowOf; @@ -11,6 +12,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(AndroidJUnit4.class) @@ -26,8 +28,10 @@ public class ShadowViewConfigurationTest { @Test public void methodsShouldReturnAndroidConstants() { ViewConfiguration viewConfiguration = ViewConfiguration.get(context); - - assertEquals(10, ViewConfiguration.getScrollBarSize()); + // Most of the constants here are private statics from ViewConfiguration circa Jelly Bean: + // https://cs.android.com/android/platform/superproject/+/android-4.1.1_r1:frameworks/base/core/java/android/view/ViewConfiguration.java + final int expectedScrollBarSize = RuntimeEnvironment.getApiLevel() >= O_MR1 ? 4 : 10; + assertEquals(expectedScrollBarSize, ViewConfiguration.getScrollBarSize()); assertEquals(250, ViewConfiguration.getScrollBarFadeDuration()); assertEquals(300, ViewConfiguration.getScrollDefaultDelay()); assertEquals(12, ViewConfiguration.getFadingEdgeLength()); @@ -48,7 +52,7 @@ public class ShadowViewConfigurationTest { assertThat(context.getResources().getDisplayMetrics().density).isEqualTo(1f); - assertEquals(10, viewConfiguration.getScaledScrollBarSize()); + assertEquals(expectedScrollBarSize, viewConfiguration.getScaledScrollBarSize()); assertEquals(12, viewConfiguration.getScaledFadingEdgeLength()); assertEquals(12, viewConfiguration.getScaledEdgeSlop()); assertEquals(16, viewConfiguration.getScaledTouchSlop()); @@ -62,11 +66,14 @@ public class ShadowViewConfigurationTest { } @Test + @Config(qualifiers = "hdpi") public void methodsShouldReturnScaledAndroidConstantsDependingOnPixelDensity() { - context.getResources().getDisplayMetrics().density = 1.5f; + // Most of the constants here are private statics from ViewConfiguration circa Jelly Bean: + // https://cs.android.com/android/platform/superproject/+/android-4.1.1_r1:frameworks/base/core/java/android/view/ViewConfiguration.java + // They are multiplied by the scaling factor 1.5 for HDPI. ViewConfiguration viewConfiguration = ViewConfiguration.get(context); - - assertEquals(15, viewConfiguration.getScaledScrollBarSize()); + final int expectedScaledScrollBarSize = RuntimeEnvironment.getApiLevel() >= O_MR1 ? 6 : 15; + assertEquals(expectedScaledScrollBarSize, viewConfiguration.getScaledScrollBarSize()); assertEquals(18, viewConfiguration.getScaledFadingEdgeLength()); assertEquals(18, viewConfiguration.getScaledEdgeSlop()); assertEquals(24, viewConfiguration.getScaledTouchSlop()); diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewConfiguration.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewConfiguration.java index 682f53b6a..8cd68ee34 100644 --- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewConfiguration.java +++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewConfiguration.java @@ -20,23 +20,28 @@ package org.robolectric.shadows; +import static android.os.Build.VERSION_CODES.P; +import static android.os.Build.VERSION_CODES.Q; import static org.robolectric.util.reflector.Reflector.reflector; import android.content.Context; +import android.content.res.Resources; import android.util.DisplayMetrics; import android.view.ViewConfiguration; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import org.robolectric.annotation.RealObject; import org.robolectric.shadow.api.Shadow; import org.robolectric.util.reflector.Accessor; import org.robolectric.util.reflector.ForType; +import org.robolectric.util.reflector.Static; @SuppressWarnings({"UnusedDeclaration"}) @Implements(ViewConfiguration.class) public class ShadowViewConfiguration { + @RealObject ViewConfiguration realViewConfiguration; - private static final int SCROLL_BAR_SIZE = 10; private static final int PRESSED_STATE_DURATION = 125; private static final int LONG_PRESS_TIMEOUT = 500; private static final int TAP_TIMEOUT = 115; @@ -54,7 +59,6 @@ public class ShadowViewConfiguration { private int fadingEdgeLength; private int minimumFlingVelocity; private int maximumFlingVelocity; - private int scrollbarSize; private int touchSlop; private int pagingTouchSlop; private int doubleTapSlop; @@ -70,7 +74,17 @@ public class ShadowViewConfiguration { fadingEdgeLength = (int) (density * ViewConfiguration.getFadingEdgeLength() + 0.5f); minimumFlingVelocity = (int) (density * ViewConfiguration.getMinimumFlingVelocity() + 0.5f); maximumFlingVelocity = (int) (density * ViewConfiguration.getMaximumFlingVelocity() + 0.5f); - scrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f); + int scrollbarSize; + if (RuntimeEnvironment.getApiLevel() >= P) { + scrollbarSize = + Resources.getSystem() + .getDimensionPixelSize( + reflector(AndroidInternalDimenReflector.class).getConfigScrollbarSize()); + } else { + scrollbarSize = (int) (density * ViewConfiguration.getScrollBarSize() + 0.5f); + } + reflector(ViewConfigurationReflector.class, realViewConfiguration) + .setScrollbarSize(scrollbarSize); touchSlop = (int) (density * TOUCH_SLOP + 0.5f); pagingTouchSlop = (int) (density * PAGING_TOUCH_SLOP + 0.5f); doubleTapSlop = (int) (density * DOUBLE_TAP_SLOP + 0.5f); @@ -89,7 +103,7 @@ public class ShadowViewConfiguration { ShadowViewConfiguration shadowViewConfiguration = Shadow.extract(viewConfiguration); shadowViewConfiguration.setup(context); - if (RuntimeEnvironment.getApiLevel() >= android.os.Build.VERSION_CODES.Q) { + if (RuntimeEnvironment.getApiLevel() >= Q) { reflector(ViewConfigurationReflector.class, viewConfiguration) .setConstructedWithContext(true); } @@ -98,16 +112,6 @@ public class ShadowViewConfiguration { } @Implementation - protected static int getScrollBarSize() { - return SCROLL_BAR_SIZE; - } - - @Implementation - protected int getScaledScrollBarSize() { - return scrollbarSize; - } - - @Implementation protected int getScaledFadingEdgeLength() { return fadingEdgeLength; } @@ -200,5 +204,21 @@ public class ShadowViewConfiguration { interface ViewConfigurationReflector { @Accessor("mConstructedWithContext") void setConstructedWithContext(boolean value); + + @Accessor("mScrollbarSize") + void setScrollbarSize(int value); + } + + /** + * Reflection is needed to access internal Android dimen constants, which are static final ints, + * so referencing them directly causes inlining. Note {@link AndroidInternalDimenReflector} is + * designed to be temporary until the real {@link + * android.view.ViewConfiguration#get(android.content.Context)} is called. + */ + @ForType(com.android.internal.R.dimen.class) + interface AndroidInternalDimenReflector { + @Static + @Accessor("config_scrollbarSize") + int getConfigScrollbarSize(); } } |