aboutsummaryrefslogtreecommitdiff
path: root/input/autofill/AutofillFramework/kotlinApp/Application/src/main/java/com/example/android/autofillframework/multidatasetservice/datasource/SharedPrefsAutofillRepository.kt
blob: e2171708d1453dcc4bded8d388f46532860ea9d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
 * Copyright (C) 2017 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 com.example.android.autofillframework.multidatasetservice.datasource

import android.content.Context
import android.content.SharedPreferences
import android.util.ArraySet
import com.example.android.autofillframework.multidatasetservice.model.FilledAutofillFieldCollection
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken


/**
 * Singleton autofill data repository that stores autofill fields to SharedPreferences.
 * Disclaimer: you should not store sensitive fields like user data unencrypted. This is done
 * here only for simplicity and learning purposes.
 */
object SharedPrefsAutofillRepository : AutofillRepository {
    private val SHARED_PREF_KEY = "com.example.android.autofillframework.service"
    private val CLIENT_FORM_DATA_KEY = "loginCredentialDatasets"
    private val DATASET_NUMBER_KEY = "datasetNumber"

    private fun getPrefs(context: Context): SharedPreferences {
        return context.applicationContext.getSharedPreferences(SHARED_PREF_KEY, Context.MODE_PRIVATE)
    }

    override fun getClientFormData(context: Context, focusedAutofillHints: List<String>,
            allAutofillHints: List<String>): HashMap<String, FilledAutofillFieldCollection>? {
        var hasDataForFocusedAutofillHints = false
        val clientFormDataMap = HashMap<String, FilledAutofillFieldCollection>()
        val clientFormDataStringSet = getAllAutofillDataStringSet(context)
        for (clientFormDataString in clientFormDataStringSet) {
            val type = object : TypeToken<FilledAutofillFieldCollection>() {}.type
            Gson().fromJson<FilledAutofillFieldCollection>(clientFormDataString, type)?.let { clientFormData ->
                if (clientFormData.helpsWithHints(focusedAutofillHints)) {
                    // Saved data has data relevant to at least 1 of the hints associated with the
                    // View in focus.
                    hasDataForFocusedAutofillHints = true
                    clientFormData.datasetName?.let { datasetName ->
                        if (clientFormData.helpsWithHints(allAutofillHints)) {
                            // Saved data has data relevant to at least 1 of these hints associated with any
                            // of the Views in the hierarchy.
                            clientFormDataMap.put(datasetName, clientFormData)
                        }
                    }
                }
            }
        }
        if (hasDataForFocusedAutofillHints) {
            return clientFormDataMap
        } else {
            return null
        }
    }

    override fun saveClientFormData(context: Context, filledAutofillFieldCollection: FilledAutofillFieldCollection) {
        val datasetName = "dataset-" + getDatasetNumber(context)
        filledAutofillFieldCollection.datasetName = datasetName
        val allAutofillData = getAllAutofillDataStringSet(context)
        allAutofillData.add(Gson().toJson(filledAutofillFieldCollection).toString())
        saveAllAutofillDataStringSet(context, allAutofillData)
        incrementDatasetNumber(context)
    }

    override fun clear(context: Context) {
        getPrefs(context).edit().remove(CLIENT_FORM_DATA_KEY).remove(DATASET_NUMBER_KEY).apply()
    }

    private fun getAllAutofillDataStringSet(context: Context): MutableSet<String> {
        return getPrefs(context).getStringSet(CLIENT_FORM_DATA_KEY, ArraySet<String>())
    }

    private fun saveAllAutofillDataStringSet(context: Context, allAutofillDataStringSet: Set<String>) {
        getPrefs(context).edit().putStringSet(CLIENT_FORM_DATA_KEY, allAutofillDataStringSet).apply()
    }

    /**
     * For simplicity, datasets will be named in the form "dataset-X" where X means
     * this was the Xth dataset saved.
     */
    private fun getDatasetNumber(context: Context): Int {
        return getPrefs(context).getInt(DATASET_NUMBER_KEY, 0)
    }

    /**
     * Every time a dataset is saved, this should be called to increment the dataset number.
     * (only important for this service's dataset naming scheme).
     */
    private fun incrementDatasetNumber(context: Context) {
        getPrefs(context).edit().putInt(DATASET_NUMBER_KEY, getDatasetNumber(context) + 1).apply()
    }
}