1 | // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | package org.chromium.sync.notifier; |
6 | |
7 | import android.accounts.Account; |
8 | import android.content.Context; |
9 | import android.content.SharedPreferences; |
10 | import android.preference.PreferenceManager; |
11 | import android.util.Base64; |
12 | import android.util.Log; |
13 | |
14 | import com.google.common.annotations.VisibleForTesting; |
15 | import com.google.common.base.Preconditions; |
16 | |
17 | import java.util.Collection; |
18 | import java.util.HashSet; |
19 | import java.util.Set; |
20 | |
21 | import javax.annotation.Nullable; |
22 | |
23 | /** |
24 | * Class to manage the preferences used by the invalidation client. |
25 | * <p> |
26 | * This class provides methods to read and write the preferences used by the invalidation client. |
27 | * <p> |
28 | * To read a preference, call the appropriate {@code get...} method. |
29 | * <p> |
30 | * To write a preference, first call {@link #edit} to obtain a {@link EditContext}. Then, make |
31 | * one or more calls to a {@code set...} method, providing the same edit context to each call. |
32 | * Finally, call {@link #commit(EditContext)} to save the changes to stable storage. |
33 | * |
34 | * @author dsmyers@google.com (Daniel Myers) |
35 | */ |
36 | public class InvalidationPreferences { |
37 | /** |
38 | * Wrapper around a {@link android.content.SharedPreferences.Editor} for the preferences. |
39 | * Used to avoid exposing raw preference objects to users of this class. |
40 | */ |
41 | public class EditContext { |
42 | private final SharedPreferences.Editor editor; |
43 | |
44 | EditContext() { |
45 | this.editor = PreferenceManager.getDefaultSharedPreferences(mContext).edit(); |
46 | } |
47 | } |
48 | |
49 | @VisibleForTesting |
50 | public static class PrefKeys { |
51 | /** |
52 | * Shared preference key to store the invalidation types that we want to register |
53 | * for. |
54 | */ |
55 | @VisibleForTesting |
56 | public static final String SYNC_TANGO_TYPES = "sync_tango_types"; |
57 | |
58 | /** Shared preference key to store the name of the account in use. */ |
59 | @VisibleForTesting |
60 | public static final String SYNC_ACCT_NAME = "sync_acct_name"; |
61 | |
62 | /** Shared preference key to store the type of account in use. */ |
63 | static final String SYNC_ACCT_TYPE = "sync_acct_type"; |
64 | |
65 | /** Shared preference key to store internal notification client library state. */ |
66 | static final String SYNC_TANGO_INTERNAL_STATE = "sync_tango_internal_state"; |
67 | } |
68 | |
69 | private static final String TAG = "InvalidationPreferences"; |
70 | |
71 | private final Context mContext; |
72 | |
73 | public InvalidationPreferences(Context context) { |
74 | this.mContext = Preconditions.checkNotNull(context.getApplicationContext()); |
75 | } |
76 | |
77 | /** Returns a new {@link EditContext} to modify the preferences managed by this class. */ |
78 | public EditContext edit() { |
79 | return new EditContext(); |
80 | } |
81 | |
82 | /** |
83 | * Applies the changes accumulated in {@code editContext}. Returns whether they were |
84 | * successfully written. |
85 | * <p> |
86 | * NOTE: this method performs blocking I/O and must not be called from the UI thread. |
87 | */ |
88 | public boolean commit(EditContext editContext) { |
89 | if (!editContext.editor.commit()) { |
90 | Log.w(TAG, "Failed to commit invalidation preferences"); |
91 | return false; |
92 | } |
93 | return true; |
94 | } |
95 | |
96 | /** Returns the saved sync types, or {@code null} if none exist. */ |
97 | @Nullable public Set<String> getSavedSyncedTypes() { |
98 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext); |
99 | return preferences.getStringSet(PrefKeys.SYNC_TANGO_TYPES, null); |
100 | } |
101 | |
102 | /** Sets the saved sync types to {@code syncTypes} in {@code editContext}. */ |
103 | public void setSyncTypes(EditContext editContext, Collection<String> syncTypes) { |
104 | Preconditions.checkNotNull(syncTypes); |
105 | Set<String> selectedTypesSet = new HashSet<String>(syncTypes); |
106 | editContext.editor.putStringSet(PrefKeys.SYNC_TANGO_TYPES, selectedTypesSet); |
107 | } |
108 | |
109 | /** Returns the saved account, or {@code null} if none exists. */ |
110 | @Nullable public Account getSavedSyncedAccount() { |
111 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext); |
112 | String accountName = preferences.getString(PrefKeys.SYNC_ACCT_NAME, null); |
113 | String accountType = preferences.getString(PrefKeys.SYNC_ACCT_TYPE, null); |
114 | if (accountName == null || accountType == null) { |
115 | return null; |
116 | } |
117 | return new Account(accountName, accountType); |
118 | } |
119 | |
120 | /** Sets the saved account to {@code account} in {@code editContext}. */ |
121 | public void setAccount(EditContext editContext, Account account) { |
122 | editContext.editor.putString(PrefKeys.SYNC_ACCT_NAME, account.name); |
123 | editContext.editor.putString(PrefKeys.SYNC_ACCT_TYPE, account.type); |
124 | } |
125 | |
126 | /** Returns the notification client internal state. */ |
127 | @Nullable public byte[] getInternalNotificationClientState() { |
128 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(mContext); |
129 | String base64State = preferences.getString(PrefKeys.SYNC_TANGO_INTERNAL_STATE, null); |
130 | if (base64State == null) { |
131 | return null; |
132 | } |
133 | return Base64.decode(base64State, Base64.DEFAULT); |
134 | } |
135 | |
136 | /** Sets the notification client internal state to {@code state}. */ |
137 | public void setInternalNotificationClientState(EditContext editContext, byte[] state) { |
138 | editContext.editor.putString(PrefKeys.SYNC_TANGO_INTERNAL_STATE, |
139 | Base64.encodeToString(state, Base64.DEFAULT)); |
140 | } |
141 | } |