1 /*
2  * Copyright (c) 2017 Google Inc.
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.example.android.wearable.wear.messaging.util;
17 
18 import android.content.Context;
19 import android.content.SharedPreferences;
20 import android.util.Log;
21 import com.example.android.wearable.wear.messaging.model.Chat;
22 import com.example.android.wearable.wear.messaging.model.Message;
23 import com.example.android.wearable.wear.messaging.model.Profile;
24 import com.google.gson.Gson;
25 import com.google.gson.JsonSyntaxException;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.HashSet;
30 import java.util.LinkedHashSet;
31 import java.util.List;
32 import java.util.Set;
33 
34 /**
35  * SharedPreferencesHelper provides static methods to set, get, delete these objects.
36  *
37  * <p>The user's profile details and chat details are persisted in SharedPreferences to access
38  * across the app.
39  */
40 public class SharedPreferencesHelper {
41 
42     private static final String TAG = "SharedPreferencesHelper";
43 
44     private static Gson gson = new Gson();
45 
46     /**
47      * Returns logged in user or null if no user is logged in.
48      *
49      * @param context shared preferences context
50      * @return user profile
51      */
readUserFromJsonPref(Context context)52     public static Profile readUserFromJsonPref(Context context) {
53         SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.PREFS_NAME, 0);
54         String profileString = sharedPreferences.getString(Constants.PREFS_USER_KEY, null);
55         if (profileString == null) {
56             return null;
57         }
58         try {
59             return gson.fromJson(profileString, Profile.class);
60         } catch (JsonSyntaxException e) {
61             Log.e(TAG, "Could not parse user from shard preferences.", e);
62             return null;
63         }
64     }
65 
66     /**
67      * Writes a {@link Profile} to json and stores it in preferences.
68      *
69      * @param context used to access {@link SharedPreferences}
70      * @param user to be stored in preferences
71      */
writeUserToJsonPref(Context context, Profile user)72     public static void writeUserToJsonPref(Context context, Profile user) {
73         SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.PREFS_NAME, 0);
74         SharedPreferences.Editor editor = sharedPreferences.edit();
75         editor.putString(Constants.PREFS_USER_KEY, gson.toJson(user));
76         editor.apply();
77     }
78 
79     /**
80      * Reads contacts from preferences.
81      *
82      * @param context used to access {@link SharedPreferences}
83      * @return contacts from preferences
84      */
readContactsFromJsonPref(Context context)85     public static List<Profile> readContactsFromJsonPref(Context context) {
86         try {
87             return getList(context, Profile.class, Constants.PREFS_CONTACTS_KEY);
88         } catch (JsonSyntaxException e) {
89             String logMessage =
90                     "Could not read/unmarshall the list of contacts from shared preferences.";
91             Log.e(TAG, logMessage, e);
92             return Collections.emptyList();
93         }
94     }
95 
96     /**
97      * Writes a {@link List<Profile>} to json and stores it in preferences.
98      *
99      * @param context used to access {@link SharedPreferences}
100      * @param contacts to be stored in preferences
101      */
writeContactsToJsonPref(Context context, List<Profile> contacts)102     public static void writeContactsToJsonPref(Context context, List<Profile> contacts) {
103         setList(context, contacts, Constants.PREFS_CONTACTS_KEY);
104     }
105 
106     /**
107      * Reads chats from preferences
108      *
109      * @param context used to access {@link SharedPreferences}
110      * @return chats from preferences
111      * @throws IOException if there is an error parsing the json from preferences
112      */
readChatsFromJsonPref(Context context)113     public static List<Chat> readChatsFromJsonPref(Context context) throws IOException {
114         try {
115             return getList(context, Chat.class, Constants.PREFS_CHATS_KEY);
116         } catch (JsonSyntaxException e) {
117             Log.e(TAG, "Could not read/unmarshall the list of chats from shared preferences", e);
118             return Collections.emptyList();
119         }
120     }
121 
122     /**
123      * Writes a {@link List<Chat>} to json and stores it in preferences.
124      *
125      * @param context used to access {@link SharedPreferences}
126      * @param chats to be stores in preferences
127      */
writeChatsToJsonPref(Context context, List<Chat> chats)128     public static void writeChatsToJsonPref(Context context, List<Chat> chats) {
129         Log.d(TAG, String.format("Saving %d chat(s)", chats.size()));
130         setList(context, chats, Constants.PREFS_CHATS_KEY);
131     }
132 
133     /**
134      * Reads messages for a chat from preferences.
135      *
136      * @param context used to access {@link SharedPreferences}
137      * @param chatId for the chat the messages are from
138      * @return messages from preferences
139      */
readMessagesForChat(Context context, String chatId)140     public static List<Message> readMessagesForChat(Context context, String chatId) {
141         try {
142             return getList(context, Message.class, Constants.PREFS_MESSAGE_PREFIX + chatId);
143         } catch (JsonSyntaxException e) {
144             Log.e(TAG, "Could not read/unmarshall the list of messages from shared preferences", e);
145             return Collections.emptyList();
146         }
147     }
148 
149     /**
150      * Writes a {@link List<Message>} to json and stores it in preferences.
151      *
152      * @param context used to access {@link SharedPreferences}
153      * @param chat that the messages are from
154      * @param messages to be stored into preferences
155      */
writeMessagesForChatToJsonPref( Context context, Chat chat, List<Message> messages)156     public static void writeMessagesForChatToJsonPref(
157             Context context, Chat chat, List<Message> messages) {
158         setList(context, messages, Constants.PREFS_MESSAGE_PREFIX + chat.getId());
159     }
160 
161     /**
162      * Returns List of specified class from SharedPreferences (converts from string in
163      * SharedPreferences to class)
164      *
165      * @param context used for getting an instance of shared preferences
166      * @param clazz the class that the strings will be unmarshalled into
167      * @param key the key in shared preferences to access the string set
168      * @param <T> the type of object that will be in the returned list, should be the same as the
169      *     clazz that was supplied
170      * @return a list of <T> objects that were stored in shared preferences. Returns an empty list
171      *     if no data is available.
172      */
getList(Context context, Class<T> clazz, String key)173     private static <T> List<T> getList(Context context, Class<T> clazz, String key)
174             throws JsonSyntaxException {
175         SharedPreferences sharedPreferences =
176                 context.getSharedPreferences(Constants.PREFS_NAME, Context.MODE_PRIVATE);
177         Set<String> contactsSet = sharedPreferences.getStringSet(key, new HashSet<String>());
178         if (contactsSet.isEmpty()) {
179             // Favoring mutability of the list over Collections.emptyList().
180             return new ArrayList<>();
181         }
182         List<T> list = new ArrayList<>(contactsSet.size());
183         for (String contactString : contactsSet) {
184             list.add(gson.fromJson(contactString, clazz));
185         }
186         return list;
187     }
188 
189     /**
190      * Sets a List of specified class in SharedPreferences (converts from List of class to string
191      * for SharedPreferences)
192      *
193      * @param context used for getting an instance of shared preferences
194      * @param list of <T> object that need to be persisted
195      * @param key the key in shared preferences which the string set will be stored
196      * @param <T> type the of object we will be marshalling and persisting
197      */
setList(Context context, List<T> list, String key)198     private static <T> void setList(Context context, List<T> list, String key) {
199         SharedPreferences sharedPreferences =
200                 context.getSharedPreferences(Constants.PREFS_NAME, Context.MODE_PRIVATE);
201         SharedPreferences.Editor editor = sharedPreferences.edit();
202 
203         Set<String> strings = new LinkedHashSet<>(list.size());
204         for (T t : list) {
205             strings.add(gson.toJson(t));
206         }
207         editor.putStringSet(key, strings);
208         editor.apply();
209     }
210 }
211