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
17package com.android.deskclock.timer;
18
19import android.content.Context;
20import android.content.SharedPreferences;
21import android.os.Parcel;
22import android.os.Parcelable;
23import android.preference.PreferenceManager;
24import android.util.Log;
25
26import com.android.deskclock.R;
27import com.android.deskclock.Utils;
28
29import java.util.ArrayList;
30import java.util.Collections;
31import java.util.Comparator;
32import java.util.HashSet;
33import java.util.Iterator;
34import java.util.Set;
35
36public 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
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
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
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
150    public int describeContents() {
151        return 0;
152    }
153
154    @Override
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
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
175    private TimerObj() {
176        this(0 /* timerLength */, 0 /* timerId */);
177    }
178
179    public TimerObj(long timerLength, int timerId) {
180      init(timerLength, timerId);
181    }
182
183    public TimerObj(long timerLength, Context context) {
184        init(timerLength, getNextTimerId(context));
185    }
186
187    public TimerObj(long length, String label, Context context) {
188        this(length, context);
189        mLabel = label != null ? label : "";
190    }
191
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
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
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
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
226    public boolean isTicking() {
227        return mState == STATE_RUNNING || mState == STATE_TIMESUP;
228    }
229
230    public boolean isInUse() {
231        return mState == STATE_RUNNING || mState == STATE_STOPPED;
232    }
233
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
241    public boolean getDeleteAfterUse() {
242        return mDeleteAfterUse;
243    }
244
245    public long getTimesupTime() {
246        return mStartTime + mOriginalLength;
247    }
248
249
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
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
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
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
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