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 package com.example.android.autofillframework.service.model; 17 18 import android.service.autofill.Dataset; 19 import android.support.annotation.NonNull; 20 import android.util.Log; 21 import android.view.View; 22 import android.view.autofill.AutofillId; 23 import android.view.autofill.AutofillValue; 24 25 import org.json.JSONException; 26 import org.json.JSONObject; 27 28 import java.util.HashMap; 29 import java.util.Iterator; 30 import java.util.List; 31 import java.util.Set; 32 33 /** 34 * ClientFormData is the model that holds all of the data on a client app's page, plus the dataset 35 * name associated with it. 36 */ 37 public final class ClientFormData { 38 private static final String TAG = "ClientFormData"; 39 private final HashMap<String, SavedAutofillValue> hintMap; 40 private String datasetName; 41 42 public ClientFormData() { 43 this(null, new HashMap<String, SavedAutofillValue>()); 44 } 45 46 public ClientFormData(String datasetName, HashMap<String, SavedAutofillValue> hintMap) { 47 this.hintMap = hintMap; 48 this.datasetName = datasetName; 49 } 50 51 public static ClientFormData fromJson(JSONObject jsonObject) { 52 HashMap<String, SavedAutofillValue> hintMap = new HashMap<>(); 53 try { 54 String datasetName = jsonObject.has("datasetName") ? 55 jsonObject.getString("datasetName") : null; 56 JSONObject valuesJson = jsonObject.getJSONObject("values"); 57 Iterator<String> hints = valuesJson.keys(); 58 while (hints.hasNext()) { 59 String hint = hints.next(); 60 JSONObject valueAsJson = valuesJson 61 .getJSONObject(hint); 62 if (valueAsJson != null) { 63 SavedAutofillValue savedAutofillValue = SavedAutofillValue.fromJson(valueAsJson); 64 hintMap.put(hint, savedAutofillValue); 65 } 66 } 67 return new ClientFormData(datasetName, hintMap); 68 } catch (JSONException e) { 69 Log.d(TAG, e.getMessage()); 70 return null; 71 } 72 } 73 74 /** 75 * Returns the name of the {@link Dataset}. 76 */ 77 public String getDatasetName() { 78 return this.datasetName; 79 } 80 81 /** 82 * Sets the {@link Dataset} name. 83 */ 84 public void setDatasetName(String datasetName) { 85 this.datasetName = datasetName; 86 } 87 88 /** 89 * Sets values for a list of hints. 90 */ 91 public void set(@NonNull String[] autofillHints, @NonNull SavedAutofillValue autofillValue) { 92 if (autofillHints.length < 1) { 93 return; 94 } 95 for (int i = 0; i < autofillHints.length; i++) { 96 hintMap.put(autofillHints[i], autofillValue); 97 } 98 } 99 100 /** 101 * Populates a {@link Dataset.Builder} with appropriate values for each {@link AutofillId} 102 * in a {@code AutofillFieldsCollection}. 103 */ 104 public boolean applyToFields(AutofillFieldsCollection autofillFieldsCollection, 105 Dataset.Builder datasetBuilder) { 106 boolean setValueAtLeastOnce = false; 107 List<String> allHints = autofillFieldsCollection.getAllHints(); 108 for (int hintIndex = 0; hintIndex < allHints.size(); hintIndex++) { 109 String hint = allHints.get(hintIndex); 110 List<AutofillField> autofillFields = autofillFieldsCollection.getFieldsForHint(hint); 111 if (autofillFields == null) { 112 continue; 113 } 114 for (int autofillFieldIndex = 0; autofillFieldIndex < autofillFields.size(); autofillFieldIndex++) { 115 AutofillField autofillField = autofillFields.get(autofillFieldIndex); 116 AutofillId autofillId = autofillField.getId(); 117 int autofillType = autofillField.getAutofillType(); 118 SavedAutofillValue savedAutofillValue = hintMap.get(hint); 119 switch (autofillType) { 120 case View.AUTOFILL_TYPE_LIST: 121 int listValue = autofillField.getAutofillOptionIndex(savedAutofillValue.getTextValue()); 122 if (listValue != -1) { 123 datasetBuilder.setValue(autofillId, AutofillValue.forList(listValue)); 124 setValueAtLeastOnce = true; 125 } 126 break; 127 case View.AUTOFILL_TYPE_DATE: 128 long dateValue = savedAutofillValue.getDateValue(); 129 if (dateValue != -1) { 130 datasetBuilder.setValue(autofillId, AutofillValue.forDate(dateValue)); 131 setValueAtLeastOnce = true; 132 } 133 break; 134 case View.AUTOFILL_TYPE_TEXT: 135 String textValue = savedAutofillValue.getTextValue(); 136 if (textValue != null) { 137 datasetBuilder.setValue(autofillId, AutofillValue.forText(textValue)); 138 setValueAtLeastOnce = true; 139 } 140 break; 141 case View.AUTOFILL_TYPE_TOGGLE: 142 if (savedAutofillValue.hasToggleValue()) { 143 boolean toggleValue = savedAutofillValue.getToggleValue(); 144 datasetBuilder.setValue(autofillId, AutofillValue.forToggle(toggleValue)); 145 setValueAtLeastOnce = true; 146 } 147 break; 148 case View.AUTOFILL_TYPE_NONE: 149 default: 150 Log.w(TAG, "Invalid autofill type - " + autofillType); 151 break; 152 } 153 } 154 } 155 return setValueAtLeastOnce; 156 } 157 158 public JSONObject toJson() { 159 JSONObject jsonObject = new JSONObject(); 160 try { 161 jsonObject.put("datasetName", datasetName != null ? datasetName : JSONObject.NULL); 162 JSONObject jsonValues = new JSONObject(); 163 Set<String> hints = hintMap.keySet(); 164 for (String hint : hints) { 165 SavedAutofillValue value = hintMap.get(hint); 166 jsonValues.put(hint, value != null ? value.toJson() : JSONObject.NULL); 167 } 168 jsonObject.put("values", jsonValues); 169 } catch (JSONException e) { 170 Log.e(TAG, e.getMessage()); 171 } 172 return jsonObject; 173 } 174 175 public boolean helpsWithHints(List<String> autofillHints) { 176 for (int i = 0; i < autofillHints.size(); i++) { 177 String autofillHint = autofillHints.get(i); 178 if (hintMap.get(autofillHint) != null && !hintMap.get(autofillHint).isNull()) { 179 return true; 180 } 181 } 182 return false; 183 } 184 } 185