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