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.Stopwatch.State;
25 
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.List;
29 
30 import static com.android.deskclock.data.Stopwatch.State.RESET;
31 
32 /**
33  * This class encapsulates the transfer of data between {@link Stopwatch} and {@link Lap} domain
34  * objects and their permanent storage in {@link SharedPreferences}.
35  */
36 final class StopwatchDAO {
37 
38     // Key to a preference that stores the state of the stopwatch.
39     private static final String STATE = "sw_state";
40 
41     // Key to a preference that stores the last start time of the stopwatch.
42     private static final String LAST_START_TIME = "sw_start_time";
43 
44     // Key to a preference that stores the accumulated elapsed time of the stopwatch.
45     private static final String ACCUMULATED_TIME = "sw_accum_time";
46 
47     // Key to a preference that stores the number of recorded laps.
48     private static final String LAP_COUNT = "sw_lap_num";
49 
50     // Prefix for a key to a preference that stores accumulated time at the end of a particular lap.
51     private static final String LAP_ACCUMULATED_TIME = "sw_lap_time_";
52 
53     // Lazily instantiated and cached for the life of the application.
54     private static SharedPreferences sPrefs;
55 
StopwatchDAO()56     private StopwatchDAO() {}
57 
58     /**
59      * @return the stopwatch from permanent storage or a reset stopwatch if none exists
60      */
getStopwatch(Context context)61     public static Stopwatch getStopwatch(Context context) {
62         final SharedPreferences prefs = getSharedPreferences(context);
63         final int stateIndex = prefs.getInt(STATE, RESET.ordinal());
64         final State state = State.values()[stateIndex];
65         final long lastStartTime = prefs.getLong(LAST_START_TIME, Long.MIN_VALUE);
66         final long accumulatedTime = prefs.getLong(ACCUMULATED_TIME, 0);
67         return new Stopwatch(state, lastStartTime, accumulatedTime);
68     }
69 
70     /**
71      * @param stopwatch the last state of the stopwatch
72      */
setStopwatch(Context context, Stopwatch stopwatch)73     public static void setStopwatch(Context context, Stopwatch stopwatch) {
74         final SharedPreferences prefs = getSharedPreferences(context);
75         final SharedPreferences.Editor editor = prefs.edit();
76 
77         if (stopwatch.isReset()) {
78             editor.remove(STATE)
79                     .remove(LAST_START_TIME)
80                     .remove(ACCUMULATED_TIME);
81         } else {
82             editor.putInt(STATE, stopwatch.getState().ordinal())
83                     .putLong(LAST_START_TIME, stopwatch.getLastStartTime())
84                     .putLong(ACCUMULATED_TIME, stopwatch.getAccumulatedTime());
85         }
86 
87         editor.apply();
88     }
89 
90     /**
91      * @return a list of recorded laps for the stopwatch
92      */
getLaps(Context context)93     public static List<Lap> getLaps(Context context) {
94         final SharedPreferences prefs = getSharedPreferences(context);
95 
96         // Prepare the container to be filled with laps.
97         final int lapCount = prefs.getInt(LAP_COUNT, 0);
98         final List<Lap> laps = new ArrayList<>(lapCount);
99 
100         long prevAccumulatedTime = 0;
101 
102         // Lap numbers are 1-based and so the are corresponding shared preference keys.
103         for (int lapNumber = 1; lapNumber <= lapCount; lapNumber++) {
104             // Look up the accumulated time for the lap.
105             final String lapAccumulatedTimeKey = LAP_ACCUMULATED_TIME + lapNumber;
106             final long accumulatedTime = prefs.getLong(lapAccumulatedTimeKey, 0);
107 
108             // Lap time is the delta between accumulated time of this lap and prior lap.
109             final long lapTime = accumulatedTime - prevAccumulatedTime;
110 
111             // Create the lap instance from the data.
112             laps.add(new Lap(lapNumber, lapTime, accumulatedTime));
113 
114             // Update the accumulated time of the previous lap.
115             prevAccumulatedTime = accumulatedTime;
116         }
117 
118         // Laps are stored in the order they were recorded; display order is the reverse.
119         Collections.reverse(laps);
120 
121         return laps;
122     }
123 
124     /**
125      * @param newLapCount the number of laps including the new lap
126      * @param accumulatedTime the amount of time accumulate by the stopwatch at the end of the lap
127      */
addLap(Context context, int newLapCount, long accumulatedTime)128     public static void addLap(Context context, int newLapCount, long accumulatedTime) {
129         getSharedPreferences(context).edit()
130                 .putInt(LAP_COUNT, newLapCount)
131                 .putLong(LAP_ACCUMULATED_TIME + newLapCount, accumulatedTime)
132                 .apply();
133     }
134 
135     /**
136      * Remove the recorded laps for the stopwatch
137      */
clearLaps(Context context)138     public static void clearLaps(Context context) {
139         final SharedPreferences prefs = getSharedPreferences(context);
140         final SharedPreferences.Editor editor = prefs.edit();
141 
142         final int lapCount = prefs.getInt(LAP_COUNT, 0);
143         for (int lapNumber = 1; lapNumber <= lapCount; lapNumber++) {
144             editor.remove(LAP_ACCUMULATED_TIME + lapNumber);
145         }
146         editor.remove(LAP_COUNT);
147 
148         editor.apply();
149     }
150 
getSharedPreferences(Context context)151     private static SharedPreferences getSharedPreferences(Context context) {
152         if (sPrefs == null) {
153             sPrefs = Utils.getDefaultSharedPreferences(context.getApplicationContext());
154         }
155 
156         return sPrefs;
157     }
158 }
159