• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.testcore;
18 
19 import static android.autofillservice.cts.testcore.Timeouts.CONNECTION_TIMEOUT;
20 import static android.view.autofill.AutofillManager.MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS;
21 
22 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
23 
24 import static com.google.common.truth.Truth.assertWithMessage;
25 
26 import android.app.Activity;
27 import android.app.assist.AssistStructure;
28 import android.autofillservice.cts.testcore.CtsAugmentedAutofillService.AugmentedFillRequest;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.service.autofill.augmented.FillRequest;
32 import android.util.Log;
33 import android.util.Pair;
34 import android.view.autofill.AutofillId;
35 import android.view.autofill.AutofillValue;
36 import android.view.inputmethod.InlineSuggestionsRequest;
37 
38 import androidx.annotation.NonNull;
39 import androidx.annotation.Nullable;
40 
41 import com.android.cts.mockime.MockImeSession;
42 
43 import java.util.List;
44 import java.util.Objects;
45 import java.util.concurrent.CountDownLatch;
46 import java.util.concurrent.TimeUnit;
47 
48 /**
49  * Helper for common funcionalities.
50  */
51 public final class AugmentedHelper {
52 
53     private static final String TAG = AugmentedHelper.class.getSimpleName();
54 
55     @NonNull
getActivityName(@ullable FillRequest request)56     public static String getActivityName(@Nullable FillRequest request) {
57         if (request == null) return "N/A (null request)";
58 
59         final ComponentName componentName = request.getActivityComponent();
60         if (componentName == null) return "N/A (no component name)";
61 
62         return componentName.flattenToShortString();
63     }
64 
65     /**
66      * Sets the augmented capture service.
67      */
setAugmentedService(@onNull String service)68     public static void setAugmentedService(@NonNull String service) {
69         Log.d(TAG, "Setting service to " + service);
70         runShellCommand("cmd autofill set temporary-augmented-service 0 %s %d", service,
71                 MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS);
72     }
73 
74     /**
75      * Resets the content capture service.
76      */
resetAugmentedService()77     public static void resetAugmentedService() {
78         Log.d(TAG, "Resetting back to default service");
79         runShellCommand("cmd autofill set temporary-augmented-service 0");
80     }
81 
82     /**
83      * Returns whether MockIme is available.
84      */
mockImeIsAvailable(Context context)85     public static boolean mockImeIsAvailable(Context context) {
86         return MockImeSession.getUnavailabilityReason(context) == null;
87     }
88 
assertBasicRequestInfo(@onNull AugmentedFillRequest request, @NonNull Activity activity, @NonNull AutofillId expectedFocusedId, @Nullable AutofillValue expectedFocusedValue)89     public static void assertBasicRequestInfo(@NonNull AugmentedFillRequest request,
90             @NonNull Activity activity, @NonNull AutofillId expectedFocusedId,
91             @Nullable AutofillValue expectedFocusedValue) {
92         final boolean hasDefaultInlineRequest = mockImeIsAvailable(activity.getBaseContext());
93         assertBasicRequestInfo(request, activity, expectedFocusedId, expectedFocusedValue,
94                 hasDefaultInlineRequest);
95     }
96 
assertBasicRequestInfo(@onNull AugmentedFillRequest request, @NonNull Activity activity, @NonNull AutofillId expectedFocusedId, @Nullable AutofillValue expectedFocusedValue, boolean hasInlineRequest)97     public static void assertBasicRequestInfo(@NonNull AugmentedFillRequest request,
98             @NonNull Activity activity, @NonNull AutofillId expectedFocusedId,
99             @Nullable AutofillValue expectedFocusedValue, boolean hasInlineRequest) {
100         Objects.requireNonNull(activity);
101         Objects.requireNonNull(expectedFocusedId);
102         assertWithMessage("no AugmentedFillRequest").that(request).isNotNull();
103         assertWithMessage("no FillRequest on %s", request).that(request.request).isNotNull();
104         assertWithMessage("no FillController on %s", request).that(request.controller).isNotNull();
105         assertWithMessage("no FillCallback on %s", request).that(request.callback).isNotNull();
106         assertWithMessage("no CancellationSignal on %s", request).that(request.cancellationSignal)
107                 .isNotNull();
108         // NOTE: task id can change, we might need to set it in the activity's onCreate()
109         assertWithMessage("wrong task id on %s", request).that(request.request.getTaskId())
110                 .isEqualTo(activity.getTaskId());
111 
112         final ComponentName actualComponentName = request.request.getActivityComponent();
113         assertWithMessage("no activity name on %s", request).that(actualComponentName).isNotNull();
114         assertWithMessage("wrong activity name on %s", request).that(actualComponentName)
115                 .isEqualTo(activity.getComponentName());
116         final AutofillId actualFocusedId = request.request.getFocusedId();
117         assertWithMessage("no focused id on %s", request).that(actualFocusedId).isNotNull();
118         assertWithMessage("wrong focused id on %s", request).that(actualFocusedId)
119                 .isEqualTo(expectedFocusedId);
120         final AutofillValue actualFocusedValue = request.request.getFocusedValue();
121         if (expectedFocusedValue != null) {
122             assertWithMessage("no focused value on %s", request).that(
123                     actualFocusedValue).isNotNull();
124             assertAutofillValue(expectedFocusedValue, actualFocusedValue);
125         } else {
126             assertWithMessage("expecting null focused value on %s", request).that(
127                     actualFocusedValue).isNull();
128         }
129         if (expectedFocusedId.isNonVirtual()) {
130             final AssistStructure.ViewNode focusedViewNode = request.request.getFocusedViewNode();
131             assertWithMessage("no focused view node on %s", request).that(
132                     focusedViewNode).isNotNull();
133             assertWithMessage("wrong autofill id in focused view node %s", focusedViewNode).that(
134                     focusedViewNode.getAutofillId()).isEqualTo(expectedFocusedId);
135             assertWithMessage("unexpected autofill value in focused view node %s",
136                     focusedViewNode).that(focusedViewNode.getAutofillValue()).isEqualTo(
137                     expectedFocusedValue);
138             assertWithMessage("children nodes should not be populated for focused view node %s",
139                     focusedViewNode).that(
140                     focusedViewNode.getChildCount()).isEqualTo(0);
141         }
142         final InlineSuggestionsRequest inlineRequest =
143                 request.request.getInlineSuggestionsRequest();
144         if (hasInlineRequest) {
145             assertWithMessage("no inline request on %s", request).that(inlineRequest).isNotNull();
146         } else {
147             assertWithMessage("exist inline request on %s", request).that(inlineRequest).isNull();
148         }
149     }
150 
assertAutofillValue(@onNull AutofillValue expectedValue, @NonNull AutofillValue actualValue)151     public static void assertAutofillValue(@NonNull AutofillValue expectedValue,
152             @NonNull AutofillValue actualValue) {
153         // It only supports text values for now...
154         assertWithMessage("expected value is not text: %s", expectedValue)
155                 .that(expectedValue.isText()).isTrue();
156         assertAutofillValue(expectedValue.getTextValue().toString(), actualValue);
157     }
158 
assertAutofillValue(@onNull String expectedValue, @NonNull AutofillValue actualValue)159     public static void assertAutofillValue(@NonNull String expectedValue,
160             @NonNull AutofillValue actualValue) {
161         assertWithMessage("actual value is not text: %s", actualValue)
162                 .that(actualValue.isText()).isTrue();
163 
164         assertWithMessage("wrong autofill value").that(actualValue.getTextValue().toString())
165                 .isEqualTo(expectedValue);
166     }
167 
168     @NonNull
toString(@ullable List<Pair<AutofillId, AutofillValue>> values)169     public static String toString(@Nullable List<Pair<AutofillId, AutofillValue>> values) {
170         if (values == null) return "null";
171         final StringBuilder string = new StringBuilder("[");
172         final int size = values.size();
173         for (int i = 0; i < size; i++) {
174             final Pair<AutofillId, AutofillValue> value = values.get(i);
175             string.append(i).append(':').append(value.first).append('=')
176                    .append(Helper.toString(value.second));
177             if (i < size - 1) {
178                 string.append(", ");
179             }
180 
181         }
182         return string.append(']').toString();
183     }
184 
185     @NonNull
toString(@ullable FillRequest request)186     public static String toString(@Nullable FillRequest request) {
187         if (request == null) return "(null request)";
188 
189         final StringBuilder string =
190                 new StringBuilder("FillRequest[act=").append(getActivityName(request))
191                 .append(", taskId=").append(request.getTaskId());
192 
193         final AutofillId focusedId = request.getFocusedId();
194         if (focusedId != null) {
195             string.append(", focusedId=").append(focusedId);
196         }
197         final AutofillValue focusedValue = request.getFocusedValue();
198         if (focusedValue != null) {
199             string.append(", focusedValue=").append(focusedValue);
200         }
201 
202         return string.append(']').toString();
203     }
204 
205     // Used internally by UiBot to assert the UI
getContentDescriptionForUi(@onNull AutofillId focusedId)206     public static String getContentDescriptionForUi(@NonNull AutofillId focusedId) {
207         return "ui_for_" + focusedId;
208     }
209 
AugmentedHelper()210     private AugmentedHelper() {
211         throw new UnsupportedOperationException("contain static methods only");
212     }
213 
214     /**
215      * Awaits for a latch to be counted down.
216      */
await(@onNull CountDownLatch latch, @NonNull String fmt, @Nullable Object... args)217     public static void await(@NonNull CountDownLatch latch, @NonNull String fmt,
218             @Nullable Object... args)
219             throws InterruptedException {
220         final boolean called = latch.await(CONNECTION_TIMEOUT.ms(), TimeUnit.MILLISECONDS);
221         if (!called) {
222             throw new IllegalStateException(String.format(fmt, args)
223                     + " in " + CONNECTION_TIMEOUT.ms() + "ms");
224         }
225     }
226 }
227