1 /*
2  * Copyright (C) 2015 The Android Open Source Project
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 
17 package com.android.deskclock.data;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.preference.PreferenceManager;
22 
23 import com.android.deskclock.Utils;
24 import com.android.deskclock.data.Timer.State;
25 
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Set;
31 
32 import static com.android.deskclock.data.Timer.State.RESET;
33 
34 /**
35  * This class encapsulates the transfer of data between {@link Timer} domain objects and their
36  * permanent storage in {@link SharedPreferences}.
37  */
38 final class TimerDAO {
39 
40     // Key to a preference that stores the set of timer ids.
41     private static final String TIMER_IDS = "timers_list";
42 
43     // Key to a preference that stores the id to assign to the next timer.
44     private static final String NEXT_TIMER_ID = "next_timer_id";
45 
46     // Prefix for a key to a preference that stores the state of the timer.
47     private static final String STATE = "timer_state_";
48 
49     // Prefix for a key to a preference that stores the length of the timer when it was created.
50     private static final String LENGTH = "timer_setup_timet_";
51 
52     // Prefix for a key to a preference that stores the total length of the timer with additions.
53     private static final String TOTAL_LENGTH = "timer_original_timet_";
54 
55     // Prefix for a key to a preference that stores the last start time of the timer.
56     private static final String LAST_START_TIME = "timer_start_time_";
57 
58     // Prefix for a key to a preference that stores the remaining time before expiry.
59     private static final String REMAINING_TIME = "timer_time_left_";
60 
61     // Prefix for a key to a preference that stores the label of the timer.
62     private static final String LABEL = "timer_label_";
63 
64     // Prefix for a key to a preference that signals the timer should be deleted on first reset.
65     private static final String DELETE_AFTER_USE = "delete_after_use_";
66 
67     // Lazily instantiated and cached for the life of the application.
68     private static SharedPreferences sPrefs;
69 
TimerDAO()70     private TimerDAO() {}
71 
72     /**
73      * @return the timers from permanent storage
74      */
getTimers(Context context)75     public static List<Timer> getTimers(Context context) {
76         final SharedPreferences prefs = getSharedPreferences(context);
77 
78         // Read the set of timer ids.
79         final Set<String> timerIds = prefs.getStringSet(TIMER_IDS, Collections.<String>emptySet());
80         final List<Timer> timers = new ArrayList<>(timerIds.size());
81 
82         // Build a timer using the data associated with each timer id.
83         for (String timerId : timerIds) {
84             final int id = Integer.parseInt(timerId);
85             final int stateValue = prefs.getInt(STATE + id, RESET.getValue());
86             final State state = State.fromValue(stateValue);
87 
88             // Timer state may be null when migrating timers from prior releases which defined a
89             // "deleted" state. Such a state is no longer required.
90             if (state != null) {
91                 final long length = prefs.getLong(LENGTH + id, Long.MIN_VALUE);
92                 final long totalLength = prefs.getLong(TOTAL_LENGTH + id, Long.MIN_VALUE);
93                 final long lastStartTime = prefs.getLong(LAST_START_TIME + id, Long.MIN_VALUE);
94                 final long remainingTime = prefs.getLong(REMAINING_TIME + id, totalLength);
95                 final String label = prefs.getString(LABEL + id, null);
96                 final boolean deleteAfterUse = prefs.getBoolean(DELETE_AFTER_USE + id, false);
97                 timers.add(new Timer(id, state, length, totalLength, lastStartTime, remainingTime,
98                         label, deleteAfterUse));
99             }
100         }
101 
102         return timers;
103     }
104 
105     /**
106      * @param timer the timer to be added
107      */
addTimer(Context context, Timer timer)108     public static Timer addTimer(Context context, Timer timer) {
109         final SharedPreferences prefs = getSharedPreferences(context);
110         final SharedPreferences.Editor editor = prefs.edit();
111 
112         // Fetch the next timer id.
113         final int id = prefs.getInt(NEXT_TIMER_ID, 0);
114         editor.putInt(NEXT_TIMER_ID, id + 1);
115 
116         // Add the new timer id to the set of all timer ids.
117         final Set<String> timerIds = new HashSet<>(getTimerIds(context));
118         timerIds.add(String.valueOf(id));
119         editor.putStringSet(TIMER_IDS, timerIds);
120 
121         // Record the fields of the timer.
122         editor.putInt(STATE + id, timer.getState().getValue());
123         editor.putLong(LENGTH + id, timer.getLength());
124         editor.putLong(TOTAL_LENGTH + id, timer.getTotalLength());
125         editor.putLong(LAST_START_TIME + id, timer.getLastStartTime());
126         editor.putLong(REMAINING_TIME + id, timer.getRemainingTime());
127         editor.putString(LABEL + id, timer.getLabel());
128         editor.putBoolean(DELETE_AFTER_USE + id, timer.getDeleteAfterUse());
129 
130         editor.apply();
131 
132         // Return a new timer with the generated timer id present.
133         return new Timer(id, timer.getState(), timer.getLength(), timer.getTotalLength(),
134                 timer.getLastStartTime(), timer.getRemainingTime(), timer.getLabel(),
135                 timer.getDeleteAfterUse());
136     }
137 
138     /**
139      * @param timer the timer to be updated
140      */
updateTimer(Context context, Timer timer)141     public static void updateTimer(Context context, Timer timer) {
142         final SharedPreferences prefs = getSharedPreferences(context);
143         final SharedPreferences.Editor editor = prefs.edit();
144 
145         // Record the fields of the timer.
146         final int id = timer.getId();
147         editor.putInt(STATE + id, timer.getState().getValue());
148         editor.putLong(LENGTH + id, timer.getLength());
149         editor.putLong(TOTAL_LENGTH + id, timer.getTotalLength());
150         editor.putLong(LAST_START_TIME + id, timer.getLastStartTime());
151         editor.putLong(REMAINING_TIME + id, timer.getRemainingTime());
152         editor.putString(LABEL + id, timer.getLabel());
153         editor.putBoolean(DELETE_AFTER_USE + id, timer.getDeleteAfterUse());
154 
155         editor.apply();
156     }
157 
158     /**
159      * @param timer the timer to be removed
160      */
removeTimer(Context context, Timer timer)161     public static void removeTimer(Context context, Timer timer) {
162         final SharedPreferences prefs = getSharedPreferences(context);
163         final SharedPreferences.Editor editor = prefs.edit();
164 
165         final int id = timer.getId();
166 
167         // Remove the timer id from the set of all timer ids.
168         final Set<String> timerIds = new HashSet<>(getTimerIds(context));
169         timerIds.remove(String.valueOf(id));
170         if (timerIds.isEmpty()) {
171             editor.remove(TIMER_IDS);
172             editor.remove(NEXT_TIMER_ID);
173         } else {
174             editor.putStringSet(TIMER_IDS, timerIds);
175         }
176 
177         // Record the fields of the timer.
178         editor.remove(STATE + id);
179         editor.remove(LENGTH + id);
180         editor.remove(TOTAL_LENGTH + id);
181         editor.remove(LAST_START_TIME + id);
182         editor.remove(REMAINING_TIME + id);
183         editor.remove(LABEL + id);
184         editor.remove(DELETE_AFTER_USE + id);
185 
186         editor.apply();
187     }
188 
getTimerIds(Context context)189     private static Set<String> getTimerIds(Context context) {
190         final SharedPreferences prefs = getSharedPreferences(context);
191         return prefs.getStringSet(TIMER_IDS, Collections.<String>emptySet());
192     }
193 
getSharedPreferences(Context context)194     private static SharedPreferences getSharedPreferences(Context context) {
195         if (sPrefs == null) {
196             sPrefs = Utils.getDefaultSharedPreferences(context.getApplicationContext());
197         }
198 
199         return sPrefs;
200     }
201 }
202