From 1903915873b96135dac51d5a5a768f5e83f90e56 Mon Sep 17 00:00:00 2001 From: Simranjit Kohli Date: Fri, 27 Jan 2023 15:57:30 -0800 Subject: [PATCH] [Autofill PCC]: Service interface definition Test: None Bug: 242704846 Bug: 261106874 CTS-Coverage-Bug: 266366047 API-Coverage-Bug: 266366047 Change-Id: I36c1c51f5fb65fa94c6c494d1e3d86862bae463e --- core/api/current.txt | 13 + core/api/system-current.txt | 34 ++ core/java/android/service/assist/OWNERS | 3 + .../classification/FieldClassification.aidl | 19 ++ .../classification/FieldClassification.java | 315 ++++++++++++++++++ .../FieldClassificationRequest.aidl | 19 ++ .../FieldClassificationRequest.java | 134 ++++++++ .../FieldClassificationResponse.aidl | 19 ++ .../FieldClassificationResponse.java | 163 +++++++++ .../FieldClassificationService.java | 178 ++++++++++ .../IFieldClassificationCallback.aidl | 42 +++ .../IFieldClassificationService.aidl | 38 +++ core/res/AndroidManifest.xml | 9 + core/res/res/values/config.xml | 9 +- core/res/res/values/symbols.xml | 1 + 15 files changed, 995 insertions(+), 1 deletion(-) create mode 100644 core/java/android/service/assist/OWNERS create mode 100644 core/java/android/service/assist/classification/FieldClassification.aidl create mode 100644 core/java/android/service/assist/classification/FieldClassification.java create mode 100644 core/java/android/service/assist/classification/FieldClassificationRequest.aidl create mode 100644 core/java/android/service/assist/classification/FieldClassificationRequest.java create mode 100644 core/java/android/service/assist/classification/FieldClassificationResponse.aidl create mode 100644 core/java/android/service/assist/classification/FieldClassificationResponse.java create mode 100644 core/java/android/service/assist/classification/FieldClassificationService.java create mode 100644 core/java/android/service/assist/classification/IFieldClassificationCallback.aidl create mode 100644 core/java/android/service/assist/classification/IFieldClassificationService.aidl diff --git a/core/api/current.txt b/core/api/current.txt index bca9913ff94ec..7e77da07b6cd0 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -39293,6 +39293,19 @@ package android.security.keystore { } +package android.service.assist.classification { + + public final class FieldClassification implements android.os.Parcelable { + ctor public FieldClassification(@NonNull android.view.autofill.AutofillId, @NonNull java.util.Set); + method public int describeContents(); + method @NonNull public android.view.autofill.AutofillId getAutofillId(); + method @NonNull public java.util.Set getHints(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + +} + package android.service.autofill { public abstract class AutofillService extends android.app.Service { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index c098adb7ea5d5..e6792e10de9f3 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -55,6 +55,7 @@ package android { field public static final String BIND_DOMAIN_VERIFICATION_AGENT = "android.permission.BIND_DOMAIN_VERIFICATION_AGENT"; field public static final String BIND_EUICC_SERVICE = "android.permission.BIND_EUICC_SERVICE"; field public static final String BIND_EXTERNAL_STORAGE_SERVICE = "android.permission.BIND_EXTERNAL_STORAGE_SERVICE"; + field public static final String BIND_FIELD_CLASSIFICATION_SERVICE = "android.permission.BIND_FIELD_CLASSIFICATION_SERVICE"; field public static final String BIND_GBA_SERVICE = "android.permission.BIND_GBA_SERVICE"; field public static final String BIND_HOTWORD_DETECTION_SERVICE = "android.permission.BIND_HOTWORD_DETECTION_SERVICE"; field public static final String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE"; @@ -11548,6 +11549,39 @@ package android.service.appprediction { } +package android.service.assist.classification { + + public final class FieldClassification implements android.os.Parcelable { + ctor public FieldClassification(@NonNull android.view.autofill.AutofillId, @NonNull java.util.Set, @NonNull java.util.Set); + method @NonNull public java.util.Set getGroupHints(); + } + + public final class FieldClassificationRequest implements android.os.Parcelable { + ctor public FieldClassificationRequest(@NonNull android.app.assist.AssistStructure); + method public int describeContents(); + method @NonNull public android.app.assist.AssistStructure getAssistStructure(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public final class FieldClassificationResponse implements android.os.Parcelable { + ctor public FieldClassificationResponse(@NonNull java.util.Set); + method public int describeContents(); + method @NonNull public java.util.Set getClassifications(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator CREATOR; + } + + public abstract class FieldClassificationService extends android.app.Service { + ctor public FieldClassificationService(); + method public abstract void onClassificationRequest(@NonNull android.service.assist.classification.FieldClassificationRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver); + method public void onConnected(); + method public void onDisconnected(); + field public static final String SERVICE_INTERFACE = "android.service.assist.classification.FieldClassificationService"; + } + +} + package android.service.attention { public abstract class AttentionService extends android.app.Service { diff --git a/core/java/android/service/assist/OWNERS b/core/java/android/service/assist/OWNERS new file mode 100644 index 0000000000000..533b1f1aef586 --- /dev/null +++ b/core/java/android/service/assist/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 351486 + +include /core/java/android/view/autofill/OWNERS \ No newline at end of file diff --git a/core/java/android/service/assist/classification/FieldClassification.aidl b/core/java/android/service/assist/classification/FieldClassification.aidl new file mode 100644 index 0000000000000..7d0c078d81e46 --- /dev/null +++ b/core/java/android/service/assist/classification/FieldClassification.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 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.service.assist.classification; + +parcelable FieldClassification; diff --git a/core/java/android/service/assist/classification/FieldClassification.java b/core/java/android/service/assist/classification/FieldClassification.java new file mode 100644 index 0000000000000..0ea8112fe772a --- /dev/null +++ b/core/java/android/service/assist/classification/FieldClassification.java @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2023 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.service.assist.classification; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArraySet; +import android.view.autofill.AutofillId; + + +import com.android.internal.util.DataClass; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * Represents a classified field from the detection service. + */ +// TODO(b/266930067): Once @SystemApi is supported, use genSetters and genConstructor. +@DataClass( + genToString = true, + genConstructor = false +) +public final class FieldClassification implements Parcelable { + + /** + * Autofill id of the detected field + */ + private final @NonNull AutofillId mAutofillId; + + /** + * Detected fields types represented as autofill hints + * + * A particular field can be detected as multiple types. For eg: A sign-in field may take in a + * username, an email address or a phone number. In such cases, it should be detected as + * "username", "emailAddress" and "phoneNumber" + * + * The value of these hints are contained in androidx.autofill.HintConstants + */ + private final @NonNull Set mHints; + + + /** + * Group hints are the hints that may represent the group of related hints (including + * themselves). The value of these group hints are contained in androidx.autofill.HintConstants + * + *

+ * + * "creditCardNumber" is the group hint for hints containing credit card related fields: + * "creditCardNumber", "creditCardExpirationDate", "creditCardExpirationDay", + * "creditCardExpirationMonth", "creditCardExpirationYear", "creditCardSecurityCode", + * + *

+ * + * "postalAddress" is the group hint for hints all postal address related fields: + * "postalAddress", "streetAddress", "aptNumber", "dependentLocality", "extendedAddress", + * "postalCode", "extendedPostalCode", "addressLocality", "addressRegion", "addressCountry". + * + *

+ * + * "phoneNumber" is the group hint for hints all phone number related fields: "phoneNumber", + * "phoneNumberDevice", "phoneNational", "phoneCountryCode". + * + *

+ * + * "personName" is the group hint for hints all name related fields: "personName", + * "personFamilyName", "personGivenName", "personMiddleName", "personMiddleInitial", + * "personNamePrefix", "personNameSuffix" . + * + *

+ * + * "birthDateFull" is the group hint for hints containing birthday related fields: + * "birthDateFull", "birthDateMonth", "birthDateYear", + * + * @hide + */ + private final @NonNull Set mGroupHints; + + /** + * Autofill id of the detected field. + */ + public @NonNull AutofillId getAutofillId() { + return mAutofillId; + } + + /** + * Detected fields types represented as autofill hints. + * + * A particular field can be detected as multiple types. For eg: A sign-in field may take in a + * username, an email address or a phone number. In such cases, it should be detected as + * "username", "emailAddress" and "phoneNumber" + * + * The value of these hints are contained in androidx.autofill.HintConstants + */ + public @NonNull Set getHints() { + return mHints; + } + + /** + * Group hints are the hints that may represent the group of related hints (including + * themselves). The value of these group hints are contained in androidx.autofill.HintConstants + * + *

+ * + * "creditCardNumber" is the group hint for hints containing credit card related fields: + * "creditCardNumber", "creditCardExpirationDate", "creditCardExpirationDay", + * "creditCardExpirationMonth", "creditCardExpirationYear", "creditCardSecurityCode", + * + *

+ * + * "postalAddress" is the group hint for hints all postal address related fields: + * "postalAddress", "streetAddress", "aptNumber", "dependentLocality", "extendedAddress", + * "postalCode", "extendedPostalCode", "addressLocality", "addressRegion", "addressCountry". + * + *

+ * + * "phoneNumber" is the group hint for hints all phone number related fields: "phoneNumber", + * "phoneNumberDevice", "phoneNational", "phoneCountryCode". + * + *

+ * + * "personName" is the group hint for hints all name related fields: "personName", + * "personFamilyName", "personGivenName", "personMiddleName", "personMiddleInitial", + * "personNamePrefix", "personNameSuffix" . + * + *

+ * + * "birthDateFull" is the group hint for hints containing birthday related fields: + * "birthDateFull", "birthDateMonth", "birthDateYear", + * + * @hide + */ + @SystemApi + public @NonNull Set getGroupHints() { + return mGroupHints; + } + + static Set unparcelHints(Parcel in) { + List hints = new java.util.ArrayList<>(); + in.readStringList(hints); + return new ArraySet<>(hints); + } + + void parcelHints(Parcel dest, int flags) { + dest.writeStringList(new ArrayList<>(mHints)); + } + + static Set unparcelGroupHints(Parcel in) { + List groupHints = new java.util.ArrayList<>(); + in.readStringList(groupHints); + return new ArraySet<>(groupHints); + } + + void parcelGroupHints(Parcel dest, int flags) { + dest.writeStringList(new ArrayList<>(mGroupHints)); + } + + /** + * Creates a new FieldClassification. + * + * @param autofillId + * Autofill id of the detected field + * @param hints + * Detected fields types represented as autofill hints. + * A particular field can be detected as multiple types. For eg: A sign-in field may take in + * a username, an email address or a phone number. In such cases, it should be detected as + * "username", "emailAddress" and "phoneNumber" + */ + public FieldClassification( + @NonNull AutofillId autofillId, + @NonNull Set hints) { + this(autofillId, hints, new ArraySet<>()); + } + + /** + * Creates a new FieldClassification. + * + * @param autofillId Autofill id of the detected field + * @param hints Detected fields types represented as autofill hints A particular field can be + * detected as multiple types. For eg: A sign-in field may take in a username, an email + * address or a phone number. In such cases, it should be detected as "username", + * "emailAddress" and "phoneNumber" + * @param groupHints Hints that may represent the group of related hints (including themselves). + * The value of these group hints are contained in androidx.autofill.HintConstants. + * See {@link #getGroupHints()} for more details + * @hide + */ + @SystemApi + @DataClass.Generated.Member + public FieldClassification( + @NonNull AutofillId autofillId, + @NonNull Set hints, + @NonNull Set groupHints) { + this.mAutofillId = autofillId; +// com.android.internal.util.AnnotationValidations.validate( +// NonNull.class, null, mAutofillId); + this.mHints = hints; +// com.android.internal.util.AnnotationValidations.validate( +// NonNull.class, null, mHints); + this.mGroupHints = groupHints; +// com.android.internal.util.AnnotationValidations.validate( +// NonNull.class, null, mGroupHints); + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/assist/classification/FieldClassification.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "FieldClassification { " + + "autofillId = " + mAutofillId + ", " + + "hints = " + mHints + ", " + + "groupHints = " + mGroupHints + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeTypedObject(mAutofillId, flags); + parcelHints(dest, flags); + parcelGroupHints(dest, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ FieldClassification(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + AutofillId autofillId = (AutofillId) in.readTypedObject(AutofillId.CREATOR); + Set hints = unparcelHints(in); + Set groupHints = unparcelGroupHints(in); + + this.mAutofillId = autofillId; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAutofillId); + this.mHints = hints; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHints); + this.mGroupHints = groupHints; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mGroupHints); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public FieldClassification[] newArray(int size) { + return new FieldClassification[size]; + } + + @Override + public FieldClassification createFromParcel(@NonNull Parcel in) { + return new FieldClassification(in); + } + }; + + @DataClass.Generated( + time = 1675320464097L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/service/assist/classification/FieldClassification.java", + inputSignatures = "private final @android.annotation.NonNull android.view.autofill.AutofillId mAutofillId\nprivate final @android.annotation.NonNull java.util.Set mHints\nprivate final @android.annotation.NonNull java.util.Set mGroupHints\npublic @android.annotation.NonNull android.view.autofill.AutofillId getAutofillId()\npublic @android.annotation.NonNull java.util.Set getHints()\npublic @android.annotation.SystemApi @android.annotation.NonNull java.util.Set getGroupHints()\nstatic java.util.Set unparcelHints(android.os.Parcel)\n void parcelHints(android.os.Parcel,int)\nstatic java.util.Set unparcelGroupHints(android.os.Parcel)\n void parcelGroupHints(android.os.Parcel,int)\nclass FieldClassification extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genConstructor=false)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/service/assist/classification/FieldClassificationRequest.aidl b/core/java/android/service/assist/classification/FieldClassificationRequest.aidl new file mode 100644 index 0000000000000..740c5cb917806 --- /dev/null +++ b/core/java/android/service/assist/classification/FieldClassificationRequest.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2023, 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.service.assist.classification; + +parcelable FieldClassificationRequest; \ No newline at end of file diff --git a/core/java/android/service/assist/classification/FieldClassificationRequest.java b/core/java/android/service/assist/classification/FieldClassificationRequest.java new file mode 100644 index 0000000000000..0afcca9615cb7 --- /dev/null +++ b/core/java/android/service/assist/classification/FieldClassificationRequest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2023 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.service.assist.classification; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.app.assist.AssistStructure; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * Represents a request to detect fields on an activity. + * @hide + */ +@SystemApi +@DataClass( + genToString = true +) +public final class FieldClassificationRequest implements Parcelable { + private final @NonNull AssistStructure mAssistStructure; + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/assist/classification/FieldClassificationRequest.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + public FieldClassificationRequest( + @NonNull AssistStructure assistStructure) { + this.mAssistStructure = assistStructure; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAssistStructure); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull AssistStructure getAssistStructure() { + return mAssistStructure; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "FieldClassificationRequest { " + + "assistStructure = " + mAssistStructure + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeTypedObject(mAssistStructure, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ FieldClassificationRequest(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + AssistStructure assistStructure = (AssistStructure) in.readTypedObject(AssistStructure.CREATOR); + + this.mAssistStructure = assistStructure; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mAssistStructure); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public FieldClassificationRequest[] newArray(int size) { + return new FieldClassificationRequest[size]; + } + + @Override + public FieldClassificationRequest createFromParcel(@NonNull Parcel in) { + return new FieldClassificationRequest(in); + } + }; + + @DataClass.Generated( + time = 1675320491692L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/service/assist/classification/FieldClassificationRequest.java", + inputSignatures = "private final @android.annotation.NonNull android.app.assist.AssistStructure mAssistStructure\nclass FieldClassificationRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/service/assist/classification/FieldClassificationResponse.aidl b/core/java/android/service/assist/classification/FieldClassificationResponse.aidl new file mode 100644 index 0000000000000..1b0de85eab1aa --- /dev/null +++ b/core/java/android/service/assist/classification/FieldClassificationResponse.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 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.service.assist.classification; + +parcelable FieldClassificationResponse; diff --git a/core/java/android/service/assist/classification/FieldClassificationResponse.java b/core/java/android/service/assist/classification/FieldClassificationResponse.java new file mode 100644 index 0000000000000..faa9488d1f674 --- /dev/null +++ b/core/java/android/service/assist/classification/FieldClassificationResponse.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2023 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.service.assist.classification; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArraySet; + +import com.android.internal.util.DataClass; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + + +/** + * Represents a response from detection service. + * @hide + */ +@SystemApi +@DataClass( + genToString = true +) +public final class FieldClassificationResponse implements Parcelable { + + /** + * List of classified fields + */ + private final @NonNull Set mClassifications; + + static Set unparcelClassifications(Parcel in) { + List detections = new java.util.ArrayList<>(); + in.readParcelableList( + detections, FieldClassification.class.getClassLoader(), FieldClassification.class); + return new ArraySet<>(detections); + } + + void parcelClassifications(Parcel dest, int flags) { + dest.writeParcelableList(new ArrayList<>(mClassifications), flags); + } + + + + // Code below generated by codegen v1.0.23. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/assist/classification/FieldClassificationResponse.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new FieldClassificationResponse. + * + * @param classifications + * List of classified fields + */ + @DataClass.Generated.Member + public FieldClassificationResponse( + @NonNull Set classifications) { + this.mClassifications = classifications; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mClassifications); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * List of classified fields + */ + @DataClass.Generated.Member + public @NonNull Set getClassifications() { + return mClassifications; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "FieldClassificationResponse { " + + "classifications = " + mClassifications + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + parcelClassifications(dest, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ FieldClassificationResponse(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + Set classifications = unparcelClassifications(in); + + this.mClassifications = classifications; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mClassifications); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public FieldClassificationResponse[] newArray(int size) { + return new FieldClassificationResponse[size]; + } + + @Override + public FieldClassificationResponse createFromParcel(@NonNull Parcel in) { + return new FieldClassificationResponse(in); + } + }; + + @DataClass.Generated( + time = 1675320458276L, + codegenVersion = "1.0.23", + sourceFile = "frameworks/base/core/java/android/service/assist/classification/FieldClassificationResponse.java", + inputSignatures = "private final @android.annotation.NonNull java.util.Set mClassifications\nstatic java.util.Set unparcelClassifications(android.os.Parcel)\n void parcelClassifications(android.os.Parcel,int)\nclass FieldClassificationResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/service/assist/classification/FieldClassificationService.java b/core/java/android/service/assist/classification/FieldClassificationService.java new file mode 100644 index 0000000000000..abffdbf7cc073 --- /dev/null +++ b/core/java/android/service/assist/classification/FieldClassificationService.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2023 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.service.assist.classification; + +import android.annotation.CallSuper; +import android.annotation.NonNull; +import android.annotation.SdkConstant; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.ComponentName; +import android.content.Intent; +import android.os.BaseBundle; +import android.os.Build; +import android.os.CancellationSignal; +import android.os.IBinder; +import android.os.ICancellationSignal; +import android.os.OutcomeReceiver; +import android.os.RemoteException; +import android.util.Log; + +/** + * A service using {@link android.app.assist.AssistStructure} to detect fields on the screen. + * Service may use classifiers to look at the un-stripped AssistStructure to make informed decision + * and classify the fields. + * + * Currently, it's used to detect the field types for the Autofill Framework to provide relevant + * autofill suggestions to the user. + * + * + * The methods are invoked on the binder threads. + * + * @hide + */ +@SystemApi +public abstract class FieldClassificationService extends Service { + + private static final String TAG = FieldClassificationService.class.getSimpleName(); + + static boolean sDebug = Build.IS_USER ? false : true; + static boolean sVerbose = false; + + /** + * The {@link Intent} that must be declared as handled by the service. + * To be supported, the service must also require the + * {@link android.Manifest.permission#BIND_FIELD_CLASSIFICATION_SERVICE} permission so + * that other applications can not abuse it. + */ + @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) + public static final String SERVICE_INTERFACE = + "android.service.assist.classification.FieldClassificationService"; + + // Used for metrics / debug only + private ComponentName mServiceComponentName; + + private final class FieldClassificationServiceImpl + extends IFieldClassificationService.Stub { + + @Override + public void onConnected(boolean debug, boolean verbose) { + handleOnConnected(debug, verbose); + } + + @Override + public void onDisconnected() { + handleOnDisconnected(); + } + + @Override + public void onFieldClassificationRequest( + FieldClassificationRequest request, IFieldClassificationCallback callback) { + handleOnClassificationRequest(request, callback); + } + }; + + @CallSuper + @Override + public void onCreate() { + super.onCreate(); + BaseBundle.setShouldDefuse(true); + } + + /** @hide */ + @Override + public final IBinder onBind(Intent intent) { + if (SERVICE_INTERFACE.equals(intent.getAction())) { + mServiceComponentName = intent.getComponent(); + return new FieldClassificationServiceImpl().asBinder(); + } + Log.w(TAG, "Tried to bind to wrong intent (should be " + SERVICE_INTERFACE + ": " + intent); + return null; + } + + /** + * Called when the Android system connects to service. + * + *

You should generally do initialization here rather than in {@link #onCreate}. + */ + public void onConnected() { + } + + /** + * Requests the service to handle field classification request. + * @param cancellationSignal signal for observing cancellation requests. The system will use + * this to notify you that the detection result is no longer needed and the service should + * stop handling this detection request in order to save resources. + * @param outcomeReceiver object used to notify the result of the request. Service must + * call {@link OutcomeReceiver<>#onResult(FieldClassificationResponse)}. + */ + public abstract void onClassificationRequest( + @NonNull FieldClassificationRequest request, + @NonNull CancellationSignal cancellationSignal, + @NonNull OutcomeReceiver outcomeReceiver); + + /** + * Called when the Android system disconnects from the service. + * + *

At this point this service may no longer be an active + * {@link FieldClassificationService}. + */ + public void onDisconnected() { + } + + private void handleOnConnected(boolean debug, boolean verbose) { + if (sDebug || debug) { + Log.d(TAG, "handleOnConnected(): debug=" + debug + ", verbose=" + verbose); + } + sDebug = debug; + sVerbose = verbose; + onConnected(); + } + + private void handleOnDisconnected() { + onDisconnected(); + } + + private void handleOnClassificationRequest( + FieldClassificationRequest request, @NonNull IFieldClassificationCallback callback) { + + final ICancellationSignal transport = CancellationSignal.createTransport(); + final CancellationSignal cancellationSignal = CancellationSignal.fromTransport(transport); + onClassificationRequest( + request, + cancellationSignal, + new OutcomeReceiver() { + @Override + public void onResult(FieldClassificationResponse result) { + try { + callback.onSuccess(result); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + @Override + public void onError(Exception e) { + try { + callback.onFailure(); + } catch (RemoteException ex) { + ex.rethrowFromSystemServer(); + } + } + }); + } +} + diff --git a/core/java/android/service/assist/classification/IFieldClassificationCallback.aidl b/core/java/android/service/assist/classification/IFieldClassificationCallback.aidl new file mode 100644 index 0000000000000..ca9e9398899a8 --- /dev/null +++ b/core/java/android/service/assist/classification/IFieldClassificationCallback.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 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.service.assist.classification; + +import android.os.Bundle; +import android.os.ICancellationSignal; + +import android.service.assist.classification.FieldClassificationResponse; + +import java.util.List; + +/** + * Interface to receive the result of an autofill request. + * + * @hide + */ +interface IFieldClassificationCallback { + + void onCancellable(in ICancellationSignal cancellation); + + void onSuccess(in FieldClassificationResponse response); + + void onFailure(); + + boolean isCompleted(); + + void cancel(); +} diff --git a/core/java/android/service/assist/classification/IFieldClassificationService.aidl b/core/java/android/service/assist/classification/IFieldClassificationService.aidl new file mode 100644 index 0000000000000..a93688d1dab7e --- /dev/null +++ b/core/java/android/service/assist/classification/IFieldClassificationService.aidl @@ -0,0 +1,38 @@ + +/* + * Copyright (C) 2023 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.service.assist.classification; + +import android.content.ComponentName; +import android.os.IBinder; +import android.service.assist.classification.IFieldClassificationCallback; +import android.service.assist.classification.FieldClassificationRequest; +import android.view.autofill.AutofillId; +import android.view.autofill.AutofillValue; +import android.view.inputmethod.InlineSuggestionsRequest; +import java.util.List; +/** + * Interface from the system to an Autofill classification service. + * + * @hide + */ +oneway interface IFieldClassificationService { + void onConnected(boolean debug, boolean verbose); + void onDisconnected(); + void onFieldClassificationRequest( + in FieldClassificationRequest request, in IFieldClassificationCallback callback); +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 81c7fba617044..537c2c0acd2b5 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -4534,6 +4534,15 @@ + + + + + +