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 [Stopwatch] and [Lap] domain 23 * objects and their permanent storage in [SharedPreferences]. 24 */ 25 internal object StopwatchDAO { 26 /** Key to a preference that stores the state of the stopwatch. */ 27 private const val STATE = "sw_state" 28 29 /** Key to a preference that stores the last start time of the stopwatch. */ 30 private const val LAST_START_TIME = "sw_start_time" 31 32 /** Key to a preference that stores the epoch time when the stopwatch last started. */ 33 private const val LAST_WALL_CLOCK_TIME = "sw_wall_clock_time" 34 35 /** Key to a preference that stores the accumulated elapsed time of the stopwatch. */ 36 private const val ACCUMULATED_TIME = "sw_accum_time" 37 38 /** Prefix for a key to a preference that stores the number of recorded laps. */ 39 private const val LAP_COUNT = "sw_lap_num" 40 41 /** Prefix for a key to a preference that stores accumulated time at the end of a lap. */ 42 private const val LAP_ACCUMULATED_TIME = "sw_lap_time_" 43 44 /** 45 * @return the stopwatch from permanent storage or a reset stopwatch if none exists 46 */ getStopwatchnull47 fun getStopwatch(prefs: SharedPreferences): Stopwatch { 48 val stateIndex: Int = prefs.getInt(STATE, Stopwatch.State.RESET.ordinal) 49 val state = Stopwatch.State.values()[stateIndex] 50 val lastStartTime: Long = prefs.getLong(LAST_START_TIME, Stopwatch.UNUSED) 51 val lastWallClockTime: Long = prefs.getLong(LAST_WALL_CLOCK_TIME, Stopwatch.UNUSED) 52 val accumulatedTime: Long = prefs.getLong(ACCUMULATED_TIME, 0) 53 var s = Stopwatch(state, lastStartTime, lastWallClockTime, accumulatedTime) 54 55 // If the stopwatch reports an illegal (negative) amount of time, remove the bad data. 56 if (s.totalTime < 0) { 57 s = s.reset() 58 setStopwatch(prefs, s) 59 } 60 return s 61 } 62 63 /** 64 * @param stopwatch the last state of the stopwatch 65 */ setStopwatchnull66 fun setStopwatch(prefs: SharedPreferences, stopwatch: Stopwatch) { 67 val editor: SharedPreferences.Editor = prefs.edit() 68 69 if (stopwatch.isReset) { 70 editor.remove(STATE) 71 .remove(LAST_START_TIME) 72 .remove(LAST_WALL_CLOCK_TIME) 73 .remove(ACCUMULATED_TIME) 74 } else { 75 editor.putInt(STATE, stopwatch.state.ordinal) 76 .putLong(LAST_START_TIME, stopwatch.lastStartTime) 77 .putLong(LAST_WALL_CLOCK_TIME, stopwatch.lastWallClockTime) 78 .putLong(ACCUMULATED_TIME, stopwatch.accumulatedTime) 79 } 80 81 editor.apply() 82 } 83 84 /** 85 * @return a list of recorded laps for the stopwatch 86 */ getLapsnull87 fun getLaps(prefs: SharedPreferences): MutableList<Lap> { 88 // Prepare the container to be filled with laps. 89 val lapCount: Int = prefs.getInt(LAP_COUNT, 0) 90 val laps: MutableList<Lap> = mutableListOf() 91 92 var prevAccumulatedTime: Long = 0 93 94 // Lap numbers are 1-based and so the are corresponding shared preference keys. 95 for (lapNumber in 1..lapCount) { 96 // Look up the accumulated time for the lap. 97 val lapAccumulatedTimeKey = LAP_ACCUMULATED_TIME + lapNumber 98 val accumulatedTime: Long = prefs.getLong(lapAccumulatedTimeKey, 0) 99 100 // Lap time is the delta between accumulated time of this lap and prior lap. 101 val lapTime = accumulatedTime - prevAccumulatedTime 102 103 // Create the lap instance from the data. 104 laps.add(Lap(lapNumber, lapTime, accumulatedTime)) 105 106 // Update the accumulated time of the previous lap. 107 prevAccumulatedTime = accumulatedTime 108 } 109 110 // Laps are stored in the order they were recorded; display order is the reverse. 111 laps.reverse() 112 113 return laps 114 } 115 116 /** 117 * @param newLapCount the number of laps including the new lap 118 * @param accumulatedTime the amount of time accumulate by the stopwatch at the end of the lap 119 */ addLapnull120 fun addLap(prefs: SharedPreferences, newLapCount: Int, accumulatedTime: Long) { 121 prefs.edit() 122 .putInt(LAP_COUNT, newLapCount) 123 .putLong(LAP_ACCUMULATED_TIME + newLapCount, accumulatedTime) 124 .apply() 125 } 126 127 /** 128 * Remove the recorded laps for the stopwatch 129 */ clearLapsnull130 fun clearLaps(prefs: SharedPreferences) { 131 val editor: SharedPreferences.Editor = prefs.edit() 132 133 val lapCount: Int = prefs.getInt(LAP_COUNT, 0) 134 for (lapNumber in 1..lapCount) { 135 editor.remove(LAP_ACCUMULATED_TIME + lapNumber) 136 } 137 editor.remove(LAP_COUNT) 138 139 editor.apply() 140 } 141 }