• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 
17 package com.android.server.healthconnect.storage.datatypehelpers;
18 
19 import static com.android.server.healthconnect.storage.request.UpsertTableRequest.TYPE_STRING;
20 import static com.android.server.healthconnect.storage.utils.StorageUtils.TEXT_NOT_NULL_UNIQUE;
21 import static com.android.server.healthconnect.storage.utils.StorageUtils.TEXT_NULL;
22 
23 import android.annotation.Nullable;
24 import android.content.ContentValues;
25 import android.database.Cursor;
26 import android.util.Pair;
27 
28 import com.android.server.healthconnect.storage.TransactionManager;
29 import com.android.server.healthconnect.storage.request.CreateTableRequest;
30 import com.android.server.healthconnect.storage.request.DeleteTableRequest;
31 import com.android.server.healthconnect.storage.request.ReadTableRequest;
32 import com.android.server.healthconnect.storage.request.UpsertTableRequest;
33 import com.android.server.healthconnect.storage.utils.StorageUtils;
34 
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.concurrent.ConcurrentHashMap;
41 
42 /**
43  * A helper class to store user preferences, set in UI APK for the platform.
44  *
45  * @hide
46  */
47 // TODO(b/303023796): Make this final.
48 public class PreferenceHelper extends DatabaseHelper {
49     private static final String TAG = "PreferenceHelper";
50     private static final String TABLE_NAME = "preference_table";
51     private static final String KEY_COLUMN_NAME = "key";
52     public static final List<Pair<String, Integer>> UNIQUE_COLUMN_INFO =
53             Collections.singletonList(new Pair<>(KEY_COLUMN_NAME, TYPE_STRING));
54     private static final String VALUE_COLUMN_NAME = "value";
55     private final TransactionManager mTransactionManager;
56 
57     /**
58      * Key to store timestamp of the last time any PHR <b>read medical resources</b> API is called.
59      */
60     private static final String PREFS_KEY_PHR_LAST_READ_MEDICAL_RESOURCES_API =
61             "phr_last_read_medical_resources_api";
62 
63     protected volatile ConcurrentHashMap<String, String> mPreferences;
64 
65     @SuppressWarnings("NullAway.Init") // TODO(b/317029272): fix this suppression
PreferenceHelper( TransactionManager transactionManager, DatabaseHelpers databaseHelpers)66     public PreferenceHelper(
67             TransactionManager transactionManager, DatabaseHelpers databaseHelpers) {
68         super(databaseHelpers);
69         mTransactionManager = transactionManager;
70     }
71 
72     /** Note: Overrides existing preference (if it exists) with the new value */
insertOrReplacePreference(String key, String value)73     public synchronized void insertOrReplacePreference(String key, String value) {
74         mTransactionManager.insertOrReplaceOnConflict(
75                 new UpsertTableRequest(
76                         TABLE_NAME, getContentValues(key, value), UNIQUE_COLUMN_INFO));
77         getPreferences().put(key, value);
78     }
79 
80     /** Removes key entry from the table */
removeKey(String id)81     public synchronized void removeKey(String id) {
82         mTransactionManager.delete(new DeleteTableRequest(TABLE_NAME).setId(KEY_COLUMN_NAME, id));
83         getPreferences().remove(id);
84     }
85 
86     /** Inserts multiple preferences together in a transaction */
insertOrReplacePreferencesTransaction( HashMap<String, String> keyValues)87     public synchronized void insertOrReplacePreferencesTransaction(
88             HashMap<String, String> keyValues) {
89         List<UpsertTableRequest> requests = new ArrayList<>();
90         keyValues.forEach(
91                 (key, value) ->
92                         requests.add(
93                                 new UpsertTableRequest(
94                                         TABLE_NAME,
95                                         getContentValues(key, value),
96                                         UNIQUE_COLUMN_INFO)));
97         mTransactionManager.insertOrReplaceAllOnConflict(requests);
98         getPreferences().putAll(keyValues);
99     }
100 
getCreateTableRequest()101     public static CreateTableRequest getCreateTableRequest() {
102         return new CreateTableRequest(TABLE_NAME, getColumnInfo());
103     }
104 
105     @Nullable
getPreference(String key)106     public String getPreference(String key) {
107         return getPreferences().get(key);
108     }
109 
110     @SuppressWarnings("NullAway") // TODO(b/317029272): fix this suppression
111     @Override
clearCache()112     public synchronized void clearCache() {
113         mPreferences = null;
114     }
115 
116     @Override
getMainTableName()117     protected String getMainTableName() {
118         return TABLE_NAME;
119     }
120 
121     /** Fetch preferences into memory. */
initializePreferences()122     public void initializePreferences() {
123         populatePreferences();
124     }
125 
getPreferences()126     protected Map<String, String> getPreferences() {
127         if (mPreferences == null) {
128             populatePreferences();
129         }
130         return mPreferences;
131     }
132 
getContentValues(String key, String value)133     private ContentValues getContentValues(String key, String value) {
134         ContentValues contentValues = new ContentValues();
135         contentValues.put(KEY_COLUMN_NAME, key);
136         contentValues.put(VALUE_COLUMN_NAME, value);
137         return contentValues;
138     }
139 
populatePreferences()140     private synchronized void populatePreferences() {
141         if (mPreferences != null) {
142             return;
143         }
144 
145         mPreferences = new ConcurrentHashMap<>();
146         try (Cursor cursor = mTransactionManager.read(new ReadTableRequest(TABLE_NAME))) {
147             while (cursor.moveToNext()) {
148                 String key = StorageUtils.getCursorString(cursor, KEY_COLUMN_NAME);
149                 String value = StorageUtils.getCursorString(cursor, VALUE_COLUMN_NAME);
150                 mPreferences.put(key, value);
151             }
152         }
153     }
154 
getColumnInfo()155     private static List<Pair<String, String>> getColumnInfo() {
156         ArrayList<Pair<String, String>> columnInfo = new ArrayList<>();
157         columnInfo.add(new Pair<>(KEY_COLUMN_NAME, TEXT_NOT_NULL_UNIQUE));
158         columnInfo.add(new Pair<>(VALUE_COLUMN_NAME, TEXT_NULL));
159 
160         return columnInfo;
161     }
162 }
163