1 /** 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 * express or implied. See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 15 package android.accessibilityservice.cts; 16 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO; 17 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN; 18 import static android.accessibilityservice.AccessibilityService.SHOW_MODE_IGNORE_HARD_KEYBOARD; 19 import static android.accessibilityservice.cts.utils.CtsTestUtils.runIfNotNull; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertTrue; 23 24 import android.accessibility.cts.common.InstrumentedAccessibilityService; 25 import android.accessibilityservice.AccessibilityService.SoftKeyboardController; 26 import android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener; 27 import android.accessibilityservice.cts.activities.AccessibilityTestActivity; 28 import android.accessibilityservice.cts.utils.AsyncUtils; 29 import android.app.Instrumentation; 30 import android.os.Bundle; 31 import android.os.SystemClock; 32 import android.platform.test.annotations.AppModeFull; 33 34 import androidx.test.InstrumentationRegistry; 35 import androidx.test.runner.AndroidJUnit4; 36 37 import org.junit.After; 38 import org.junit.Before; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 42 /** 43 * Test cases for testing the accessibility APIs for interacting with the soft keyboard show mode. 44 */ 45 @RunWith(AndroidJUnit4.class) 46 @AppModeFull 47 public class AccessibilitySoftKeyboardModesTest { 48 private int mLastCallbackValue; 49 50 private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); 51 private InstrumentedAccessibilityService mService; 52 private final Object mLock = new Object(); 53 private final OnShowModeChangedListener mListener = (c, showMode) -> { 54 synchronized (mLock) { 55 mLastCallbackValue = showMode; 56 mLock.notifyAll(); 57 } 58 }; 59 60 61 62 @Before setUp()63 public void setUp() throws Exception { 64 mService = InstrumentedAccessibilityService.enableService(mInstrumentation, 65 InstrumentedAccessibilityService.class); 66 } 67 68 @After tearDown()69 public void tearDown() throws Exception { 70 runIfNotNull(mService, service -> service.runOnServiceSync(service::disableSelf)); 71 } 72 73 @Test testApiReturnValues_shouldChangeValueOnRequestAndSendCallback()74 public void testApiReturnValues_shouldChangeValueOnRequestAndSendCallback() throws Exception { 75 final SoftKeyboardController controller = mService.getSoftKeyboardController(); 76 77 // Confirm that we start in the default state 78 assertEquals(SHOW_MODE_AUTO, controller.getShowMode()); 79 80 controller.addOnShowModeChangedListener(mListener); 81 assertCanSetAndGetShowModeAndCallbackHappens(SHOW_MODE_HIDDEN, mService); 82 assertCanSetAndGetShowModeAndCallbackHappens(SHOW_MODE_IGNORE_HARD_KEYBOARD, mService); 83 assertCanSetAndGetShowModeAndCallbackHappens(SHOW_MODE_AUTO, mService); 84 85 // Make sure we can remove our listener. 86 assertTrue(controller.removeOnShowModeChangedListener(mListener)); 87 } 88 89 @Test secondServiceChangingTheShowMode_updatesModeAndNotifiesFirstService()90 public void secondServiceChangingTheShowMode_updatesModeAndNotifiesFirstService() 91 throws Exception { 92 93 final SoftKeyboardController controller = mService.getSoftKeyboardController(); 94 // Confirm that we start in the default state 95 assertEquals(SHOW_MODE_AUTO, controller.getShowMode()); 96 97 final InstrumentedAccessibilityService secondService = 98 StubAccessibilityButtonService.enableSelf(mInstrumentation); 99 try { 100 // Listen on the first service 101 controller.addOnShowModeChangedListener(mListener); 102 assertCanSetAndGetShowModeAndCallbackHappens(SHOW_MODE_HIDDEN, mService); 103 104 // Change the mode on the second service 105 assertCanSetAndGetShowModeAndCallbackHappens(SHOW_MODE_IGNORE_HARD_KEYBOARD, 106 secondService); 107 } finally { 108 secondService.runOnServiceSync(() -> secondService.disableSelf()); 109 } 110 111 // Shutting down the second service, which was controlling the mode, should put us back 112 // to the default 113 waitForCallbackValueWithLock(SHOW_MODE_AUTO); 114 final int showMode = mService.getOnService(() -> controller.getShowMode()); 115 assertEquals(SHOW_MODE_AUTO, showMode); 116 } 117 assertCanSetAndGetShowModeAndCallbackHappens( int mode, InstrumentedAccessibilityService service)118 private void assertCanSetAndGetShowModeAndCallbackHappens( 119 int mode, InstrumentedAccessibilityService service) 120 throws Exception { 121 final SoftKeyboardController controller = service.getSoftKeyboardController(); 122 mLastCallbackValue = -1; 123 final boolean setShowModeReturns = 124 service.getOnService(() -> controller.setShowMode(mode)); 125 assertTrue(setShowModeReturns); 126 waitForCallbackValueWithLock(mode); 127 assertEquals(mode, controller.getShowMode()); 128 } 129 waitForCallbackValueWithLock(int expectedValue)130 private void waitForCallbackValueWithLock(int expectedValue) throws Exception { 131 long timeoutTimeMillis = SystemClock.uptimeMillis() + AsyncUtils.DEFAULT_TIMEOUT_MS; 132 133 while (SystemClock.uptimeMillis() < timeoutTimeMillis) { 134 synchronized(mLock) { 135 if (mLastCallbackValue == expectedValue) { 136 return; 137 } 138 try { 139 mLock.wait(timeoutTimeMillis - SystemClock.uptimeMillis()); 140 } catch (InterruptedException e) { 141 // Wait until timeout. 142 } 143 } 144 } 145 146 throw new IllegalStateException("last callback value <" + mLastCallbackValue 147 + "> does not match expected value < " + expectedValue + ">"); 148 } 149 150 /** 151 * Activity for testing the AccessibilityService API for hiding and showing the soft keyboard. 152 */ 153 public static class SoftKeyboardModesActivity extends AccessibilityTestActivity { SoftKeyboardModesActivity()154 public SoftKeyboardModesActivity() { 155 super(); 156 } 157 158 @Override onCreate(Bundle savedInstanceState)159 public void onCreate(Bundle savedInstanceState) { 160 super.onCreate(savedInstanceState); 161 setContentView(R.layout.accessibility_soft_keyboard_modes_test); 162 } 163 } 164 } 165