1/* 2 * Copyright (C) 2017 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 */ 16package com.android.managedprovisioning.common; 17 18import static android.support.test.InstrumentationRegistry.getTargetContext; 19 20import static org.hamcrest.Matchers.equalTo; 21import static org.hamcrest.Matchers.lessThanOrEqualTo; 22import static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo; 23import static org.junit.Assert.assertThat; 24import static org.mockito.Matchers.any; 25import static org.mockito.Mockito.verify; 26import static org.mockito.Mockito.verifyNoMoreInteractions; 27import static org.mockito.Mockito.verifyZeroInteractions; 28 29import android.graphics.Rect; 30import android.support.test.filters.SmallTest; 31import android.view.TouchDelegate; 32import android.view.View; 33 34import org.junit.Before; 35import org.junit.Test; 36import org.mockito.ArgumentCaptor; 37import org.mockito.Captor; 38import org.mockito.Mock; 39import org.mockito.MockitoAnnotations; 40 41@SmallTest 42public class TouchTargetEnforcerTest { 43 private static final float SAMPLE_DENSITY = 2.625f; 44 private static final int TOLERANCE_PX = 2; 45 private static final int OFFSET_DEFAULT = 500; 46 47 @Mock private View mViewAncestor; 48 @Captor private ArgumentCaptor<Runnable> mArgumentCaptor; 49 private TouchTargetEnforcer mEnforcer; 50 private View mView; 51 private int mEdgeValue; 52 53 private Rect mCapturedBounds; 54 private View mCapturedTargetView; 55 56 @Before 57 public void setUp() { 58 MockitoAnnotations.initMocks(this); 59 mView = new View(getTargetContext()); 60 mEdgeValue = Math.round(TouchTargetEnforcer.MIN_TARGET_DP * SAMPLE_DENSITY); 61 62 mEnforcer = new TouchTargetEnforcer(SAMPLE_DENSITY, (bounds, target) -> { 63 mCapturedBounds = bounds; 64 mCapturedTargetView = target; 65 return new TouchDelegate(mCapturedBounds, mCapturedTargetView); 66 }); 67 68 mCapturedBounds = null; 69 mCapturedTargetView = null; 70 } 71 72 @Test 73 public void expansionNeededWidth() { 74 testExpansionNeeded(mEdgeValue - 1, mEdgeValue + 1); 75 } 76 77 @Test 78 public void expansionNeededHeight() { 79 testExpansionNeeded(mEdgeValue + 1, mEdgeValue - 1); 80 } 81 82 @Test 83 public void expansionNeededWidthHeight() { 84 testExpansionNeeded(mEdgeValue - 1, mEdgeValue - 1); 85 } 86 87 private void testExpansionNeeded(int width, int height) { 88 setViewDimen(width, height); 89 assertExpansionNeeded(width, height); 90 } 91 92 private void assertExpansionNeeded(int width, int height) { 93 // when 94 mEnforcer.enforce(mView, mViewAncestor); 95 mView.getViewTreeObserver().dispatchOnGlobalLayout(); // force try register Touch Delegate 96 97 // then 98 verify(mViewAncestor).post(mArgumentCaptor.capture()); // prep capture TouchDelegate args 99 mArgumentCaptor.getValue().run(); // capture args under mCapturedBounds 100 //noinspection ResultOfMethodCallIgnored 101 verify(mViewAncestor).getTouchDelegate(); 102 verify(mViewAncestor).setTouchDelegate(any()); 103 verifyNoMoreInteractions(mViewAncestor); 104 105 // verify end state correct 106 assertBoundsCorrect(width, mCapturedBounds.width()); 107 assertBoundsCorrect(height, mCapturedBounds.height()); 108 } 109 110 @Test 111 public void expansionNotNeeded() { 112 // given 113 setViewDimen(mEdgeValue + 1, mEdgeValue + 1); 114 assertThat(mView.getWidth(), greaterThanOrEqualTo(mEdgeValue)); 115 assertThat(mView.getHeight(), greaterThanOrEqualTo(mEdgeValue)); 116 117 // when 118 mEnforcer.enforce(mView, mViewAncestor); 119 mView.getViewTreeObserver().dispatchOnGlobalLayout(); // force UI queue to add a Runnable 120 121 // then 122 verifyZeroInteractions(mViewAncestor); 123 } 124 125 @Test 126 public void doesNotCrashOnEdges() { 127 setViewDimen(0, 0, 0); 128 assertExpansionNeeded(0, 0); 129 } 130 131 private void assertBoundsCorrect(int oldValue, int newValue) { 132 assertThat(newValue, greaterThanOrEqualTo(mEdgeValue)); 133 if (oldValue >= mEdgeValue) { 134 assertThat(newValue, equalTo(oldValue)); 135 } else { 136 assertThat(mCapturedBounds.width(), lessThanOrEqualTo(mEdgeValue + TOLERANCE_PX)); 137 } 138 } 139 140 private void setViewDimen(int width, int height) { 141 setViewDimen(width, height, OFFSET_DEFAULT); 142 } 143 144 private void setViewDimen(int width, int height, int offset) { 145 mView.setLeft(offset); 146 mView.setRight(offset + width); 147 mView.setTop(offset); 148 mView.setBottom(offset + height); 149 } 150}