Skip to content

Commit 58c97df

Browse files
committed
Migrate common
1 parent a2020ac commit 58c97df

File tree

3 files changed

+157
-135
lines changed

3 files changed

+157
-135
lines changed

firebase-common/src/main/java/com/google/firebase/heartbeatinfo/HeartBeatInfoStorage.java

Lines changed: 123 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
package com.google.firebase.heartbeatinfo;
1616

1717
import android.content.Context;
18-
import android.content.SharedPreferences;
1918
import android.os.Build;
2019
import androidx.annotation.RestrictTo;
2120
import androidx.annotation.VisibleForTesting;
21+
import androidx.datastore.preferences.core.*;
22+
import androidx.datastore.preferences.core.Preferences;
23+
import com.google.firebase.datastore.DataStorage;
24+
import com.google.firebase.datastore.DataStoreKt;
2225
import java.text.SimpleDateFormat;
2326
import java.time.Instant;
2427
import java.time.LocalDateTime;
@@ -40,128 +43,138 @@
4043
class HeartBeatInfoStorage {
4144
private static HeartBeatInfoStorage instance = null;
4245

43-
private static final String GLOBAL = "fire-global";
46+
private static final Preferences.Key<Long> GLOBAL = PreferencesKeys.longKey("fire-global");
4447

4548
private static final String PREFERENCES_NAME = "FirebaseAppHeartBeat";
4649

4750
private static final String HEARTBEAT_PREFERENCES_NAME = "FirebaseHeartBeat";
4851

49-
private static final String HEART_BEAT_COUNT_TAG = "fire-count";
52+
private static final Preferences.Key<Long> HEART_BEAT_COUNT_TAG =
53+
PreferencesKeys.longKey("fire-count");
5054

51-
private static final String LAST_STORED_DATE = "last-used-date";
55+
private static final Preferences.Key<String> LAST_STORED_DATE =
56+
PreferencesKeys.stringKey("last-used-date");
5257

5358
// As soon as you hit the limit of heartbeats. The number of stored heartbeats is halved.
5459
private static final int HEART_BEAT_COUNT_LIMIT = 30;
5560

56-
private final SharedPreferences firebaseSharedPreferences;
61+
private final DataStorage firebaseDataStore;
5762

5863
public HeartBeatInfoStorage(Context applicationContext, String persistenceKey) {
59-
this.firebaseSharedPreferences =
60-
applicationContext.getSharedPreferences(
61-
HEARTBEAT_PREFERENCES_NAME + persistenceKey, Context.MODE_PRIVATE);
64+
this.firebaseDataStore =
65+
new DataStorage(applicationContext, HEARTBEAT_PREFERENCES_NAME + persistenceKey);
6266
}
6367

6468
@VisibleForTesting
6569
@RestrictTo(RestrictTo.Scope.TESTS)
66-
HeartBeatInfoStorage(SharedPreferences firebaseSharedPreferences) {
67-
this.firebaseSharedPreferences = firebaseSharedPreferences;
70+
HeartBeatInfoStorage(DataStorage dataStorage) {
71+
this.firebaseDataStore = dataStorage;
6872
}
6973

7074
@VisibleForTesting
7175
@RestrictTo(RestrictTo.Scope.TESTS)
7276
int getHeartBeatCount() {
73-
return (int) this.firebaseSharedPreferences.getLong(HEART_BEAT_COUNT_TAG, 0);
77+
return this.firebaseDataStore.getSync(HEART_BEAT_COUNT_TAG, 0L).intValue();
7478
}
7579

7680
synchronized void deleteAllHeartBeats() {
77-
SharedPreferences.Editor editor = firebaseSharedPreferences.edit();
78-
int counter = 0;
79-
for (Map.Entry<String, ?> entry : this.firebaseSharedPreferences.getAll().entrySet()) {
80-
if (entry.getValue() instanceof Set) {
81-
// All other heartbeats other than the heartbeats stored today will be deleted.
82-
Set<String> dates = (Set<String>) entry.getValue();
83-
String today = getFormattedDate(System.currentTimeMillis());
84-
String key = entry.getKey();
85-
if (dates.contains(today)) {
86-
Set<String> userAgentDateSet = new HashSet<>();
87-
userAgentDateSet.add(today);
88-
counter += 1;
89-
editor.putStringSet(key, userAgentDateSet);
90-
} else {
91-
editor.remove(key);
92-
}
93-
}
94-
}
95-
if (counter == 0) {
96-
editor.remove(HEART_BEAT_COUNT_TAG);
97-
} else {
98-
editor.putLong(HEART_BEAT_COUNT_TAG, counter);
99-
}
81+
firebaseDataStore.editSync(
82+
(pref) -> {
83+
long counter = 0;
84+
for (Map.Entry<Preferences.Key<?>, Object> entry : pref.asMap().entrySet()) {
85+
if (entry.getValue() instanceof Set) {
86+
// All other heartbeats other than the heartbeats stored today will be deleted.
87+
Preferences.Key<Set<String>> key = (Preferences.Key<Set<String>>) entry.getKey();
88+
Set<String> dates = (Set<String>) entry.getValue();
89+
String today = getFormattedDate(System.currentTimeMillis());
90+
91+
if (dates.contains(today)) {
92+
pref.set(key, Set.of(today));
93+
counter += 1;
94+
} else {
95+
pref.remove(key);
96+
}
97+
}
98+
}
99+
if (counter == 0) {
100+
pref.remove(HEART_BEAT_COUNT_TAG);
101+
} else {
102+
pref.set(HEART_BEAT_COUNT_TAG, counter);
103+
}
100104

101-
editor.commit();
105+
return null;
106+
});
102107
}
103108

104109
synchronized List<HeartBeatResult> getAllHeartBeats() {
105110
ArrayList<HeartBeatResult> heartBeatResults = new ArrayList<>();
106-
for (Map.Entry<String, ?> entry : this.firebaseSharedPreferences.getAll().entrySet()) {
111+
String today = getFormattedDate(System.currentTimeMillis());
112+
113+
for (Map.Entry<Preferences.Key<?>, Object> entry :
114+
this.firebaseDataStore.getAllSync().entrySet()) {
107115
if (entry.getValue() instanceof Set) {
108116
Set<String> dates = new HashSet<>((Set<String>) entry.getValue());
109-
String today = getFormattedDate(System.currentTimeMillis());
110117
dates.remove(today);
111118
if (!dates.isEmpty()) {
112-
heartBeatResults.add(
113-
HeartBeatResult.create(entry.getKey(), new ArrayList<String>(dates)));
119+
heartBeatResults.add(HeartBeatResult.create(entry.getKey().getName(), new ArrayList<>()));
114120
}
115121
}
116122
}
123+
117124
updateGlobalHeartBeat(System.currentTimeMillis());
125+
118126
return heartBeatResults;
119127
}
120128

121-
private synchronized String getStoredUserAgentString(String dateString) {
122-
for (Map.Entry<String, ?> entry : firebaseSharedPreferences.getAll().entrySet()) {
129+
private synchronized Preferences.Key<Set<String>> getStoredUserAgentString(
130+
MutablePreferences preferences, String dateString) {
131+
for (Map.Entry<Preferences.Key<?>, Object> entry : preferences.asMap().entrySet()) {
123132
if (entry.getValue() instanceof Set) {
124133
Set<String> dateSet = (Set<String>) entry.getValue();
125134
for (String date : dateSet) {
126135
if (dateString.equals(date)) {
127-
return entry.getKey();
136+
return PreferencesKeys.stringSetKey(entry.getKey().getName());
128137
}
129138
}
130139
}
131140
}
132141
return null;
133142
}
134143

135-
private synchronized void updateStoredUserAgent(String userAgent, String dateString) {
136-
removeStoredDate(dateString);
144+
private synchronized void updateStoredUserAgent(
145+
MutablePreferences preferences, Preferences.Key<Set<String>> userAgent, String dateString) {
146+
removeStoredDate(preferences, dateString);
137147
Set<String> userAgentDateSet =
138-
new HashSet<String>(
139-
firebaseSharedPreferences.getStringSet(userAgent, new HashSet<String>()));
148+
new HashSet<>(DataStoreKt.getOrDefault(preferences, userAgent, new HashSet<>()));
140149
userAgentDateSet.add(dateString);
141-
firebaseSharedPreferences.edit().putStringSet(userAgent, userAgentDateSet).commit();
150+
preferences.set(userAgent, userAgentDateSet);
142151
}
143152

144-
private synchronized void removeStoredDate(String dateString) {
153+
private synchronized void removeStoredDate(MutablePreferences preferences, String dateString) {
145154
// Find stored heartbeat and clear it.
146-
String userAgentString = getStoredUserAgentString(dateString);
147-
if (userAgentString == null) {
155+
Preferences.Key<Set<String>> userAgent = getStoredUserAgentString(preferences, dateString);
156+
if (userAgent == null) {
148157
return;
149158
}
150159
Set<String> userAgentDateSet =
151-
new HashSet<String>(
152-
firebaseSharedPreferences.getStringSet(userAgentString, new HashSet<String>()));
160+
new HashSet<>(DataStoreKt.getOrDefault(preferences, userAgent, new HashSet<>()));
153161
userAgentDateSet.remove(dateString);
154162
if (userAgentDateSet.isEmpty()) {
155-
firebaseSharedPreferences.edit().remove(userAgentString).commit();
163+
preferences.remove(userAgent);
156164
} else {
157-
firebaseSharedPreferences.edit().putStringSet(userAgentString, userAgentDateSet).commit();
165+
preferences.set(userAgent, userAgentDateSet);
158166
}
159167
}
160168

161169
synchronized void postHeartBeatCleanUp() {
162170
String dateString = getFormattedDate(System.currentTimeMillis());
163-
firebaseSharedPreferences.edit().putString(LAST_STORED_DATE, dateString).commit();
164-
removeStoredDate(dateString);
171+
172+
firebaseDataStore.editSync(
173+
(pref) -> {
174+
pref.set(LAST_STORED_DATE, dateString);
175+
removeStoredDate(pref, dateString);
176+
return null;
177+
});
165178
}
166179

167180
private synchronized String getFormattedDate(long millis) {
@@ -176,71 +189,77 @@ private synchronized String getFormattedDate(long millis) {
176189

177190
synchronized void storeHeartBeat(long millis, String userAgentString) {
178191
String dateString = getFormattedDate(millis);
179-
String lastDateString = firebaseSharedPreferences.getString(LAST_STORED_DATE, "");
180-
if (lastDateString.equals(dateString)) {
181-
String storedUserAgentString = getStoredUserAgentString(dateString);
182-
if (storedUserAgentString == null) {
183-
// Heartbeat already sent for today.
184-
return;
185-
}
186-
if (storedUserAgentString.equals(userAgentString)) {
187-
// UserAgent not updated.
188-
return;
189-
} else {
190-
updateStoredUserAgent(userAgentString, dateString);
191-
return;
192-
}
193-
}
194-
long heartBeatCount = firebaseSharedPreferences.getLong(HEART_BEAT_COUNT_TAG, 0);
195-
if (heartBeatCount + 1 == HEART_BEAT_COUNT_LIMIT) {
196-
cleanUpStoredHeartBeats();
197-
heartBeatCount = firebaseSharedPreferences.getLong(HEART_BEAT_COUNT_TAG, 0);
198-
}
199-
Set<String> userAgentDateSet =
200-
new HashSet<String>(
201-
firebaseSharedPreferences.getStringSet(userAgentString, new HashSet<String>()));
202-
userAgentDateSet.add(dateString);
203-
heartBeatCount += 1;
204-
firebaseSharedPreferences
205-
.edit()
206-
.putStringSet(userAgentString, userAgentDateSet)
207-
.putLong(HEART_BEAT_COUNT_TAG, heartBeatCount)
208-
.putString(LAST_STORED_DATE, dateString)
209-
.commit();
192+
Preferences.Key<Set<String>> userAgent = PreferencesKeys.stringSetKey(userAgentString);
193+
firebaseDataStore.editSync(
194+
(pref) -> {
195+
String lastDateString = DataStoreKt.getOrDefault(pref, LAST_STORED_DATE, "");
196+
if (lastDateString.equals(dateString)) {
197+
Preferences.Key<Set<String>> storedUserAgent =
198+
getStoredUserAgentString(pref, dateString);
199+
if (storedUserAgent == null) {
200+
// Heartbeat already sent for today.
201+
return null;
202+
} else if (storedUserAgent.getName().equals(userAgentString)) {
203+
// UserAgent not updated.
204+
return null;
205+
} else {
206+
updateStoredUserAgent(pref, userAgent, dateString);
207+
return null;
208+
}
209+
}
210+
long heartBeatCount = DataStoreKt.getOrDefault(pref, HEART_BEAT_COUNT_TAG, 0L);
211+
if (heartBeatCount + 1 == HEART_BEAT_COUNT_LIMIT) {
212+
heartBeatCount = cleanUpStoredHeartBeats(pref);
213+
}
214+
Set<String> userAgentDateSet =
215+
new HashSet<>(DataStoreKt.getOrDefault(pref, userAgent, new HashSet<>()));
216+
userAgentDateSet.add(dateString);
217+
heartBeatCount += 1;
218+
219+
pref.set(userAgent, userAgentDateSet);
220+
pref.set(HEART_BEAT_COUNT_TAG, heartBeatCount);
221+
pref.set(LAST_STORED_DATE, dateString);
222+
223+
return null;
224+
});
210225
}
211226

212-
private synchronized void cleanUpStoredHeartBeats() {
213-
long heartBeatCount = firebaseSharedPreferences.getLong(HEART_BEAT_COUNT_TAG, 0);
227+
private synchronized long cleanUpStoredHeartBeats(MutablePreferences preferences) {
228+
long heartBeatCount = DataStoreKt.getOrDefault(preferences, HEART_BEAT_COUNT_TAG, 0L);
229+
214230
String lowestDate = null;
215231
String userAgentString = "";
216-
for (Map.Entry<String, ?> entry : firebaseSharedPreferences.getAll().entrySet()) {
232+
Set<String> userAgentDateSet = new HashSet<>();
233+
for (Map.Entry<Preferences.Key<?>, Object> entry : preferences.asMap().entrySet()) {
217234
if (entry.getValue() instanceof Set) {
218235
Set<String> dateSet = (Set<String>) entry.getValue();
219236
for (String date : dateSet) {
220237
if (lowestDate == null || lowestDate.compareTo(date) > 0) {
238+
userAgentDateSet = dateSet;
221239
lowestDate = date;
222-
userAgentString = entry.getKey();
240+
userAgentString = entry.getKey().getName();
223241
}
224242
}
225243
}
226244
}
227-
Set<String> userAgentDateSet =
228-
new HashSet<String>(
229-
firebaseSharedPreferences.getStringSet(userAgentString, new HashSet<String>()));
245+
userAgentDateSet = new HashSet<>(userAgentDateSet);
230246
userAgentDateSet.remove(lowestDate);
231-
firebaseSharedPreferences
232-
.edit()
233-
.putStringSet(userAgentString, userAgentDateSet)
234-
.putLong(HEART_BEAT_COUNT_TAG, heartBeatCount - 1)
235-
.commit();
247+
preferences.set(PreferencesKeys.stringSetKey(userAgentString), userAgentDateSet);
248+
preferences.set(HEART_BEAT_COUNT_TAG, heartBeatCount - 1);
249+
250+
return heartBeatCount - 1;
236251
}
237252

238253
synchronized long getLastGlobalHeartBeat() {
239-
return firebaseSharedPreferences.getLong(GLOBAL, -1);
254+
return firebaseDataStore.getSync(GLOBAL, -1L);
240255
}
241256

242257
synchronized void updateGlobalHeartBeat(long millis) {
243-
firebaseSharedPreferences.edit().putLong(GLOBAL, millis).commit();
258+
firebaseDataStore.editSync(
259+
(pref) -> {
260+
pref.set(GLOBAL, millis);
261+
return null;
262+
});
244263
}
245264

246265
synchronized boolean isSameDateUtc(long base, long target) {
@@ -252,15 +271,11 @@ synchronized boolean isSameDateUtc(long base, long target) {
252271
A sdk heartbeat is sent either when there is no heartbeat sent ever for the sdk or
253272
when the last heartbeat send for the sdk was later than a day before.
254273
*/
255-
synchronized boolean shouldSendSdkHeartBeat(String heartBeatTag, long millis) {
256-
if (firebaseSharedPreferences.contains(heartBeatTag)) {
257-
if (!this.isSameDateUtc(firebaseSharedPreferences.getLong(heartBeatTag, -1), millis)) {
258-
firebaseSharedPreferences.edit().putLong(heartBeatTag, millis).commit();
259-
return true;
260-
}
274+
synchronized boolean shouldSendSdkHeartBeat(Preferences.Key<Long> heartBeatTag, long millis) {
275+
if (this.isSameDateUtc(firebaseDataStore.getSync(heartBeatTag, -1L), millis)) {
261276
return false;
262277
} else {
263-
firebaseSharedPreferences.edit().putLong(heartBeatTag, millis).commit();
278+
firebaseDataStore.putSync(heartBeatTag, millis);
264279
return true;
265280
}
266281
}

firebase-common/src/test/java/com/google/firebase/heartbeatinfo/DefaultHeartBeatControllerTest.java

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
import static org.mockito.Mockito.when;
2626

2727
import android.content.Context;
28-
import android.content.SharedPreferences;
2928
import androidx.test.core.app.ApplicationProvider;
3029
import androidx.test.ext.junit.runners.AndroidJUnit4;
3130
import com.google.common.collect.ImmutableSet;
31+
import com.google.firebase.datastore.DataStorage;
3232
import com.google.firebase.platforminfo.UserAgentPublisher;
3333
import java.io.ByteArrayOutputStream;
3434
import java.io.IOException;
@@ -107,10 +107,8 @@ public void generateHeartBeat_oneHeartBeat() throws InterruptedException, Timeou
107107
public void firstNewThenOld_synchronizedCorrectly()
108108
throws InterruptedException, TimeoutException {
109109
Context context = ApplicationProvider.getApplicationContext();
110-
SharedPreferences heartBeatSharedPreferences =
111-
context.getSharedPreferences("testHeartBeat", Context.MODE_PRIVATE);
112-
HeartBeatInfoStorage heartBeatInfoStorage =
113-
new HeartBeatInfoStorage(heartBeatSharedPreferences);
110+
DataStorage heartBeatDataStore = new DataStorage(context, "testHeartBeat");
111+
HeartBeatInfoStorage heartBeatInfoStorage = new HeartBeatInfoStorage(heartBeatDataStore);
114112
DefaultHeartBeatController controller =
115113
new DefaultHeartBeatController(
116114
() -> heartBeatInfoStorage, logSources, executor, () -> publisher, context);
@@ -130,10 +128,8 @@ public void firstNewThenOld_synchronizedCorrectly()
130128
public void firstOldThenNew_synchronizedCorrectly()
131129
throws InterruptedException, TimeoutException {
132130
Context context = ApplicationProvider.getApplicationContext();
133-
SharedPreferences heartBeatSharedPreferences =
134-
context.getSharedPreferences("testHeartBeat", Context.MODE_PRIVATE);
135-
HeartBeatInfoStorage heartBeatInfoStorage =
136-
new HeartBeatInfoStorage(heartBeatSharedPreferences);
131+
DataStorage heartBeatDataStore = new DataStorage(context, "testHeartBeat");
132+
HeartBeatInfoStorage heartBeatInfoStorage = new HeartBeatInfoStorage(heartBeatDataStore);
137133
DefaultHeartBeatController controller =
138134
new DefaultHeartBeatController(
139135
() -> heartBeatInfoStorage, logSources, executor, () -> publisher, context);

0 commit comments

Comments
 (0)