blob: c7dc15a8c774da74b5da8a28fa4367fe01d31b32 [file] [log] [blame]
Adam He1cb6f802018-12-10 15:15:49 -08001/*
2 * Copyright (C) 2018 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 */
16package android.service.autofill;
17
18import static android.view.autofill.Helper.sDebug;
19
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.annotation.TestApi;
23import android.os.Bundle;
24import android.os.Parcel;
25import android.os.Parcelable;
26import android.util.ArrayMap;
27
28import com.android.internal.util.Preconditions;
29
30import java.util.ArrayList;
31import java.util.Collections;
32
33/**
34 * Holds both a generic and package-specific userData used for
35 * <a href="AutofillService.html#FieldClassification">field classification</a>.
36 *
37 * @hide
38 */
39@TestApi
40public final class CompositeUserData implements FieldClassificationUserData, Parcelable {
41
42 private final UserData mGenericUserData;
43 private final UserData mPackageUserData;
44
45 private final String[] mCategories;
46 private final String[] mValues;
47
48 public CompositeUserData(@Nullable UserData genericUserData,
49 @NonNull UserData packageUserData) {
50 mGenericUserData = genericUserData;
51 mPackageUserData = packageUserData;
52
53 final String[] packageCategoryIds = mPackageUserData.getCategoryIds();
54 final String[] packageValues = mPackageUserData.getValues();
55
56 final ArrayList<String> categoryIds = new ArrayList<>(packageCategoryIds.length);
57 final ArrayList<String> values = new ArrayList<>(packageValues.length);
58
59 Collections.addAll(categoryIds, packageCategoryIds);
60 Collections.addAll(values, packageValues);
61
62 if (mGenericUserData != null) {
63 final String[] genericCategoryIds = mGenericUserData.getCategoryIds();
64 final String[] genericValues = mGenericUserData.getValues();
65 final int size = mGenericUserData.getCategoryIds().length;
66 for (int i = 0; i < size; i++) {
67 if (!categoryIds.contains(genericCategoryIds[i])) {
68 categoryIds.add(genericCategoryIds[i]);
69 values.add(genericValues[i]);
70 }
71 }
72 }
73
74 mCategories = new String[categoryIds.size()];
75 categoryIds.toArray(mCategories);
76 mValues = new String[values.size()];
77 values.toArray(mValues);
78 }
79
80 @Nullable
81 @Override
82 public String getFieldClassificationAlgorithm() {
83 final String packageDefaultAlgo = mPackageUserData.getFieldClassificationAlgorithm();
84 if (packageDefaultAlgo != null) {
85 return packageDefaultAlgo;
86 } else {
87 return mGenericUserData == null ? null :
88 mGenericUserData.getFieldClassificationAlgorithm();
89 }
90 }
91
92 @Override
93 public Bundle getDefaultFieldClassificationArgs() {
94 final Bundle packageDefaultArgs = mPackageUserData.getDefaultFieldClassificationArgs();
95 if (packageDefaultArgs != null) {
96 return packageDefaultArgs;
97 } else {
98 return mGenericUserData == null ? null :
99 mGenericUserData.getDefaultFieldClassificationArgs();
100 }
101 }
102
103 @Nullable
104 @Override
105 public String getFieldClassificationAlgorithmForCategory(@NonNull String categoryId) {
106 Preconditions.checkNotNull(categoryId);
107 final ArrayMap<String, String> categoryAlgorithms = getFieldClassificationAlgorithms();
108 if (categoryAlgorithms == null || !categoryAlgorithms.containsKey(categoryId)) {
109 return null;
110 }
111 return categoryAlgorithms.get(categoryId);
112 }
113
114 @Override
115 public ArrayMap<String, String> getFieldClassificationAlgorithms() {
116 final ArrayMap<String, String> packageAlgos = mPackageUserData
117 .getFieldClassificationAlgorithms();
118 final ArrayMap<String, String> genericAlgos = mGenericUserData == null ? null :
119 mGenericUserData.getFieldClassificationAlgorithms();
120
121 ArrayMap<String, String> categoryAlgorithms = null;
122 if (packageAlgos != null || genericAlgos != null) {
123 categoryAlgorithms = new ArrayMap<>();
124 if (genericAlgos != null) {
125 categoryAlgorithms.putAll(genericAlgos);
126 }
127 if (packageAlgos != null) {
128 categoryAlgorithms.putAll(packageAlgos);
129 }
130 }
131
132 return categoryAlgorithms;
133 }
134
135 @Override
136 public ArrayMap<String, Bundle> getFieldClassificationArgs() {
137 final ArrayMap<String, Bundle> packageArgs = mPackageUserData.getFieldClassificationArgs();
138 final ArrayMap<String, Bundle> genericArgs = mGenericUserData == null ? null :
139 mGenericUserData.getFieldClassificationArgs();
140
141 ArrayMap<String, Bundle> categoryArgs = null;
142 if (packageArgs != null || genericArgs != null) {
143 categoryArgs = new ArrayMap<>();
144 if (genericArgs != null) {
145 categoryArgs.putAll(genericArgs);
146 }
147 if (packageArgs != null) {
148 categoryArgs.putAll(packageArgs);
149 }
150 }
151
152 return categoryArgs;
153 }
154
155 @Override
156 public String[] getCategoryIds() {
157 return mCategories;
158 }
159
160 @Override
161 public String[] getValues() {
162 return mValues;
163 }
164
165 /////////////////////////////////////
166 // Object "contract" methods. //
167 /////////////////////////////////////
168 @Override
169 public String toString() {
170 if (!sDebug) return super.toString();
171
172 // OK to print UserData because UserData.toString() is PII-aware
173 final StringBuilder builder = new StringBuilder("genericUserData=")
174 .append(mGenericUserData)
175 .append(", packageUserData=").append(mPackageUserData);
176 return builder.toString();
177 }
178
179 /////////////////////////////////////
180 // Parcelable "contract" methods. //
181 /////////////////////////////////////
182
183 @Override
184 public int describeContents() {
185 return 0;
186 }
187
188 @Override
189 public void writeToParcel(Parcel parcel, int flags) {
190 parcel.writeParcelable(mGenericUserData, 0);
191 parcel.writeParcelable(mPackageUserData, 0);
192 }
193
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700194 public static final @android.annotation.NonNull Parcelable.Creator<CompositeUserData> CREATOR =
Adam He1cb6f802018-12-10 15:15:49 -0800195 new Parcelable.Creator<CompositeUserData>() {
196 @Override
197 public CompositeUserData createFromParcel(Parcel parcel) {
198 // Always go through the builder to ensure the data ingested by
199 // the system obeys the contract of the builder to avoid attacks
200 // using specially crafted parcels.
201 final UserData genericUserData = parcel.readParcelable(null);
202 final UserData packageUserData = parcel.readParcelable(null);
203 return new CompositeUserData(genericUserData, packageUserData);
204 }
205
206 @Override
207 public CompositeUserData[] newArray(int size) {
208 return new CompositeUserData[size];
209 }
210 };
211}