aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Hoisie <hoisie@google.com>2024-04-18 17:33:40 -0700
committerCopybara-Service <copybara-worker@google.com>2024-04-18 17:34:30 -0700
commit43a7f0b102a9350cdb379cf88329858a150a2e12 (patch)
tree5b1e0dc56fe3e014d269c105b75ef261123d3bf5
parent1920a4cbbf574f775bd360b901b3e4102b7ad8b4 (diff)
downloadrobolectric-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
-rw-r--r--integration_tests/ctesque/src/sharedTest/java/android/view/ViewConfigurationTest.java45
-rw-r--r--robolectric/src/test/java/org/robolectric/shadows/ShadowViewConfigurationTest.java19
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowViewConfiguration.java48
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();
}
}