SaveInfo.java revision b72f012cb49a5930010fb0766776b40c2955ee3e
1/* 2 * Copyright (C) 2017 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 17package android.service.autofill; 18 19import static android.view.autofill.Helper.DEBUG; 20 21import android.annotation.IntDef; 22import android.annotation.NonNull; 23import android.annotation.Nullable; 24import android.os.Bundle; 25import android.os.Parcel; 26import android.os.Parcelable; 27import android.util.ArraySet; 28import android.view.autofill.AutoFillId; 29 30import java.lang.annotation.Retention; 31import java.lang.annotation.RetentionPolicy; 32import java.util.ArrayList; 33 34/** 35 * Information used to indicate that a service is interested on saving the user-inputed data for 36 * future use. 37 * 38 * <p>A {@link SaveInfo} is always associated with a {@link FillResponse}. 39 * 40 * <p>A {@link SaveInfo} must define the type it represents, and contain at least one 41 * {@code savableId}. A {@code savableId} is the {@link AutoFillId} of a view the service is 42 * interested to save in a {@code onSaveRequest()}; the ids of all {@link Dataset} present in the 43 * {@link FillResponse} associated with this {@link SaveInfo} are already marked as savable, 44 * but additional ids can be added through {@link Builder#addSavableIds(AutoFillId...)}. 45 * 46 * <p>See {@link AutoFillService#onSaveRequest(android.app.assist.AssistStructure, Bundle, 47 * SaveCallback)} and {@link FillResponse} for more info. 48 */ 49public final class SaveInfo implements Parcelable { 50 51 /** 52 * Type used on when the service can save the contents of an activity, but cannot describe what 53 * the content is for. 54 */ 55 public static final int SAVE_DATA_TYPE_GENERIC = 0; 56 57 /** 58 * Type used when the {@link FillResponse} represents user credentials that have a password. 59 */ 60 public static final int SAVE_DATA_TYPE_PASSWORD = 1; 61 62 63 /** 64 * Type used on when the {@link FillResponse} represents a physical address (such as street, 65 * city, state, etc). 66 */ 67 public static final int SAVE_DATA_TYPE_ADDRESS = 2; 68 69 /** 70 * Type used when the {@link FillResponse} represents a credit card. 71 */ 72 public static final int SAVE_DATA_TYPE_CREDIT_CARD = 3; 73 74 private final @SaveDataType int mType; 75 private ArraySet<AutoFillId> mSavableIds; 76 private final CharSequence mDescription; 77 78 /** @hide */ 79 @IntDef({ 80 SAVE_DATA_TYPE_GENERIC, 81 SAVE_DATA_TYPE_PASSWORD, 82 SAVE_DATA_TYPE_ADDRESS, 83 SAVE_DATA_TYPE_CREDIT_CARD 84 }) 85 @Retention(RetentionPolicy.SOURCE) 86 public @interface SaveDataType { 87 } 88 89 private SaveInfo(Builder builder) { 90 mType = builder.mType; 91 mSavableIds = builder.mSavableIds; 92 mDescription = builder.mDescription; 93 } 94 95 /** @hide */ 96 public @Nullable ArraySet<AutoFillId> getSavableIds() { 97 return mSavableIds; 98 } 99 100 /** @hide */ 101 public int getType() { 102 return mType; 103 } 104 105 /** @hide */ 106 public CharSequence getDescription() { 107 return mDescription; 108 } 109 110 /** @hide */ 111 public void addSavableIds(@Nullable ArrayList<Dataset> datasets) { 112 if (datasets != null) { 113 for (Dataset dataset : datasets) { 114 final ArrayList<AutoFillId> ids = dataset.getFieldIds(); 115 if (ids != null) { 116 final int fieldCount = ids.size(); 117 for (int i = 0; i < fieldCount; i++) { 118 final AutoFillId id = ids.get(i); 119 if (mSavableIds == null) { 120 mSavableIds = new ArraySet<>(); 121 } 122 mSavableIds.add(id); 123 } 124 } 125 } 126 } 127 } 128 129 /** 130 * A builder for {@link SaveInfo} objects. 131 */ 132 public static final class Builder { 133 134 private final @SaveDataType int mType; 135 private ArraySet<AutoFillId> mSavableIds; 136 private CharSequence mDescription; 137 private boolean mDestroyed; 138 139 /** 140 * Creates a new builder. 141 * 142 * @param type the type of information the associated {@link FillResponse} represents. Must 143 * be {@link SaveInfo#SAVE_DATA_TYPE_GENERIC}, {@link SaveInfo#SAVE_DATA_TYPE_PASSWORD}, 144 * {@link SaveInfo#SAVE_DATA_TYPE_ADDRESS}, or {@link SaveInfo#SAVE_DATA_TYPE_CREDIT_CARD}; 145 * otherwise it will assume {@link SaveInfo#SAVE_DATA_TYPE_GENERIC}. 146 */ 147 public Builder(@SaveDataType int type) { 148 switch (type) { 149 case SAVE_DATA_TYPE_PASSWORD: 150 case SAVE_DATA_TYPE_ADDRESS: 151 case SAVE_DATA_TYPE_CREDIT_CARD: 152 mType = type; 153 break; 154 default: 155 mType = SAVE_DATA_TYPE_GENERIC; 156 } 157 } 158 159 /** 160 * Adds ids of additional views the service would be interested to save, but were not 161 * indirectly set through {@link FillResponse.Builder#addDataset(Dataset)}. 162 * 163 * @param ids The savable ids. 164 * @return This builder. 165 * 166 * @see FillResponse 167 */ 168 public @NonNull Builder addSavableIds(@Nullable AutoFillId... ids) { 169 throwIfDestroyed(); 170 171 if (ids == null) { 172 return this; 173 } 174 for (AutoFillId id : ids) { 175 if (mSavableIds == null) { 176 mSavableIds = new ArraySet<>(); 177 } 178 mSavableIds.add(id); 179 } 180 return this; 181 } 182 183 /** 184 * Sets an optional description to be shown in the UI when the user is asked to save. 185 * 186 * <p>Typically, it describes how the data will be stored by the service, so it can help 187 * users to decide whether they can trust the service to save their data. 188 * 189 * @param description a succint description. 190 * @return This Builder. 191 */ 192 public @NonNull Builder setDescription(@Nullable CharSequence description) { 193 mDescription = description; 194 return this; 195 } 196 197 /** 198 * Builds a new {@link SaveInfo} instance. 199 */ 200 public SaveInfo build() { 201 throwIfDestroyed(); 202 mDestroyed = true; 203 return new SaveInfo(this); 204 } 205 206 private void throwIfDestroyed() { 207 if (mDestroyed) { 208 throw new IllegalStateException("Already called #build()"); 209 } 210 } 211 212 } 213 214 ///////////////////////////////////// 215 // Object "contract" methods. // 216 ///////////////////////////////////// 217 @Override 218 public String toString() { 219 if (!DEBUG) return super.toString(); 220 221 return new StringBuilder("SaveInfo: [type=").append(mType) 222 .append(", savableIds=").append(mSavableIds) 223 .append("]").toString(); 224 } 225 226 ///////////////////////////////////// 227 // Parcelable "contract" methods. // 228 ///////////////////////////////////// 229 230 @Override 231 public int describeContents() { 232 return 0; 233 } 234 235 @Override 236 public void writeToParcel(Parcel parcel, int flags) { 237 parcel.writeInt(mType); 238 parcel.writeTypedArraySet(mSavableIds, flags); 239 parcel.writeCharSequence(mDescription); 240 } 241 242 public static final Parcelable.Creator<SaveInfo> CREATOR = new Parcelable.Creator<SaveInfo>() { 243 @Override 244 public SaveInfo createFromParcel(Parcel parcel) { 245 // Always go through the builder to ensure the data ingested by 246 // the system obeys the contract of the builder to avoid attacks 247 // using specially crafted parcels. 248 final Builder builder = new Builder(parcel.readInt()); 249 final ArraySet<AutoFillId> savableIds = parcel.readTypedArraySet(null); 250 final int savableIdsCount = (savableIds != null) ? savableIds.size() : 0; 251 for (int i = 0; i < savableIdsCount; i++) { 252 builder.addSavableIds(savableIds.valueAt(i)); 253 } 254 builder.setDescription(parcel.readCharSequence()); 255 return builder.build(); 256 } 257 258 @Override 259 public SaveInfo[] newArray(int size) { 260 return new SaveInfo[size]; 261 } 262 }; 263} 264