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