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 */ 16 17 package android.autofillservice.cts; 18 19 import static android.autofillservice.cts.Helper.callbackEventAsString; 20 import static android.autofillservice.cts.Timeouts.CONNECTION_TIMEOUT; 21 22 import static com.google.common.truth.Truth.assertWithMessage; 23 24 import android.util.Log; 25 import android.view.View; 26 import android.view.autofill.AutofillManager.AutofillCallback; 27 28 import java.util.concurrent.BlockingQueue; 29 import java.util.concurrent.LinkedBlockingQueue; 30 import java.util.concurrent.TimeUnit; 31 32 /** 33 * Custom {@link AutofillCallback} used to recover events during tests. 34 */ 35 final class MyAutofillCallback extends AutofillCallback { 36 37 private static final String TAG = "MyAutofillCallback"; 38 private final BlockingQueue<MyEvent> mEvents = new LinkedBlockingQueue<>(); 39 40 public static final Timeout MY_TIMEOUT = CONNECTION_TIMEOUT; 41 42 @Override onAutofillEvent(View view, int event)43 public void onAutofillEvent(View view, int event) { 44 Log.v(TAG, "onAutofillEvent: view=" + view + ", event=" + callbackEventAsString(event)); 45 mEvents.offer(new MyEvent(view, event)); 46 } 47 48 @Override onAutofillEvent(View view, int childId, int event)49 public void onAutofillEvent(View view, int childId, int event) { 50 Log.v(TAG, "onAutofillEvent: view=" + view + ", child=" + childId 51 + ", event=" + callbackEventAsString(event)); 52 mEvents.offer(new MyEvent(view, childId, event)); 53 } 54 55 /** 56 * Gets the next available event or fail if it times out. 57 */ getEvent()58 MyEvent getEvent() throws InterruptedException { 59 final MyEvent event = mEvents.poll(CONNECTION_TIMEOUT.ms(), TimeUnit.MILLISECONDS); 60 if (event == null) { 61 throw new RetryableException(CONNECTION_TIMEOUT, "no event"); 62 } 63 return event; 64 } 65 66 /** 67 * Assert no more events were received. 68 */ assertNotCalled()69 void assertNotCalled() throws InterruptedException { 70 final MyEvent event = mEvents.poll(CONNECTION_TIMEOUT.ms(), TimeUnit.MILLISECONDS); 71 if (event != null) { 72 // Not retryable. 73 throw new IllegalStateException("should not have received " + event); 74 } 75 } 76 77 /** 78 * Used to assert there is no event left behind. 79 */ assertNumberUnhandledEvents(int expected)80 void assertNumberUnhandledEvents(int expected) { 81 assertWithMessage("Invalid number of events left: %s", mEvents).that(mEvents.size()) 82 .isEqualTo(expected); 83 } 84 85 /** 86 * Convenience method to assert an UI shown event for the given view was received. 87 */ assertUiShownEvent(View expectedView)88 MyEvent assertUiShownEvent(View expectedView) throws InterruptedException { 89 final MyEvent event = getEvent(); 90 assertWithMessage("Invalid type on event %s", event).that(event.event) 91 .isEqualTo(EVENT_INPUT_SHOWN); 92 assertWithMessage("Invalid view on event %s", event).that(event.view) 93 .isSameAs(expectedView); 94 return event; 95 } 96 97 /** 98 * Convenience method to assert an UI shown event for the given virtual view was received. 99 */ assertUiShownEvent(View expectedView, int expectedChildId)100 void assertUiShownEvent(View expectedView, int expectedChildId) throws InterruptedException { 101 final MyEvent event = assertUiShownEvent(expectedView); 102 assertWithMessage("Invalid child on event %s", event).that(event.childId) 103 .isEqualTo(expectedChildId); 104 } 105 106 /** 107 * Convenience method to assert an UI shown event a virtual view was received. 108 * 109 * @return virtual child id 110 */ assertUiShownEventForVirtualChild(View expectedView)111 int assertUiShownEventForVirtualChild(View expectedView) throws InterruptedException { 112 final MyEvent event = assertUiShownEvent(expectedView); 113 return event.childId; 114 } 115 116 /** 117 * Convenience method to assert an UI hidden event for the given view was received. 118 */ assertUiHiddenEvent(View expectedView)119 MyEvent assertUiHiddenEvent(View expectedView) throws InterruptedException { 120 final MyEvent event = getEvent(); 121 assertWithMessage("Invalid type on event %s", event).that(event.event) 122 .isEqualTo(EVENT_INPUT_HIDDEN); 123 assertWithMessage("Invalid view on event %s", event).that(event.view) 124 .isSameAs(expectedView); 125 return event; 126 } 127 128 /** 129 * Convenience method to assert an UI hidden event for the given view was received. 130 */ assertUiHiddenEvent(View expectedView, int expectedChildId)131 void assertUiHiddenEvent(View expectedView, int expectedChildId) throws InterruptedException { 132 final MyEvent event = assertUiHiddenEvent(expectedView); 133 assertWithMessage("Invalid child on event %s", event).that(event.childId) 134 .isEqualTo(expectedChildId); 135 } 136 137 /** 138 * Convenience method to assert an UI unavailable event for the given view was received. 139 */ assertUiUnavailableEvent(View expectedView)140 MyEvent assertUiUnavailableEvent(View expectedView) throws InterruptedException { 141 final MyEvent event = getEvent(); 142 assertWithMessage("Invalid type on event %s", event).that(event.event) 143 .isEqualTo(EVENT_INPUT_UNAVAILABLE); 144 assertWithMessage("Invalid view on event %s", event).that(event.view) 145 .isSameAs(expectedView); 146 return event; 147 } 148 149 /** 150 * Convenience method to assert an UI unavailable event for the given view was received. 151 */ assertUiUnavailableEvent(View expectedView, int expectedChildId)152 void assertUiUnavailableEvent(View expectedView, int expectedChildId) 153 throws InterruptedException { 154 final MyEvent event = assertUiUnavailableEvent(expectedView); 155 assertWithMessage("Invalid child on event %s", event).that(event.childId) 156 .isEqualTo(expectedChildId); 157 } 158 159 private static final class MyEvent { 160 public final View view; 161 public final int childId; 162 public final int event; 163 MyEvent(View view, int event)164 MyEvent(View view, int event) { 165 this(view, View.NO_ID, event); 166 } 167 MyEvent(View view, int childId, int event)168 MyEvent(View view, int childId, int event) { 169 this.view = view; 170 this.childId = childId; 171 this.event = event; 172 } 173 174 @Override toString()175 public String toString() { 176 return callbackEventAsString(event) + ": " + view + " (childId: " + childId + ")"; 177 } 178 } 179 } 180