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
17package com.android.deskclock.data;
18
19import android.content.Context;
20import android.content.SharedPreferences;
21import android.preference.PreferenceManager;
22
23import com.android.deskclock.Utils;
24import com.android.deskclock.data.Timer.State;
25
26import java.util.ArrayList;
27import java.util.Collections;
28import java.util.HashSet;
29import java.util.List;
30import java.util.Set;
31
32import 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 */
38final 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
70    private TimerDAO() {}
71
72    /**
73     * @return the timers from permanent storage
74     */
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     */
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     */
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     */
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
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
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