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.augmented;
18 
19 import static android.autofillservice.cts.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.autofillservice.cts.Helper;
28 import android.autofillservice.cts.augmented.CtsAugmentedAutofillService.AugmentedFillRequest;
29 import android.content.ComponentName;
30 import android.service.autofill.augmented.FillRequest;
31 import android.util.Log;
32 import android.util.Pair;
33 import android.view.autofill.AutofillId;
34 import android.view.autofill.AutofillValue;
35 
36 import androidx.annotation.NonNull;
37 import androidx.annotation.Nullable;
38 
39 import com.google.common.base.Preconditions;
40 
41 import java.util.List;
42 import java.util.concurrent.CountDownLatch;
43 import java.util.concurrent.TimeUnit;
44 
45 /**
46  * Helper for common funcionalities.
47  */
48 public final class AugmentedHelper {
49 
50     private static final String TAG = AugmentedHelper.class.getSimpleName();
51 
52     @NonNull
getActivityName(@ullable FillRequest request)53     public static String getActivityName(@Nullable FillRequest request) {
54         if (request == null) return "N/A (null request)";
55 
56         final ComponentName componentName = request.getActivityComponent();
57         if (componentName == null) return "N/A (no component name)";
58 
59         return componentName.flattenToShortString();
60     }
61 
62     /**
63      * Sets the augmented capture service.
64      */
setAugmentedService(@onNull String service)65     public static void setAugmentedService(@NonNull String service) {
66         Log.d(TAG, "Setting service to " + service);
67         runShellCommand("cmd autofill set temporary-augmented-service 0 %s %d", service,
68                 MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS);
69     }
70 
71     /**
72      * Resets the content capture service.
73      */
resetAugmentedService()74     public static void resetAugmentedService() {
75         Log.d(TAG, "Resetting back to default service");
76         runShellCommand("cmd autofill set temporary-augmented-service 0");
77     }
78 
assertBasicRequestInfo(@onNull AugmentedFillRequest request, @NonNull Activity activity, @NonNull AutofillId expectedFocusedId, @NonNull AutofillValue expectedFocusedValue)79     public static void assertBasicRequestInfo(@NonNull AugmentedFillRequest request,
80             @NonNull Activity activity, @NonNull AutofillId expectedFocusedId,
81             @NonNull AutofillValue expectedFocusedValue) {
82         assertBasicRequestInfo(request, activity, expectedFocusedId,
83                 expectedFocusedValue.getTextValue().toString());
84     }
85 
assertBasicRequestInfo(@onNull AugmentedFillRequest request, @NonNull Activity activity, @NonNull AutofillId expectedFocusedId, @NonNull String expectedFocusedValue)86     public static void assertBasicRequestInfo(@NonNull AugmentedFillRequest request,
87             @NonNull Activity activity, @NonNull AutofillId expectedFocusedId,
88             @NonNull String expectedFocusedValue) {
89         Preconditions.checkNotNull(activity);
90         Preconditions.checkNotNull(expectedFocusedId);
91         assertWithMessage("no AugmentedFillRequest").that(request).isNotNull();
92         assertWithMessage("no FillRequest on %s", request).that(request.request).isNotNull();
93         assertWithMessage("no FillController on %s", request).that(request.controller).isNotNull();
94         assertWithMessage("no FillCallback on %s", request).that(request.callback).isNotNull();
95         assertWithMessage("no CancellationSignal on %s", request).that(request.cancellationSignal)
96                 .isNotNull();
97         // NOTE: task id can change, we might need to set it in the activity's onCreate()
98         assertWithMessage("wrong task id on %s", request).that(request.request.getTaskId())
99                 .isEqualTo(activity.getTaskId());
100 
101         final ComponentName actualComponentName = request.request.getActivityComponent();
102         assertWithMessage("no activity name on %s", request).that(actualComponentName).isNotNull();
103         assertWithMessage("wrong activity name on %s", request).that(actualComponentName)
104                 .isEqualTo(activity.getComponentName());
105         final AutofillId actualFocusedId = request.request.getFocusedId();
106         assertWithMessage("no focused id on %s", request).that(actualFocusedId).isNotNull();
107         assertWithMessage("wrong focused id on %s", request).that(actualFocusedId)
108                 .isEqualTo(expectedFocusedId);
109         final AutofillValue actualFocusedValue = request.request.getFocusedValue();
110         assertWithMessage("no focused value on %s", request).that(actualFocusedValue).isNotNull();
111         assertAutofillValue(expectedFocusedValue, actualFocusedValue);
112     }
113 
assertAutofillValue(@onNull AutofillValue expectedValue, @NonNull AutofillValue actualValue)114     public static void assertAutofillValue(@NonNull AutofillValue expectedValue,
115             @NonNull AutofillValue actualValue) {
116         // It only supports text values for now...
117         assertWithMessage("expected value is not text: %s", expectedValue)
118                 .that(expectedValue.isText()).isTrue();
119         assertAutofillValue(expectedValue.getTextValue().toString(), actualValue);
120     }
121 
assertAutofillValue(@onNull String expectedValue, @NonNull AutofillValue actualValue)122     public static void assertAutofillValue(@NonNull String expectedValue,
123             @NonNull AutofillValue actualValue) {
124         assertWithMessage("actual value is not text: %s", actualValue)
125                 .that(actualValue.isText()).isTrue();
126 
127         assertWithMessage("wrong autofill value").that(actualValue.getTextValue().toString())
128                 .isEqualTo(expectedValue);
129     }
130 
131     @NonNull
toString(@ullable List<Pair<AutofillId, AutofillValue>> values)132     public static String toString(@Nullable List<Pair<AutofillId, AutofillValue>> values) {
133         if (values == null) return "null";
134         final StringBuilder string = new StringBuilder("[");
135         final int size = values.size();
136         for (int i = 0; i < size; i++) {
137             final Pair<AutofillId, AutofillValue> value = values.get(i);
138             string.append(i).append(':').append(value.first).append('=')
139                    .append(Helper.toString(value.second));
140             if (i < size - 1) {
141                 string.append(", ");
142             }
143 
144         }
145         return string.append(']').toString();
146     }
147 
148     @NonNull
toString(@ullable FillRequest request)149     public static String toString(@Nullable FillRequest request) {
150         if (request == null) return "(null request)";
151 
152         final StringBuilder string =
153                 new StringBuilder("FillRequest[act=").append(getActivityName(request))
154                 .append(", taskId=").append(request.getTaskId());
155 
156         final AutofillId focusedId = request.getFocusedId();
157         if (focusedId != null) {
158             string.append(", focusedId=").append(focusedId);
159         }
160         final AutofillValue focusedValue = request.getFocusedValue();
161         if (focusedValue != null) {
162             string.append(", focusedValue=").append(focusedValue);
163         }
164 
165         return string.append(']').toString();
166     }
167 
168     // Used internally by UiBot to assert the UI
getContentDescriptionForUi(@onNull AutofillId focusedId)169     static String getContentDescriptionForUi(@NonNull AutofillId focusedId) {
170         return "ui_for_" + focusedId;
171     }
172 
AugmentedHelper()173     private AugmentedHelper() {
174         throw new UnsupportedOperationException("contain static methods only");
175     }
176 
177     /**
178      * Awaits for a latch to be counted down.
179      */
await(@onNull CountDownLatch latch, @NonNull String fmt, @Nullable Object... args)180     public static void await(@NonNull CountDownLatch latch, @NonNull String fmt,
181             @Nullable Object... args)
182             throws InterruptedException {
183         final boolean called = latch.await(CONNECTION_TIMEOUT.ms(), TimeUnit.MILLISECONDS);
184         if (!called) {
185             throw new IllegalStateException(String.format(fmt, args)
186                     + " in " + CONNECTION_TIMEOUT.ms() + "ms");
187         }
188     }
189 }
190