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