1 /* 2 * Copyright (C) 2012 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.timer; 18 19 import android.content.Context; 20 import android.content.SharedPreferences; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.preference.PreferenceManager; 24 25 import com.android.deskclock.R; 26 import com.android.deskclock.Utils; 27 28 import java.util.ArrayList; 29 import java.util.Collections; 30 import java.util.Comparator; 31 import java.util.HashSet; 32 import java.util.List; 33 import java.util.Set; 34 35 public class TimerObj implements Parcelable { 36 37 public static final String KEY_NEXT_TIMER_ID = "next_timer_id"; 38 39 private static final String TAG = "TimerObj"; 40 // Max timer length is 9 hours + 99 minutes + 99 seconds 41 public static final long MAX_TIMER_LENGTH = (9 * 3600 + 99 * 60 + 99) * 1000; 42 public static final long MINUTE_IN_MILLIS = 60 * 1000; 43 44 public int mTimerId; // Unique id 45 public long mStartTime; // With mTimeLeft , used to calculate the correct time 46 public long mTimeLeft; // in the timer. 47 public long mOriginalLength; // length set at start of timer and by +1 min after times up 48 public long mSetupLength; // length set at start of timer 49 public TimerListItem mView; 50 public int mState; 51 public int mPriorState; 52 public String mLabel; 53 public boolean mDeleteAfterUse; 54 55 public static final int STATE_RUNNING = 1; 56 public static final int STATE_STOPPED = 2; 57 public static final int STATE_TIMESUP = 3; 58 public static final int STATE_RESTART = 4; 59 public static final int STATE_DELETED = 5; 60 61 private static final String PREF_TIMER_ID = "timer_id_"; 62 private static final String PREF_START_TIME = "timer_start_time_"; 63 private static final String PREF_TIME_LEFT = "timer_time_left_"; 64 private static final String PREF_ORIGINAL_TIME = "timer_original_timet_"; 65 private static final String PREF_SETUP_TIME = "timer_setup_timet_"; 66 private static final String PREF_STATE = "timer_state_"; 67 private static final String PREF_PRIOR_STATE = "timer_prior_state_"; 68 private static final String PREF_LABEL = "timer_label_"; 69 private static final String PREF_DELETE_AFTER_USE = "delete_after_use_"; 70 71 private static final String PREF_TIMERS_LIST = "timers_list"; 72 73 public static final Parcelable.Creator<TimerObj> CREATOR = new Parcelable.Creator<TimerObj>() { 74 @Override 75 public TimerObj createFromParcel(Parcel p) { 76 return new TimerObj(p); 77 } 78 79 @Override 80 public TimerObj[] newArray(int size) { 81 return new TimerObj[size]; 82 } 83 }; 84 writeToSharedPref(SharedPreferences prefs)85 public void writeToSharedPref(SharedPreferences prefs) { 86 final String id = Integer.toString(mTimerId); 87 88 final Set<String> timerIds = getTimerIds(prefs); 89 timerIds.add(id); 90 91 final SharedPreferences.Editor editor = prefs.edit() 92 .putInt(PREF_TIMER_ID + id, mTimerId) 93 .putLong(PREF_START_TIME + id, mStartTime) 94 .putLong(PREF_TIME_LEFT + id, mTimeLeft) 95 .putLong(PREF_ORIGINAL_TIME + id, mOriginalLength) 96 .putLong(PREF_SETUP_TIME + id, mSetupLength) 97 .putInt(PREF_STATE + id, mState) 98 .putInt(PREF_PRIOR_STATE + id, mPriorState) 99 .putStringSet(PREF_TIMERS_LIST, timerIds) 100 .putString(PREF_LABEL + id, mLabel) 101 .putBoolean(PREF_DELETE_AFTER_USE + id, mDeleteAfterUse); 102 103 editor.apply(); 104 } 105 readFromSharedPref(SharedPreferences prefs)106 public void readFromSharedPref(SharedPreferences prefs) { 107 final String id = Integer.toString(mTimerId); 108 109 mStartTime = prefs.getLong(PREF_START_TIME + id, 0); 110 mTimeLeft = prefs.getLong(PREF_TIME_LEFT + id, 0); 111 mOriginalLength = prefs.getLong(PREF_ORIGINAL_TIME + id, 0); 112 mSetupLength = prefs.getLong(PREF_SETUP_TIME + id, 0); 113 mState = prefs.getInt(PREF_STATE + id, 0); 114 mPriorState = prefs.getInt(PREF_PRIOR_STATE + id, 0); 115 mLabel = prefs.getString(PREF_LABEL + id, ""); 116 mDeleteAfterUse = prefs.getBoolean(PREF_DELETE_AFTER_USE + id, false); 117 } 118 deleteFromSharedPref(SharedPreferences prefs)119 public boolean deleteFromSharedPref(SharedPreferences prefs) { 120 final String id = Integer.toString(mTimerId); 121 122 final Set<String> timerIds = getTimerIds(prefs); 123 timerIds.remove(id); 124 125 final SharedPreferences.Editor editor = prefs.edit() 126 .remove(PREF_TIMER_ID + id) 127 .remove(PREF_START_TIME + id) 128 .remove(PREF_TIME_LEFT + id) 129 .remove(PREF_ORIGINAL_TIME + id) 130 .remove(PREF_SETUP_TIME + id) 131 .remove(PREF_STATE + id) 132 .remove(PREF_PRIOR_STATE + id) 133 .putStringSet(PREF_TIMERS_LIST, timerIds) 134 .remove(PREF_LABEL + id) 135 .remove(PREF_DELETE_AFTER_USE + id); 136 137 if (timerIds.isEmpty()) { 138 editor.remove(KEY_NEXT_TIMER_ID); 139 } 140 141 return editor.commit(); 142 } 143 144 @Override describeContents()145 public int describeContents() { 146 return 0; 147 } 148 149 @Override writeToParcel(Parcel dest, int flags)150 public void writeToParcel(Parcel dest, int flags) { 151 dest.writeInt(mTimerId); 152 dest.writeLong(mStartTime); 153 dest.writeLong(mTimeLeft); 154 dest.writeLong(mOriginalLength); 155 dest.writeLong(mSetupLength); 156 dest.writeInt(mState); 157 dest.writeInt(mPriorState); 158 dest.writeString(mLabel); 159 } 160 TimerObj(Parcel p)161 public TimerObj(Parcel p) { 162 mTimerId = p.readInt(); 163 mStartTime = p.readLong(); 164 mTimeLeft = p.readLong(); 165 mOriginalLength = p.readLong(); 166 mSetupLength = p.readLong(); 167 mState = p.readInt(); 168 mPriorState = p.readInt(); 169 mLabel = p.readString(); 170 } 171 TimerObj()172 private TimerObj() { 173 this(0 /* timerLength */, 0 /* timerId */); 174 } 175 TimerObj(long timerLength, int timerId)176 public TimerObj(long timerLength, int timerId) { 177 init(timerLength, timerId); 178 } 179 TimerObj(long timerLength, Context context)180 public TimerObj(long timerLength, Context context) { 181 init(timerLength, getNextTimerId(context)); 182 } 183 TimerObj(long length, String label, Context context)184 public TimerObj(long length, String label, Context context) { 185 this(length, context); 186 mLabel = label != null ? label : ""; 187 } 188 init(long length, int timerId)189 private void init (long length, int timerId) { 190 /* TODO: mTimerId must avoid StopwatchService.NOTIFICATION_ID, 191 * TimerReceiver.IN_USE_NOTIFICATION_ID, and alarm ID's (which seem to be 1, 2, ..) 192 */ 193 mTimerId = timerId; 194 mStartTime = Utils.getTimeNow(); 195 mTimeLeft = mOriginalLength = mSetupLength = length; 196 mLabel = ""; 197 } 198 getNextTimerId(Context context)199 private int getNextTimerId(Context context) { 200 final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 201 final int nextTimerId; 202 synchronized (TimerObj.class) { 203 nextTimerId = prefs.getInt(KEY_NEXT_TIMER_ID, 0); 204 prefs.edit().putInt(KEY_NEXT_TIMER_ID, nextTimerId + 1).apply(); 205 } 206 return nextTimerId; 207 } 208 isTimerStateSharedPrefKey(String prefKey)209 public static boolean isTimerStateSharedPrefKey(String prefKey) { 210 return prefKey.startsWith(PREF_STATE); 211 } 212 getTimerIdFromTimerStateKey(String timerStatePrefKey)213 public static int getTimerIdFromTimerStateKey(String timerStatePrefKey) { 214 final String timerId = timerStatePrefKey.substring(PREF_STATE.length()); 215 return Integer.parseInt(timerId); 216 } 217 updateTimeLeft(boolean forceUpdate)218 public long updateTimeLeft(boolean forceUpdate) { 219 if (isTicking() || forceUpdate) { 220 long millis = Utils.getTimeNow(); 221 mTimeLeft = mOriginalLength - (millis - mStartTime); 222 } 223 return mTimeLeft; 224 } 225 setState(int state)226 public void setState(int state) { 227 mPriorState = mState; 228 mState = state; 229 } 230 getLabelOrDefault(Context context)231 public String getLabelOrDefault(Context context) { 232 return (mLabel == null || mLabel.length() == 0) ? context.getString( 233 R.string.timer_notification_label) 234 : mLabel; 235 } 236 isTicking()237 public boolean isTicking() { 238 return mState == STATE_RUNNING || mState == STATE_TIMESUP; 239 } 240 isInUse()241 public boolean isInUse() { 242 return mState == STATE_RUNNING || mState == STATE_STOPPED; 243 } 244 addTime(long time)245 public void addTime(long time) { 246 mTimeLeft = mOriginalLength - (Utils.getTimeNow() - mStartTime); 247 if (mTimeLeft < MAX_TIMER_LENGTH - time) { 248 mOriginalLength += time; 249 } 250 } 251 getDeleteAfterUse()252 public boolean getDeleteAfterUse() { 253 return mDeleteAfterUse; 254 } 255 getTimesupTime()256 public long getTimesupTime() { 257 return mStartTime + mOriginalLength; 258 } 259 getTimerFromSharedPrefs(SharedPreferences prefs, int timerId)260 public static TimerObj getTimerFromSharedPrefs(SharedPreferences prefs, int timerId) { 261 final TimerObj timer = new TimerObj(); 262 timer.mTimerId = timerId; 263 timer.readFromSharedPref(prefs); 264 return timer; 265 } 266 getTimersFromSharedPrefs(SharedPreferences prefs, List<TimerObj> timers)267 public static void getTimersFromSharedPrefs(SharedPreferences prefs, List<TimerObj> timers) { 268 for (String timerIdString : getTimerIds(prefs)) { 269 final int timerId = Integer.parseInt(timerIdString); 270 timers.add(getTimerFromSharedPrefs(prefs, timerId)); 271 } 272 273 Collections.sort(timers, new Comparator<TimerObj>() { 274 @Override 275 public int compare(TimerObj timer1, TimerObj timer2) { 276 return timer1.mTimerId - timer2.mTimerId; 277 } 278 }); 279 } 280 getTimersFromSharedPrefs(SharedPreferences prefs, List<TimerObj> timers, int state)281 public static void getTimersFromSharedPrefs(SharedPreferences prefs, List<TimerObj> timers, 282 int state) { 283 for (String timerIdString : getTimerIds(prefs)) { 284 final int timerId = Integer.parseInt(timerIdString); 285 final TimerObj timer = getTimerFromSharedPrefs(prefs, timerId); 286 if (timer.mState == state) { 287 timers.add(timer); 288 } 289 } 290 } 291 putTimersInSharedPrefs(SharedPreferences prefs, List<TimerObj> timers)292 public static void putTimersInSharedPrefs(SharedPreferences prefs, List<TimerObj> timers) { 293 for (TimerObj timer : timers) { 294 timer.writeToSharedPref(prefs); 295 } 296 } 297 resetTimersInSharedPrefs(SharedPreferences prefs)298 public static void resetTimersInSharedPrefs(SharedPreferences prefs) { 299 final List<TimerObj> timers = new ArrayList<>(); 300 getTimersFromSharedPrefs(prefs, timers); 301 for (TimerObj timer : timers) { 302 timer.setState(TimerObj.STATE_RESTART); 303 timer.mTimeLeft = timer.mOriginalLength = timer.mSetupLength; 304 timer.writeToSharedPref(prefs); 305 } 306 } 307 getTimerIds(SharedPreferences prefs)308 private static Set<String> getTimerIds(SharedPreferences prefs) { 309 // return a defensive copy that is safe to mutate; see doc for getStringSet() for details 310 return new HashSet<>(prefs.getStringSet(PREF_TIMERS_LIST, Collections.<String>emptySet())); 311 } 312 } 313