• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
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.google.android.libraries.mobiledatadownload.populator;
17 
18 import android.content.Context;
19 import android.content.SharedPreferences;
20 import com.google.android.libraries.mobiledatadownload.internal.util.SharedPreferencesUtil;
21 import com.google.android.libraries.mobiledatadownload.tracing.PropagatedFutures;
22 import com.google.common.base.Optional;
23 import com.google.common.base.Supplier;
24 import com.google.common.base.Suppliers;
25 import com.google.common.util.concurrent.ListenableFuture;
26 import com.google.mobiledatadownload.populator.MetadataProto.ManifestFileBookkeeping;
27 import java.io.IOException;
28 import java.util.concurrent.Executor;
29 
30 /** ManifestFileMetadataStore based on SharedPreferences. */
31 public final class SharedPreferencesManifestFileMetadata implements ManifestFileMetadataStore {
32 
33   private static final String SHARED_PREFS_NAME = "ManifestFileMetadata";
34 
35   private final Object lock = new Object();
36 
37   private final Supplier<SharedPreferences> sharedPrefs;
38   private final Executor backgroundExecutor;
39 
40   /**
41    * @param sharedPrefs may be called multiple times, so memoization is recommended
42    */
create( Supplier<SharedPreferences> sharedPrefs, Executor backgroundExecutor)43   public static SharedPreferencesManifestFileMetadata create(
44       Supplier<SharedPreferences> sharedPrefs, Executor backgroundExecutor) {
45     return new SharedPreferencesManifestFileMetadata(sharedPrefs, backgroundExecutor);
46   }
47 
createFromContext( Context context, Optional<String> instanceIdOptional, Executor backgroundExecutor)48   public static SharedPreferencesManifestFileMetadata createFromContext(
49       Context context, Optional<String> instanceIdOptional, Executor backgroundExecutor) {
50     // Avoid calling getSharedPreferences on the main thread.
51     Supplier<SharedPreferences> sharedPrefs =
52         Suppliers.memoize(
53             () ->
54                 SharedPreferencesUtil.getSharedPreferences(
55                     context, SHARED_PREFS_NAME, instanceIdOptional));
56     return new SharedPreferencesManifestFileMetadata(sharedPrefs, backgroundExecutor);
57   }
58 
SharedPreferencesManifestFileMetadata( Supplier<SharedPreferences> sharedPrefs, Executor backgroundExecutor)59   private SharedPreferencesManifestFileMetadata(
60       Supplier<SharedPreferences> sharedPrefs, Executor backgroundExecutor) {
61     this.sharedPrefs = sharedPrefs;
62     this.backgroundExecutor = backgroundExecutor;
63   }
64 
65   @Override
read(String manifestId)66   public ListenableFuture<Optional<ManifestFileBookkeeping>> read(String manifestId) {
67     return PropagatedFutures.submit(
68         () -> {
69           synchronized (lock) {
70             ManifestFileBookkeeping proto =
71                 SharedPreferencesUtil.readProto(
72                     sharedPrefs.get(), manifestId, ManifestFileBookkeeping.parser());
73             return Optional.fromNullable(proto);
74           }
75         },
76         backgroundExecutor);
77   }
78 
79   @Override
80   public ListenableFuture<Void> upsert(String manifestId, ManifestFileBookkeeping value) {
81     return PropagatedFutures.submit(
82         () -> {
83           synchronized (lock) {
84             SharedPreferences.Editor editor = sharedPrefs.get().edit();
85             SharedPreferencesUtil.writeProto(editor, manifestId, value);
86             if (!editor.commit()) {
87               throw new IOException("Failed to commit");
88             }
89             return null; // for Callable
90           }
91         },
92         backgroundExecutor);
93   }
94 }
95