1 /* 2 * Copyright (C) 2016 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.accessibilityservice.cts; 18 19 import android.accessibilityservice.AccessibilityService.MagnificationController; 20 import android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener; 21 import android.accessibilityservice.AccessibilityServiceInfo; 22 import android.content.res.Resources; 23 import android.graphics.Region; 24 import android.provider.Settings; 25 import android.test.InstrumentationTestCase; 26 import android.util.DisplayMetrics; 27 28 import java.util.concurrent.atomic.AtomicBoolean; 29 30 import static org.mockito.Mockito.*; 31 32 /** 33 * Class for testing {@link AccessibilityServiceInfo}. 34 */ 35 public class AccessibilityMagnificationTest extends InstrumentationTestCase { 36 37 /** Maximum timeout when waiting for a magnification callback. */ 38 public static final int LISTENER_TIMEOUT_MILLIS = 500; 39 public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = 40 "accessibility_display_magnification_enabled"; 41 private StubMagnificationAccessibilityService mService; 42 43 @Override 44 public void setUp() throws Exception { 45 super.setUp(); 46 ShellCommandBuilder.create(this) 47 .deleteSecureSetting(ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED) 48 .run(); 49 // Starting the service will force the accessibility subsystem to examine its settings, so 50 // it will update magnification in the process to disable it. 51 mService = StubMagnificationAccessibilityService.enableSelf(this); 52 } 53 54 @Override 55 protected void tearDown() throws Exception { 56 if (mService != null) { 57 mService.runOnServiceSync(() -> mService.disableSelfAndRemove()); 58 mService = null; 59 } 60 61 super.tearDown(); 62 } 63 64 public void testSetScale() { 65 final MagnificationController controller = mService.getMagnificationController(); 66 final float scale = 2.0f; 67 final AtomicBoolean result = new AtomicBoolean(); 68 69 mService.runOnServiceSync(() -> result.set(controller.setScale(scale, false))); 70 71 assertTrue("Failed to set scale", result.get()); 72 assertEquals("Failed to apply scale", scale, controller.getScale()); 73 74 mService.runOnServiceSync(() -> result.set(controller.reset(false))); 75 76 assertTrue("Failed to reset", result.get()); 77 assertEquals("Failed to apply reset", 1.0f, controller.getScale()); 78 } 79 80 public void testSetScaleAndCenter() { 81 final MagnificationController controller = mService.getMagnificationController(); 82 final Resources res = getInstrumentation().getTargetContext().getResources(); 83 final DisplayMetrics metrics = res.getDisplayMetrics(); 84 final float scale = 2.0f; 85 final float x = metrics.widthPixels / 4.0f; 86 final float y = metrics.heightPixels / 4.0f; 87 final AtomicBoolean setScale = new AtomicBoolean(); 88 final AtomicBoolean setCenter = new AtomicBoolean(); 89 final AtomicBoolean result = new AtomicBoolean(); 90 91 mService.runOnServiceSync(() -> { 92 setScale.set(controller.setScale(scale, false)); 93 setCenter.set(controller.setCenter(x, y, false)); 94 }); 95 96 assertTrue("Failed to set scale", setScale.get()); 97 assertEquals("Failed to apply scale", scale, controller.getScale()); 98 99 assertTrue("Failed to set center", setCenter.get()); 100 assertEquals("Failed to apply center X", x, controller.getCenterX(), 5.0f); 101 assertEquals("Failed to apply center Y", y, controller.getCenterY(), 5.0f); 102 103 mService.runOnServiceSync(() -> result.set(controller.reset(false))); 104 105 assertTrue("Failed to reset", result.get()); 106 assertEquals("Failed to apply reset", 1.0f, controller.getScale()); 107 } 108 109 public void testListener() { 110 final MagnificationController controller = mService.getMagnificationController(); 111 final OnMagnificationChangedListener listener = mock(OnMagnificationChangedListener.class); 112 controller.addListener(listener); 113 114 try { 115 final float scale = 2.0f; 116 final AtomicBoolean result = new AtomicBoolean(); 117 118 mService.runOnServiceSync(() -> result.set(controller.setScale(scale, false))); 119 120 assertTrue("Failed to set scale", result.get()); 121 verify(listener, timeout(LISTENER_TIMEOUT_MILLIS).atLeastOnce()).onMagnificationChanged( 122 eq(controller), any(Region.class), eq(scale), anyFloat(), anyFloat()); 123 124 mService.runOnServiceSync(() -> result.set(controller.reset(false))); 125 126 assertTrue("Failed to reset", result.get()); 127 verify(listener, timeout(LISTENER_TIMEOUT_MILLIS).atLeastOnce()).onMagnificationChanged( 128 eq(controller), any(Region.class), eq(1.0f), anyFloat(), anyFloat()); 129 } finally { 130 controller.removeListener(listener); 131 } 132 } 133 134 public void testMagnificationServiceShutsDownWhileMagnifying_shouldReturnTo1x() { 135 final MagnificationController controller = mService.getMagnificationController(); 136 mService.runOnServiceSync(() -> controller.setScale(2.0f, false)); 137 138 mService.runOnServiceSync(() -> mService.disableSelf()); 139 mService = null; 140 InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService( 141 this, InstrumentedAccessibilityService.class); 142 final MagnificationController controller2 = service.getMagnificationController(); 143 try { 144 assertEquals("Magnification must reset when a service dies", 145 1.0f, controller2.getScale()); 146 } finally { 147 service.runOnServiceSync(() -> service.disableSelf()); 148 } 149 } 150 151 public void testGetMagnificationRegion_whenCanControlMagnification_shouldNotBeEmpty() { 152 final MagnificationController controller = mService.getMagnificationController(); 153 Region magnificationRegion = controller.getMagnificationRegion(); 154 assertFalse("Magnification region should not be empty when " 155 + "magnification is being actively controlled", magnificationRegion.isEmpty()); 156 } 157 158 public void testGetMagnificationRegion_whenCantControlMagnification_shouldBeEmpty() { 159 mService.runOnServiceSync(() -> mService.disableSelf()); 160 mService = null; 161 InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService( 162 this, InstrumentedAccessibilityService.class); 163 try { 164 final MagnificationController controller = service.getMagnificationController(); 165 Region magnificationRegion = controller.getMagnificationRegion(); 166 assertTrue("Magnification region should be empty when magnification " 167 + "is not being actively controlled", magnificationRegion.isEmpty()); 168 } finally { 169 service.runOnServiceSync(() -> service.disableSelf()); 170 } 171 } 172 173 public void testGetMagnificationRegion_whenMagnificationGesturesEnabled_shouldNotBeEmpty() { 174 ShellCommandBuilder.create(this) 175 .putSecureSetting(ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, "1") 176 .run(); 177 mService.runOnServiceSync(() -> mService.disableSelf()); 178 mService = null; 179 InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService( 180 this, InstrumentedAccessibilityService.class); 181 try { 182 final MagnificationController controller = service.getMagnificationController(); 183 Region magnificationRegion = controller.getMagnificationRegion(); 184 assertFalse("Magnification region should not be empty when magnification " 185 + "gestures are active", magnificationRegion.isEmpty()); 186 } finally { 187 service.runOnServiceSync(() -> service.disableSelf()); 188 ShellCommandBuilder.create(this) 189 .deleteSecureSetting(ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED) 190 .run(); 191 } 192 } 193 194 public void testAnimatingMagnification() throws InterruptedException { 195 final MagnificationController controller = mService.getMagnificationController(); 196 final int timeBetweenAnimationChanges = 100; 197 198 final float scale1 = 5.0f; 199 final float x1 = 500; 200 final float y1 = 1000; 201 202 final float scale2 = 4.0f; 203 final float x2 = 500; 204 final float y2 = 1500; 205 206 final float scale3 = 2.1f; 207 final float x3 = 700; 208 final float y3 = 700; 209 210 for (int i = 0; i < 5; i++) { 211 mService.runOnServiceSync(() -> { 212 controller.setScale(scale1, true); 213 controller.setCenter(x1, y1, true); 214 }); 215 216 Thread.sleep(timeBetweenAnimationChanges); 217 218 mService.runOnServiceSync(() -> { 219 controller.setScale(scale2, true); 220 controller.setCenter(x2, y2, true); 221 }); 222 223 Thread.sleep(timeBetweenAnimationChanges); 224 225 mService.runOnServiceSync(() -> { 226 controller.setScale(scale3, true); 227 controller.setCenter(x3, y3, true); 228 }); 229 230 Thread.sleep(timeBetweenAnimationChanges); 231 } 232 } 233 } 234