blob: f1bacb53863f18125f6c20d42a224aa5871a7da0 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.autofillservice.cts.testcore;
import static android.autofillservice.cts.testcore.Timeouts.CONNECTION_TIMEOUT;
import static android.view.autofill.AutofillManager.MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS;
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import static com.google.common.truth.Truth.assertWithMessage;
import android.app.Activity;
import android.app.assist.AssistStructure;
import android.autofillservice.cts.testcore.CtsAugmentedAutofillService.AugmentedFillRequest;
import android.content.ComponentName;
import android.content.Context;
import android.service.autofill.augmented.FillRequest;
import android.util.Log;
import android.util.Pair;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.inputmethod.InlineSuggestionsRequest;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.cts.mockime.MockImeSession;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Helper for common funcionalities.
*/
public final class AugmentedHelper {
private static final String TAG = AugmentedHelper.class.getSimpleName();
@NonNull
public static String getActivityName(@Nullable FillRequest request) {
if (request == null) return "N/A (null request)";
final ComponentName componentName = request.getActivityComponent();
if (componentName == null) return "N/A (no component name)";
return componentName.flattenToShortString();
}
/**
* Sets the augmented capture service.
*/
public static void setAugmentedService(@NonNull String service) {
Log.d(TAG, "Setting service to " + service);
runShellCommand("cmd autofill set temporary-augmented-service 0 %s %d", service,
MAX_TEMP_AUGMENTED_SERVICE_DURATION_MS);
}
/**
* Resets the content capture service.
*/
public static void resetAugmentedService() {
Log.d(TAG, "Resetting back to default service");
runShellCommand("cmd autofill set temporary-augmented-service 0");
}
/**
* Returns whether MockIme is available.
*/
public static boolean mockImeIsAvailable(Context context) {
return MockImeSession.getUnavailabilityReason(context) == null;
}
public static void assertBasicRequestInfo(@NonNull AugmentedFillRequest request,
@NonNull Activity activity, @NonNull AutofillId expectedFocusedId,
@Nullable AutofillValue expectedFocusedValue) {
final boolean hasDefaultInlineRequest = mockImeIsAvailable(activity.getBaseContext());
assertBasicRequestInfo(request, activity, expectedFocusedId, expectedFocusedValue,
hasDefaultInlineRequest);
}
public static void assertBasicRequestInfo(@NonNull AugmentedFillRequest request,
@NonNull Activity activity, @NonNull AutofillId expectedFocusedId,
@Nullable AutofillValue expectedFocusedValue, boolean hasInlineRequest) {
Objects.requireNonNull(activity);
Objects.requireNonNull(expectedFocusedId);
assertWithMessage("no AugmentedFillRequest").that(request).isNotNull();
assertWithMessage("no FillRequest on %s", request).that(request.request).isNotNull();
assertWithMessage("no FillController on %s", request).that(request.controller).isNotNull();
assertWithMessage("no FillCallback on %s", request).that(request.callback).isNotNull();
assertWithMessage("no CancellationSignal on %s", request).that(request.cancellationSignal)
.isNotNull();
// NOTE: task id can change, we might need to set it in the activity's onCreate()
assertWithMessage("wrong task id on %s", request).that(request.request.getTaskId())
.isEqualTo(activity.getTaskId());
final ComponentName actualComponentName = request.request.getActivityComponent();
assertWithMessage("no activity name on %s", request).that(actualComponentName).isNotNull();
assertWithMessage("wrong activity name on %s", request).that(actualComponentName)
.isEqualTo(activity.getComponentName());
final AutofillId actualFocusedId = request.request.getFocusedId();
assertWithMessage("no focused id on %s", request).that(actualFocusedId).isNotNull();
assertWithMessage("wrong focused id on %s", request).that(actualFocusedId)
.isEqualTo(expectedFocusedId);
final AutofillValue actualFocusedValue = request.request.getFocusedValue();
if (expectedFocusedValue != null) {
assertWithMessage("no focused value on %s", request).that(
actualFocusedValue).isNotNull();
assertAutofillValue(expectedFocusedValue, actualFocusedValue);
} else {
assertWithMessage("expecting null focused value on %s", request).that(
actualFocusedValue).isNull();
}
if (expectedFocusedId.isNonVirtual()) {
final AssistStructure.ViewNode focusedViewNode = request.request.getFocusedViewNode();
assertWithMessage("no focused view node on %s", request).that(
focusedViewNode).isNotNull();
assertWithMessage("wrong autofill id in focused view node %s", focusedViewNode).that(
focusedViewNode.getAutofillId()).isEqualTo(expectedFocusedId);
assertWithMessage("unexpected autofill value in focused view node %s",
focusedViewNode).that(focusedViewNode.getAutofillValue()).isEqualTo(
expectedFocusedValue);
assertWithMessage("children nodes should not be populated for focused view node %s",
focusedViewNode).that(
focusedViewNode.getChildCount()).isEqualTo(0);
}
final InlineSuggestionsRequest inlineRequest =
request.request.getInlineSuggestionsRequest();
if (hasInlineRequest) {
assertWithMessage("no inline request on %s", request).that(inlineRequest).isNotNull();
} else {
assertWithMessage("exist inline request on %s", request).that(inlineRequest).isNull();
}
}
public static void assertAutofillValue(@NonNull AutofillValue expectedValue,
@NonNull AutofillValue actualValue) {
// It only supports text values for now...
assertWithMessage("expected value is not text: %s", expectedValue)
.that(expectedValue.isText()).isTrue();
assertAutofillValue(expectedValue.getTextValue().toString(), actualValue);
}
public static void assertAutofillValue(@NonNull String expectedValue,
@NonNull AutofillValue actualValue) {
assertWithMessage("actual value is not text: %s", actualValue)
.that(actualValue.isText()).isTrue();
assertWithMessage("wrong autofill value").that(actualValue.getTextValue().toString())
.isEqualTo(expectedValue);
}
@NonNull
public static String toString(@Nullable List<Pair<AutofillId, AutofillValue>> values) {
if (values == null) return "null";
final StringBuilder string = new StringBuilder("[");
final int size = values.size();
for (int i = 0; i < size; i++) {
final Pair<AutofillId, AutofillValue> value = values.get(i);
string.append(i).append(':').append(value.first).append('=')
.append(Helper.toString(value.second));
if (i < size - 1) {
string.append(", ");
}
}
return string.append(']').toString();
}
@NonNull
public static String toString(@Nullable FillRequest request) {
if (request == null) return "(null request)";
final StringBuilder string =
new StringBuilder("FillRequest[act=").append(getActivityName(request))
.append(", taskId=").append(request.getTaskId());
final AutofillId focusedId = request.getFocusedId();
if (focusedId != null) {
string.append(", focusedId=").append(focusedId);
}
final AutofillValue focusedValue = request.getFocusedValue();
if (focusedValue != null) {
string.append(", focusedValue=").append(focusedValue);
}
return string.append(']').toString();
}
// Used internally by UiBot to assert the UI
public static String getContentDescriptionForUi(@NonNull AutofillId focusedId) {
return "ui_for_" + focusedId;
}
private AugmentedHelper() {
throw new UnsupportedOperationException("contain static methods only");
}
/**
* Awaits for a latch to be counted down.
*/
public static void await(@NonNull CountDownLatch latch, @NonNull String fmt,
@Nullable Object... args)
throws InterruptedException {
final boolean called = latch.await(CONNECTION_TIMEOUT.ms(), TimeUnit.MILLISECONDS);
if (!called) {
throw new IllegalStateException(String.format(fmt, args)
+ " in " + CONNECTION_TIMEOUT.ms() + "ms");
}
}
}