Home | History | Annotate | Download | only in timer
      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 
     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 
    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 
    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
    145     public int describeContents() {
    146         return 0;
    147     }
    148 
    149     @Override
    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 
    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 
    172     private TimerObj() {
    173         this(0 /* timerLength */, 0 /* timerId */);
    174     }
    175 
    176     public TimerObj(long timerLength, int timerId) {
    177       init(timerLength, timerId);
    178     }
    179 
    180     public TimerObj(long timerLength, Context context) {
    181         init(timerLength, getNextTimerId(context));
    182     }
    183 
    184     public TimerObj(long length, String label, Context context) {
    185         this(length, context);
    186         mLabel = label != null ? label : "";
    187     }
    188 
    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 
    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 
    209     public static boolean isTimerStateSharedPrefKey(String prefKey) {
    210         return prefKey.startsWith(PREF_STATE);
    211     }
    212 
    213     public static int getTimerIdFromTimerStateKey(String timerStatePrefKey) {
    214         final String timerId = timerStatePrefKey.substring(PREF_STATE.length());
    215         return Integer.parseInt(timerId);
    216     }
    217 
    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 
    226     public void setState(int state) {
    227         mPriorState = mState;
    228         mState = state;
    229     }
    230 
    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 
    237     public boolean isTicking() {
    238         return mState == STATE_RUNNING || mState == STATE_TIMESUP;
    239     }
    240 
    241     public boolean isInUse() {
    242         return mState == STATE_RUNNING || mState == STATE_STOPPED;
    243     }
    244 
    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 
    252     public boolean getDeleteAfterUse() {
    253         return mDeleteAfterUse;
    254     }
    255 
    256     public long getTimesupTime() {
    257         return mStartTime + mOriginalLength;
    258     }
    259 
    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 
    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 
    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 
    292     public static void putTimersInSharedPrefs(SharedPreferences prefs, List<TimerObj> timers) {
    293         for (TimerObj timer : timers) {
    294             timer.writeToSharedPref(prefs);
    295         }
    296     }
    297 
    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 
    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