1 /*
2  * Copyright (C) 2020 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.inputmethodservice.cts.devicetest;
18 
19 import static org.junit.Assert.assertTrue;
20 import static org.junit.Assume.assumeTrue;
21 
22 import android.app.Instrumentation;
23 import android.app.UiAutomation;
24 import android.inputmethodservice.cts.ime.Watermark;
25 import android.os.SystemClock;
26 
27 import androidx.annotation.NonNull;
28 import androidx.test.platform.app.InstrumentationRegistry;
29 
30 import java.util.concurrent.CountDownLatch;
31 import java.util.concurrent.TimeUnit;
32 
33 /**
34  * Provides utility methods to test whether test IMEs are visible to the user or not.
35  */
36 final class InputMethodVisibilityVerifier {
37 
38     private static final long SCREENSHOT_DELAY = 100;  // msec
39     private static final long SCREENSHOT_TIME_SLICE = 500;  // msec
40 
41     @NonNull
containsWatermark(@onNull UiAutomation uiAutomation, @NonNull Watermark watermark)42     private static boolean containsWatermark(@NonNull UiAutomation uiAutomation,
43             @NonNull Watermark watermark) {
44         return watermark.isContainedIn(uiAutomation.takeScreenshot());
45     }
46 
waitUntilWatermarkBecomesVisible(long timeout, @NonNull Watermark watermark)47     private static boolean waitUntilWatermarkBecomesVisible(long timeout,
48             @NonNull Watermark watermark) {
49         final long startTime = SystemClock.elapsedRealtime();
50         SystemClock.sleep(SCREENSHOT_DELAY);
51 
52         final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
53 
54         // Wait until the main thread becomes idle.
55         final CountDownLatch latch = new CountDownLatch(1);
56         instrumentation.waitForIdle(latch::countDown);
57         try {
58             if (!latch.await(timeout, TimeUnit.MILLISECONDS)) {
59                 return false;
60             }
61         } catch (InterruptedException e) {
62         }
63 
64         final UiAutomation uiAutomation = instrumentation.getUiAutomation();
65 
66         // Make sure the watermark is tested at least two times, regardless of the timeout.
67         boolean firstCheck = true;
68         while (true) {
69             final boolean lastCheck;
70             if (firstCheck) {
71                 firstCheck = false;
72                 lastCheck = false;
73             } else {
74                 SystemClock.sleep(SCREENSHOT_TIME_SLICE);
75                 lastCheck = (SystemClock.elapsedRealtime() - startTime) >= timeout;
76             }
77             if (containsWatermark(uiAutomation, watermark)) {
78                 return true;
79             }
80             if (lastCheck) {
81                 return false;
82             }
83         }
84     }
85 
86     /**
87      * Asserts that IME1 is visible to the user.
88      *
89      * @param timeout timeout in milliseconds.
90      */
assertIme1Visible(long timeout)91     static void assertIme1Visible(long timeout) {
92         assertTrue(waitUntilWatermarkBecomesVisible(timeout, Watermark.IME1));
93     }
94 
95     /**
96      * Assumes that IME1 is visible to the user.
97      *
98      * @param message message to be shown when the assumption is not satisfied.
99      * @param timeout timeout in milliseconds.
100      */
assumeIme1Visible(String message, long timeout)101     static void assumeIme1Visible(String message, long timeout) {
102         assumeTrue(message, waitUntilWatermarkBecomesVisible(timeout, Watermark.IME1));
103     }
104 
105     /**
106      * Asserts that IME2 is visible to the user.
107      *
108      * @param timeout timeout in milliseconds.
109      */
assertIme2Visible(long timeout)110     static void assertIme2Visible(long timeout) {
111         assertTrue(waitUntilWatermarkBecomesVisible(timeout, Watermark.IME2));
112     }
113 }
114