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.tv.channelsprograms.util; 17 18 import android.content.Context; 19 import android.content.SharedPreferences; 20 import android.util.Log; 21 22 import com.example.android.tv.channelsprograms.model.Movie; 23 import com.example.android.tv.channelsprograms.model.Subscription; 24 import com.google.gson.Gson; 25 import com.google.gson.JsonSyntaxException; 26 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 * Helper class to store {@link Subscription}s and {@link Movie}s in {@link SharedPreferences}. 36 * 37 * <p>SharedPreferencesHelper provides static methods to set and get these objects. 38 * 39 * <p>The methods of this class should not be called on the UI thread. Marshalling an object into 40 * JSON can be expensive for large objects. 41 */ 42 public final class SharedPreferencesHelper { 43 44 private static final String TAG = "SharedPreferencesHelper"; 45 46 private static final String PREFS_NAME = "com.example.android.tv.recommendations"; 47 private static final String PREFS_SUBSCRIPTIONS_KEY = 48 "com.example.android.tv.recommendations.prefs.SUBSCRIPTIONS"; 49 private static final String PREFS_SUBSCRIBED_MOVIES_PREFIX = 50 "com.example.android.tv.recommendations.prefs.SUBSCRIBED_MOVIES_"; 51 52 private static final Gson mGson = new Gson(); 53 54 /** 55 * Reads the {@link List <Subscription>} from {@link SharedPreferences}. 56 * 57 * @param context used for getting an instance of shared preferences. 58 * @return a list of subscriptions or an empty list if none exist. 59 */ readSubscriptions(Context context)60 public static List<Subscription> readSubscriptions(Context context) { 61 return getList(context, Subscription.class, PREFS_SUBSCRIPTIONS_KEY); 62 } 63 64 /** 65 * Overrides the subscriptions stored in {@link SharedPreferences}. 66 * 67 * @param context used for getting an instance of shared preferences. 68 * @param subscriptions to be stored in shared preferences. 69 */ storeSubscriptions(Context context, List<Subscription> subscriptions)70 public static void storeSubscriptions(Context context, List<Subscription> subscriptions) { 71 setList(context, subscriptions, PREFS_SUBSCRIPTIONS_KEY); 72 } 73 74 /** 75 * Reads the {@link List <Movie>} from {@link SharedPreferences} for a given channel. 76 * 77 * @param context used for getting an instance of shared preferences. 78 * @param channelId of the channel that the movies are associated with. 79 * @return a list of movies or an empty list if none exist. 80 */ readMovies(Context context, long channelId)81 public static List<Movie> readMovies(Context context, long channelId) { 82 return getList(context, Movie.class, PREFS_SUBSCRIBED_MOVIES_PREFIX + channelId); 83 } 84 85 /** 86 * Overrides the movies stored in {@link SharedPreferences} for the associated channel id. 87 * 88 * @param context used for getting an instance of shared preferences. 89 * @param channelId of the channel that the movies are associated with. 90 * @param movies to be stored. 91 */ storeMovies(Context context, long channelId, List<Movie> movies)92 public static void storeMovies(Context context, long channelId, List<Movie> movies) { 93 setList(context, movies, PREFS_SUBSCRIBED_MOVIES_PREFIX + channelId); 94 } 95 96 /** 97 * Retrieves a set of Strings from {@link SharedPreferences} and returns as a List. 98 * 99 * @param context used for getting an instance of shared preferences. 100 * @param clazz the class that the strings will be unmarshalled into. 101 * @param key the key in shared preferences to access the string set. 102 * @param <T> the type of object that will be in the returned list, should be the same as the 103 * clazz that was supplied. 104 * @return a list of <T> objects that were stored in shared preferences or an empty list if no 105 * objects exists. 106 */ getList(Context context, Class<T> clazz, String key)107 private static <T> List<T> getList(Context context, Class<T> clazz, String key) { 108 SharedPreferences sharedPreferences = 109 context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); 110 Set<String> stringSet = sharedPreferences.getStringSet(key, new HashSet<String>()); 111 if (stringSet.isEmpty()) { 112 // Favoring mutability of the list over Collections.emptyList(). 113 return new ArrayList<>(); 114 } 115 List<T> list = new ArrayList<>(stringSet.size()); 116 try { 117 for (String contactString : stringSet) { 118 list.add(mGson.fromJson(contactString, clazz)); 119 } 120 } catch (JsonSyntaxException e) { 121 Log.e(TAG, "Could not parse json.", e); 122 return Collections.emptyList(); 123 } 124 return list; 125 } 126 127 /** 128 * Saves a list of Strings into {@link SharedPreferences}. 129 * 130 * @param context used for getting an instance of shared preferences. 131 * @param list of <T> object that need to be persisted. 132 * @param key the key in shared preferences which the string set will be stored. 133 * @param <T> type the of object we will be marshalling and persisting. 134 */ setList(Context context, List<T> list, String key)135 private static <T> void setList(Context context, List<T> list, String key) { 136 SharedPreferences sharedPreferences = 137 context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); 138 SharedPreferences.Editor editor = sharedPreferences.edit(); 139 140 Set<String> strings = new LinkedHashSet<>(list.size()); 141 for (T item : list) { 142 strings.add(mGson.toJson(item)); 143 } 144 editor.putStringSet(key, strings); 145 editor.apply(); 146 } 147 } 148