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