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