1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22 
23 import android.content.Context;
24 import android.graphics.Point;
25 import android.platform.test.annotations.AppModeSdkSandbox;
26 import android.util.TypedValue;
27 import android.view.Display;
28 import android.view.InputDevice;
29 import android.view.MotionEvent;
30 import android.view.ViewConfiguration;
31 import android.view.WindowManager;
32 import android.view.cts.util.InputDeviceIterators;
33 
34 import androidx.test.InstrumentationRegistry;
35 import androidx.test.filters.SmallTest;
36 import androidx.test.runner.AndroidJUnit4;
37 
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.util.Set;
42 
43 /**
44  * Test {@link ViewConfiguration}.
45  */
46 @SmallTest
47 @RunWith(AndroidJUnit4.class)
48 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).")
49 public class ViewConfigurationTest {
50     private static Set<Integer> SUPPORTED_AXES_FOR_SCROLL_HAPTICS = Set.of(MotionEvent.AXIS_SCROLL);
51 
52     @Test
testStaticValues()53     public void testStaticValues() {
54         ViewConfiguration.getScrollBarSize();
55         ViewConfiguration.getFadingEdgeLength();
56         ViewConfiguration.getPressedStateDuration();
57         ViewConfiguration.getLongPressTimeout();
58         assertTrue(ViewConfiguration.getMultiPressTimeout() > 0);
59         ViewConfiguration.getTapTimeout();
60         ViewConfiguration.getJumpTapTimeout();
61         ViewConfiguration.getEdgeSlop();
62         ViewConfiguration.getTouchSlop();
63         ViewConfiguration.getWindowTouchSlop();
64         ViewConfiguration.getMinimumFlingVelocity();
65         ViewConfiguration.getMaximumFlingVelocity();
66         ViewConfiguration.getMaximumDrawingCacheSize();
67         ViewConfiguration.getZoomControlsTimeout();
68         ViewConfiguration.getGlobalActionKeyTimeout();
69         ViewConfiguration.getScrollFriction();
70         ViewConfiguration.getScrollBarFadeDuration();
71         ViewConfiguration.getScrollDefaultDelay();
72         ViewConfiguration.getDoubleTapTimeout();
73         ViewConfiguration.getKeyRepeatTimeout();
74         ViewConfiguration.getKeyRepeatDelay();
75         ViewConfiguration.getDefaultActionModeHideDuration();
76     }
77 
78     @Test
testConstructor()79     public void testConstructor() {
80         new ViewConfiguration();
81     }
82 
83     @Test
testInstanceValues()84     public void testInstanceValues() {
85         Context context = InstrumentationRegistry.getTargetContext();
86         ViewConfiguration vc = ViewConfiguration.get(context);
87         assertNotNull(vc);
88 
89         vc.getScaledDoubleTapSlop();
90         vc.getScaledEdgeSlop();
91         vc.getScaledFadingEdgeLength();
92         vc.getScaledMaximumDrawingCacheSize();
93         vc.getScaledMaximumFlingVelocity();
94         vc.getScaledMinimumFlingVelocity();
95         vc.getScaledOverflingDistance();
96         vc.getScaledOverscrollDistance();
97         vc.getScaledPagingTouchSlop();
98         vc.getScaledScrollBarSize();
99         vc.getScaledHorizontalScrollFactor();
100         vc.getScaledVerticalScrollFactor();
101         vc.getScaledTouchSlop();
102         vc.getScaledHandwritingSlop();
103         vc.getScaledWindowTouchSlop();
104         vc.hasPermanentMenuKey();
105 
106         float pixelsToMmRatio = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,
107                 context.getResources().getDisplayMetrics());
108 
109         // Verify that the min scaling span size is reasonable.
110         float scaledMinScalingSpanMm = vc.getScaledMinimumScalingSpan() / pixelsToMmRatio;
111         assertTrue(scaledMinScalingSpanMm > 0);
112         assertTrue(scaledMinScalingSpanMm < 40.5); // 1.5 times the recommended size of 27mm
113     }
114 
115     @Test
116     public void testExceptionsThrown() {
117         ViewConfiguration vc = new ViewConfiguration();
118         boolean correctExceptionThrown = false;
119         try {
120             vc.getScaledMinimumScalingSpan();
121         } catch (IllegalStateException e) {
122             if (e.getMessage().equals("Min scaling span cannot be determined when this "
123                     + "method is called on a ViewConfiguration that was instantiated using a "
124                     + "constructor with no Context parameter")) {
125                 correctExceptionThrown = true;
126             }
127         }
128         assertTrue(correctExceptionThrown);
129     }
130 
131     /**
132      * The purpose of the ambiguous gesture multiplier is to potentially increase the touch slop
133      * and the long press timeout to allow the gesture classifier an additional window to
134      * make the classification. Therefore, this multiplier should be always greater or equal to 1.
135      */
136     @Test
137     public void testGetAmbiguousGestureMultiplier() {
138         final float staticMultiplier = ViewConfiguration.getAmbiguousGestureMultiplier();
139         assertTrue(staticMultiplier >= 1);
140 
141         ViewConfiguration vc = ViewConfiguration.get(InstrumentationRegistry.getTargetContext());
142         final float instanceMultiplier = vc.getAmbiguousGestureMultiplier();
143         assertTrue(instanceMultiplier >= 1);
144     }
145 
146     @Test
testFlingThresholds_forInvalidInputDeviceIds()147     public void testFlingThresholds_forInvalidInputDeviceIds() {
148         Context context = InstrumentationRegistry.getTargetContext();
149         ViewConfiguration contextBasedVc = ViewConfiguration.get(context);
150         ViewConfiguration contextLessVc = new ViewConfiguration();
151         for (ViewConfiguration vc : new ViewConfiguration[] {contextBasedVc, contextLessVc}) {
152             InputDeviceIterators.iteratorOverInvalidDeviceIds((deviceId) -> {
153                 // Test with some source-axis combinations. Any source-axis combination should
154                 // provide the no-fling thresholds, since the device ID is known to be invalid.
155                 verifyNoFlingThresholds(
156                         vc, deviceId, InputDevice.SOURCE_TOUCHSCREEN, MotionEvent.AXIS_X);
157                 verifyNoFlingThresholds(
158                         vc, deviceId, InputDevice.SOURCE_TOUCHSCREEN, MotionEvent.AXIS_Y);
159                 verifyNoFlingThresholds(
160                         vc, deviceId, InputDevice.SOURCE_ROTARY_ENCODER, MotionEvent.AXIS_SCROLL);
161             });
162         }
163     }
164 
165     @Test
testFlingThresholds_forAllAvailableDevices()166     public void testFlingThresholds_forAllAvailableDevices() {
167         Context context = InstrumentationRegistry.getTargetContext();
168         ViewConfiguration contextBasedVc = ViewConfiguration.get(context);
169         ViewConfiguration contextLessVc = new ViewConfiguration();
170         for (ViewConfiguration vc : new ViewConfiguration[] {contextBasedVc, contextLessVc}) {
171             InputDeviceIterators.iteratorOverEveryInputDeviceMotionRange((deviceId, range) -> {
172                 int axis = range.getAxis();
173                 int source = range.getSource();
174 
175                 int minVel = vc.getScaledMinimumFlingVelocity(deviceId, axis, source);
176                 int maxVel = vc.getScaledMaximumFlingVelocity(deviceId, axis, source);
177 
178                 // These min/max thresholds are thresholds for a valid InputDevice ID, on a
179                 // source and axis applicable to the InputDevice represented by the ID. Check
180                 // that the provided thresholds are within the valid bounds.
181                 verifyFlingThresholdRange(minVel, maxVel);
182             });
183             InputDeviceIterators.iteratorOverEveryValidDeviceId((deviceId) -> {
184                 // Test with source-axis combinations that we know are not valid. Since the
185                 // source-axis combinations will be invalid, we expect the no-fling thresholds,
186                 // despite the fact that we're using a valid InputDevice ID.
187                 verifyNoFlingThresholds(
188                         vc, deviceId, InputDevice.SOURCE_ROTARY_ENCODER, MotionEvent.AXIS_X);
189                 verifyNoFlingThresholds(
190                         vc, deviceId, InputDevice.SOURCE_TOUCHSCREEN, MotionEvent.AXIS_WHEEL);
191             });
192         }
193     }
194 
195     @Test
testGetScaledAmbiguousGestureMultiplier()196     public void testGetScaledAmbiguousGestureMultiplier() {
197         ViewConfiguration vc = ViewConfiguration.get(InstrumentationRegistry.getTargetContext());
198         final float instanceMultiplier = vc.getScaledAmbiguousGestureMultiplier();
199         assertTrue(instanceMultiplier >= 1);
200     }
201 
202     @Test
testGetMaximumDrawingCacheSize()203     public void testGetMaximumDrawingCacheSize() {
204         Context context = InstrumentationRegistry.getTargetContext();
205         ViewConfiguration vc = ViewConfiguration.get(context);
206         assertNotNull(vc);
207 
208         // Should be at least the size of the screen we're supposed to draw into.
209         final WindowManager win = context.getSystemService(WindowManager.class);
210         final Display display = win.getDefaultDisplay();
211         final Point size = new Point();
212         display.getSize(size);
213         assertTrue(vc.getScaledMaximumDrawingCacheSize() >= size.x * size.y * 4);
214 
215         // This deprecated value should just be what it's historically hardcoded to be.
216         assertEquals(480 * 800 * 4, vc.getMaximumDrawingCacheSize());
217     }
218 
219     /** Verifies whether or not the given fling thresholds are within the valid range. */
verifyFlingThresholdRange(int minVel, int maxVel)220     private static void verifyFlingThresholdRange(int minVel, int maxVel) {
221         if (minVel > maxVel) {
222             // The only case where we expect the minimum velocity to exceed the maximum velocity is
223             // for InputDevices that do not support fling, in which case the minimum and maximum
224             // velocties are set to Integer's max and min values, respectively.
225             verifyNoFlingThresholds(minVel, maxVel);
226         } else {
227             // If the minimum velocity is <= the maximum velocity, the velocities should represent
228             // valid thresholds, which should not be negative values (as the thresholds are defined
229             // as absolute values).
230             assertTrue(minVel >= 0);
231             assertTrue(maxVel >= 0);
232         }
233     }
234 
verifyNoFlingThresholds( ViewConfiguration viewConfiguration, int deviceId, int source, int axis)235     private static void verifyNoFlingThresholds(
236             ViewConfiguration viewConfiguration, int deviceId, int source, int axis) {
237         verifyNoFlingThresholds(
238             viewConfiguration.getScaledMinimumFlingVelocity(deviceId, axis, source),
239             viewConfiguration.getScaledMaximumFlingVelocity(deviceId, axis, source));
240     }
241 
242     /**
243      * Verifies that the given min and max fling velocities represent the values used to suppress
244      * fling.
245      */
verifyNoFlingThresholds(int minVel, int maxVel)246     private static void verifyNoFlingThresholds(int minVel, int maxVel) {
247         assertEquals(Integer.MAX_VALUE, minVel);
248         assertEquals(Integer.MIN_VALUE, maxVel);
249     }
250 }
251