Home | History | Annotate | Download | only in datasource
      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.datasource;
     17 
     18 import android.content.Context;
     19 import android.content.SharedPreferences;
     20 import android.util.ArraySet;
     21 
     22 import com.example.android.autofillframework.service.model.ClientFormData;
     23 
     24 import org.json.JSONException;
     25 import org.json.JSONObject;
     26 
     27 import java.util.HashMap;
     28 import java.util.List;
     29 import java.util.Set;
     30 
     31 /**
     32  * Singleton autofill data repository, that stores autofill fields to SharedPreferences.
     33  * DISCLAIMER, you should not store sensitive fields like user data unencrypted. This is only done
     34  * here for simplicity and learning purposes.
     35  */
     36 public class LocalAutofillRepository implements AutofillRepository {
     37     private static final String SHARED_PREF_KEY = "com.example.android.autofillframework.service";
     38     private static final String CLIENT_FORM_DATA_KEY = "loginCredentialDatasets";
     39     private static final String DATASET_NUMBER_KEY = "datasetNumber";
     40 
     41     private static LocalAutofillRepository sInstance;
     42 
     43     private final SharedPreferences mPrefs;
     44 
     45     // TODO prepend with autofill data set in Settings.
     46     private LocalAutofillRepository(Context context) {
     47         mPrefs = context.getApplicationContext()
     48                 .getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE);
     49     }
     50 
     51     public static LocalAutofillRepository getInstance(Context context) {
     52         if (sInstance == null) {
     53             sInstance = new LocalAutofillRepository(context);
     54         }
     55         return sInstance;
     56     }
     57 
     58     @Override
     59     public HashMap<String, ClientFormData> getClientFormData(List<String> focusedAutofillHints,
     60             List<String> allAutofillHints) {
     61         try {
     62             // TODO use sqlite instead.
     63             boolean hasDataForFocusedAutofillHints = false;
     64             HashMap<String, ClientFormData> clientFormDataMap = new HashMap<>();
     65             Set<String> clientFormDataStringSet = getAllAutofillDataStringSet();
     66             for (String clientFormDataString : clientFormDataStringSet) {
     67                 ClientFormData clientFormData = ClientFormData
     68                         .fromJson(new JSONObject(clientFormDataString));
     69                 if (clientFormData != null) {
     70                     if (clientFormData.helpsWithHints(focusedAutofillHints)) {
     71                         hasDataForFocusedAutofillHints = true;
     72                     }
     73                     if (clientFormData.helpsWithHints(allAutofillHints)) {
     74                         clientFormDataMap.put(clientFormData.getDatasetName(), clientFormData);
     75                     }
     76                 }
     77             }
     78             if (hasDataForFocusedAutofillHints) {
     79                 return clientFormDataMap;
     80             } else {
     81                 return null;
     82             }
     83         } catch (JSONException e) {
     84             return null;
     85         }
     86     }
     87 
     88     @Override
     89     public void saveClientFormData(ClientFormData clientFormData) {
     90         //TODO use sqlite instead.
     91         String datasetName = "dataset-" + getDatasetNumber();
     92         clientFormData.setDatasetName(datasetName);
     93         Set<String> allAutofillData = getAllAutofillDataStringSet();
     94         allAutofillData.add(clientFormData.toJson().toString());
     95         saveAllAutofillDataStringSet(allAutofillData);
     96         incrementDatasetNumber();
     97     }
     98 
     99     @Override
    100     public void clear() {
    101         mPrefs.edit().remove(CLIENT_FORM_DATA_KEY).apply();
    102     }
    103 
    104     private Set<String> getAllAutofillDataStringSet() {
    105         return mPrefs.getStringSet(CLIENT_FORM_DATA_KEY, new ArraySet<String>());
    106     }
    107 
    108     private void saveAllAutofillDataStringSet(Set<String> allAutofillDataStringSet) {
    109         mPrefs.edit().putStringSet(CLIENT_FORM_DATA_KEY, allAutofillDataStringSet).apply();
    110     }
    111 
    112     /**
    113      * For simplicity, datasets will be named in the form "dataset-X" where X means
    114      * this was the Xth dataset saved.
    115      */
    116     private int getDatasetNumber() {
    117         return mPrefs.getInt(DATASET_NUMBER_KEY, 0);
    118     }
    119 
    120     /**
    121      * Every time a dataset is saved, this should be called to increment the dataset number.
    122      * (only important for this service's dataset naming scheme).
    123      */
    124     private void incrementDatasetNumber() {
    125         mPrefs.edit().putInt(DATASET_NUMBER_KEY, getDatasetNumber() + 1).apply();
    126     }
    127 }