1 /*
2  * Copyright (C) 2020 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 /**
22  * This class encapsulates the transfer of data between [Timer] domain objects and their
23  * permanent storage in [SharedPreferences].
24  */
25 internal object TimerDAO {
26     /** Key to a preference that stores the set of timer ids.  */
27     private const val TIMER_IDS = "timers_list"
28 
29     /** Key to a preference that stores the id to assign to the next timer.  */
30     private const val NEXT_TIMER_ID = "next_timer_id"
31 
32     /** Prefix for a key to a preference that stores the state of the timer.  */
33     private const val STATE = "timer_state_"
34 
35     /** Prefix for a key to a preference that stores the original timer length at creation.  */
36     private const val LENGTH = "timer_setup_timet_"
37 
38     /** Prefix for a key to a preference that stores the total timer length with additions.  */
39     private const val TOTAL_LENGTH = "timer_original_timet_"
40 
41     /** Prefix for a key to a preference that stores the last start time of the timer.  */
42     private const val LAST_START_TIME = "timer_start_time_"
43 
44     /** Prefix for a key to a preference that stores the epoch time when the timer last started.  */
45     private const val LAST_WALL_CLOCK_TIME = "timer_wall_clock_time_"
46 
47     /** Prefix for a key to a preference that stores the remaining time before expiry.  */
48     private const val REMAINING_TIME = "timer_time_left_"
49 
50     /** Prefix for a key to a preference that stores the label of the timer.  */
51     private const val LABEL = "timer_label_"
52 
53     /** Prefix for a key to a preference that signals the timer should be deleted on first reset. */
54     private const val DELETE_AFTER_USE = "delete_after_use_"
55 
56     /**
57      * @return the timers from permanent storage
58      */
59     @JvmStatic
getTimersnull60     fun getTimers(prefs: SharedPreferences): MutableList<Timer> {
61         // Read the set of timer ids.
62         val timerIds: Set<String> = prefs.getStringSet(TIMER_IDS, emptySet<String>())!!
63         val timers: MutableList<Timer> = ArrayList(timerIds.size)
64 
65         // Build a timer using the data associated with each timer id.
66         for (timerId in timerIds) {
67             val id = timerId.toInt()
68             val stateValue: Int = prefs.getInt(STATE + id, Timer.State.RESET.value)
69             val state: Timer.State? = Timer.State.fromValue(stateValue)
70 
71             // Timer state may be null when migrating timers from prior releases which defined a
72             // "deleted" state. Such a state is no longer required.
73             state?.let {
74                 val length: Long = prefs.getLong(LENGTH + id, Long.MIN_VALUE)
75                 val totalLength: Long = prefs.getLong(TOTAL_LENGTH + id, Long.MIN_VALUE)
76                 val lastStartTime: Long = prefs.getLong(LAST_START_TIME + id, Timer.UNUSED)
77                 val lastWallClockTime: Long = prefs.getLong(LAST_WALL_CLOCK_TIME + id, Timer.UNUSED)
78                 val remainingTime: Long = prefs.getLong(REMAINING_TIME + id, totalLength)
79                 val label: String? = prefs.getString(LABEL + id, null)
80                 val deleteAfterUse: Boolean = prefs.getBoolean(DELETE_AFTER_USE + id, false)
81                 timers.add(Timer(id, it, length, totalLength, lastStartTime,
82                         lastWallClockTime, remainingTime, label, deleteAfterUse))
83             }
84         }
85 
86         return timers
87     }
88 
89     /**
90      * @param timer the timer to be added
91      */
92     @JvmStatic
addTimernull93     fun addTimer(prefs: SharedPreferences, timer: Timer): Timer {
94         val editor: SharedPreferences.Editor = prefs.edit()
95 
96         // Fetch the next timer id.
97         val id: Int = prefs.getInt(NEXT_TIMER_ID, 0)
98         editor.putInt(NEXT_TIMER_ID, id + 1)
99 
100         // Add the new timer id to the set of all timer ids.
101         val timerIds: MutableSet<String> = HashSet(getTimerIds(prefs))
102         timerIds.add(id.toString())
103         editor.putStringSet(TIMER_IDS, timerIds)
104 
105         // Record the fields of the timer.
106         editor.putInt(STATE + id, timer.state.value)
107         editor.putLong(LENGTH + id, timer.length)
108         editor.putLong(TOTAL_LENGTH + id, timer.totalLength)
109         editor.putLong(LAST_START_TIME + id, timer.lastStartTime)
110         editor.putLong(LAST_WALL_CLOCK_TIME + id, timer.lastWallClockTime)
111         editor.putLong(REMAINING_TIME + id, timer.remainingTime)
112         editor.putString(LABEL + id, timer.label)
113         editor.putBoolean(DELETE_AFTER_USE + id, timer.deleteAfterUse)
114 
115         editor.apply()
116 
117         // Return a new timer with the generated timer id present.
118         return Timer(id, timer.state, timer.length, timer.totalLength,
119                 timer.lastStartTime, timer.lastWallClockTime, timer.remainingTime,
120                 timer.label, timer.deleteAfterUse)
121     }
122 
123     /**
124      * @param timer the timer to be updated
125      */
126     @JvmStatic
updateTimernull127     fun updateTimer(prefs: SharedPreferences, timer: Timer) {
128         val editor: SharedPreferences.Editor = prefs.edit()
129 
130         // Record the fields of the timer.
131         val id = timer.id
132         editor.putInt(STATE + id, timer.state.value)
133         editor.putLong(LENGTH + id, timer.length)
134         editor.putLong(TOTAL_LENGTH + id, timer.totalLength)
135         editor.putLong(LAST_START_TIME + id, timer.lastStartTime)
136         editor.putLong(LAST_WALL_CLOCK_TIME + id, timer.lastWallClockTime)
137         editor.putLong(REMAINING_TIME + id, timer.remainingTime)
138         editor.putString(LABEL + id, timer.label)
139         editor.putBoolean(DELETE_AFTER_USE + id, timer.deleteAfterUse)
140 
141         editor.apply()
142     }
143 
144     /**
145      * @param timer the timer to be removed
146      */
147     @JvmStatic
removeTimernull148     fun removeTimer(prefs: SharedPreferences, timer: Timer) {
149         val editor: SharedPreferences.Editor = prefs.edit()
150         val id = timer.id
151 
152         // Remove the timer id from the set of all timer ids.
153         val timerIds: MutableSet<String> = HashSet(getTimerIds(prefs))
154         timerIds.remove(id.toString())
155         if (timerIds.isEmpty()) {
156             editor.remove(TIMER_IDS)
157             editor.remove(NEXT_TIMER_ID)
158         } else {
159             editor.putStringSet(TIMER_IDS, timerIds)
160         }
161 
162         // Record the fields of the timer.
163         editor.remove(STATE + id)
164         editor.remove(LENGTH + id)
165         editor.remove(TOTAL_LENGTH + id)
166         editor.remove(LAST_START_TIME + id)
167         editor.remove(LAST_WALL_CLOCK_TIME + id)
168         editor.remove(REMAINING_TIME + id)
169         editor.remove(LABEL + id)
170         editor.remove(DELETE_AFTER_USE + id)
171 
172         editor.apply()
173     }
174 
getTimerIdsnull175     private fun getTimerIds(prefs: SharedPreferences): Set<String> {
176         return prefs.getStringSet(TIMER_IDS, emptySet<String>())!!
177     }
178 }