package net.kismetwireless.android.smarterwifimanager; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; /** * Created by dragorn on 10/1/13. * * This has to be parcelable because we can keep un-saved changes in fragments */ public class SmarterTimeRange implements Parcelable { public static int REPEAT_SUN = (1 << Calendar.SUNDAY); public static int REPEAT_MON = (1 << Calendar.MONDAY); public static int REPEAT_TUE = (1 << Calendar.TUESDAY); public static int REPEAT_WED = (1 << Calendar.WEDNESDAY); public static int REPEAT_THU = (1 << Calendar.THURSDAY); public static int REPEAT_FRI = (1 << Calendar.FRIDAY); public static int REPEAT_SAT = (1 << Calendar.SATURDAY); private int startHour, startMinute; private int endHour, endMinute; private int days; private int oldStartHour, oldStartMinute, oldEndHour, oldEndMinute, oldDays; private boolean controlWifi, controlBluetooth; private boolean wifiOn, bluetoothOn; private boolean oldControlWifi, oldControlBluetooth, oldWifiOn, oldBluetoothOn; private boolean aggressive = false, oldAggressive; private boolean dirty = false; // Hide the UI collapse state in here private boolean collapsed = true; // Is this alarm enabled private boolean enabled = true; private long dbid = -1; // Expanded duration for simple math private class DurationSlice { long adjustedMinuteOfWeek; long durationMinutes; } private ArrayList<DurationSlice> expandedDurations = new ArrayList<DurationSlice>(); public SmarterTimeRange() { dbid = -1; } public SmarterTimeRange(int starthour, int startminute, int endhour, int endminute, int days, boolean controlwifi, boolean controlbt, boolean wifion, boolean bton, boolean enabled, boolean aggressive, long id) { oldStartHour = startHour = starthour; oldStartMinute = startMinute = startminute; oldEndHour = endHour = endhour; oldEndMinute = endMinute = endminute; this.oldDays = this.days = days; oldControlWifi = controlWifi = controlwifi; oldControlBluetooth = controlBluetooth = controlbt; oldWifiOn = wifiOn = wifion; oldBluetoothOn = bluetoothOn = bton; this.enabled = enabled; dirty = false; dbid = id; } public SmarterTimeRange(SmarterTimeRange r) { this.startHour = r.getStartHour(); this.startMinute = r.getStartMinute(); this.endHour = r.getEndHour(); this.endMinute = r.getEndMinute(); this.days = r.getDays(); this.controlWifi = r.getWifiControlled(); this.wifiOn = r.getWifiEnabled(); this.controlBluetooth = r.getBluetoothControlled(); this.bluetoothOn = r.getBluetoothEnabled(); this.enabled = r.getEnabled(); this.dbid = r.getDbId(); dirty = false; } public static long getNowInMinutes() { /* Calendar c = GregorianCalendar.getInstance(); return (c.get(Calendar.DAY_OF_WEEK) * 1440) + (c.get(Calendar.HOUR_OF_DAY) * 60) + c.get(Calendar.MINUTE); */ return System.currentTimeMillis() / 60000; } public long getDurationMinutes() { // Arbitrary day int d = 1; long weekstart = (1440 * (d - 1)) + (60 * startHour) + startMinute; long duration; int endday = d; if (getCrossesDays()) { endday += 1; } long endtime = (1440 * (endday - 1)) + (60 * endHour) + endMinute; duration = endtime - weekstart; return duration; } public boolean getCrossesDays() { if (endHour < startHour || (endHour == startHour && endMinute < startMinute)) { return true; } return false; } // Returns '0' or duration of current element public boolean isInRangeNow() { // Blow up our time ranges expandTimeDurations(); // Now since epoch converted to minute precision long now = System.currentTimeMillis() / 60000; for (DurationSlice d : expandedDurations) { if (now < d.adjustedMinuteOfWeek) continue; if (now < d.adjustedMinuteOfWeek + d.durationMinutes) return true; } return false; } public long getNextStartMillis() { expandTimeDurations(); long now = System.currentTimeMillis() / 60000; long closestmin = 0; for (DurationSlice d : expandedDurations) { if (now > d.adjustedMinuteOfWeek) continue; if (closestmin == 0 || d.adjustedMinuteOfWeek < closestmin) closestmin = d.adjustedMinuteOfWeek; } return closestmin * 60000; } public long getNextEndMillis() { expandTimeDurations(); long now = System.currentTimeMillis() / 60000; long closestmin = 0; for (DurationSlice d : expandedDurations) { long endminute = d.adjustedMinuteOfWeek + d.durationMinutes; if (now > endminute) continue; if (closestmin == 0 || endminute < closestmin) closestmin = endminute; } return closestmin * 60000; } public void expandTimeDurations() { if (expandedDurations.size() != 0 && !dirty) return; Calendar c = GregorianCalendar.getInstance(); // Midnight c.set(Calendar.HOUR_OF_DAY, 0); c.clear(Calendar.MINUTE); c.clear(Calendar.SECOND); c.clear(Calendar.MILLISECOND); // Decrement via localization while (c.get(Calendar.DAY_OF_WEEK) != c.getFirstDayOfWeek()) { c.add(Calendar.DATE, -1); } // Get the start of the week, in seconds, since the epoch long adjustment = c.getTimeInMillis() / 60000; long duration = getDurationMinutes(); expandedDurations.clear(); // No matter what our localization, numerically we go sunday-saturday and we're iterating the bitfield for (int d = Calendar.SUNDAY; d <= Calendar.SATURDAY; d++) { // For days we're active in if ((days & (1 << d)) == 0) continue; // Start time in minutes long weekstart = (1440 * (d - 1)) + (60 * startHour) + startMinute; // If we repeat on saturday and end on sunday, we need to make a record a day earlier // that carries into sunday; which is a week earlier from our current calculation point, // which is the end of the week if (d == Calendar.SATURDAY && getCrossesDays()) { DurationSlice ds = new DurationSlice(); ds.adjustedMinuteOfWeek = weekstart + adjustment - (7 * 1440); ds.durationMinutes = duration; LogAlias.d("smarter", "Occurrence at " + (new Date(ds.adjustedMinuteOfWeek * 60000)).toString() + " until " + (new Date((ds.adjustedMinuteOfWeek + ds.durationMinutes) * 60000)).toString()); expandedDurations.add(ds); } DurationSlice ds = new DurationSlice(); // ds.startMinuteOfWeek = weekstart; ds.adjustedMinuteOfWeek = weekstart + adjustment; ds.durationMinutes = (int) duration; expandedDurations.add(ds); LogAlias.d("smarter", "Occurrence at " + (new Date(ds.adjustedMinuteOfWeek * 60000)).toString() + " until " + (new Date((ds.adjustedMinuteOfWeek + ds.durationMinutes) * 60000)).toString()); } } public int getStartHour() { return startHour; } public int getEndHour() { return endHour; } public int getStartMinute() { return startMinute; } public int getEndMinute() { return endMinute; } public int getDays() { return days; } public void setDays(int repeats) { if (days != repeats) { dirty = true; expandedDurations.clear(); } oldDays = days; days = repeats; } public void setStartTime(int starthour, int startminute) { if (startHour != starthour || startMinute != startminute) { dirty = true; expandedDurations.clear(); } oldStartHour = startHour; oldStartMinute = startMinute; startHour = starthour; startMinute = startminute; } public void setEndTime(int endhour, int endminute) { if (endHour != endhour || endMinute != endminute) { dirty = true; expandedDurations.clear(); } //Log.d("smarter", "setendtime " + dirty); oldEndHour = endHour; oldEndMinute = endMinute; endHour = endhour; endMinute = endminute; } public long getDbId() { return dbid; } public void setDbId(long id) { dbid = id; } public boolean getAggressiveManagement() { return aggressive; } public void setAggressiveManagement(boolean agg) { if (aggressive != agg) { dirty = true; } oldAggressive = aggressive; aggressive = agg; } public boolean getWifiControlled() { return controlWifi; } public void setWifiControlled(boolean control) { if (controlWifi != control) { dirty = true; expandedDurations.clear(); } oldControlWifi = controlWifi; controlWifi = control; } public boolean getBluetoothControlled() { return controlBluetooth; } public void setBluetoothControlled(boolean control) { if (controlBluetooth != control) { dirty = true; expandedDurations.clear(); } oldControlBluetooth = controlBluetooth; controlBluetooth = control; } public boolean getWifiEnabled() { return wifiOn; } public void setWifiEnabled(boolean en) { if (wifiOn != en) { dirty = true; expandedDurations.clear(); } oldWifiOn = wifiOn; wifiOn = en; } public boolean getBluetoothEnabled() { return bluetoothOn; } public boolean getCollapsed() { return collapsed; } public void setCollapsed(boolean collapse) { collapsed = collapse; } public void setBluetoothEnabled(boolean en) { if (bluetoothOn != en) { dirty = true; expandedDurations.clear(); } oldBluetoothOn = bluetoothOn; bluetoothOn = en; } public boolean getEnabled() { return enabled; } public void setEnabled(boolean e) { enabled = e; } public boolean getDirty() { return dirty; } public boolean getRevertable() { if (dirty && dbid >= 0) return true; return false; } public void revertChanges() { startHour = oldStartHour; startMinute = oldStartMinute; endHour = oldEndHour; endMinute = oldEndMinute; days = oldDays; controlWifi = oldControlWifi; wifiOn = oldWifiOn; controlBluetooth = oldControlBluetooth; bluetoothOn = oldBluetoothOn; aggressive = oldAggressive; dirty = false; expandedDurations.clear(); } public void applyChanges() { oldStartHour = startHour; oldStartMinute = startMinute; oldEndHour = endHour; oldEndMinute = endMinute; oldDays = days; oldControlWifi = controlWifi; oldWifiOn = wifiOn; oldControlBluetooth = controlBluetooth; oldBluetoothOn = bluetoothOn; dirty = false; expandedDurations.clear(); } static public int getHuman12Hour(int hour) { // 12am if (hour == 0) return 12; // 1am - 12pm if (hour <= 12) return hour; // 1pm to 12am return getHuman12Hour(hour - 12); } // am = true // pm = false static public boolean getHumanAmPm(int hour) { // 12am - 11am if (hour < 12) return true; return false; } static public String getHumanDayText(Context c, int repeat) { StringBuilder sb = new StringBuilder(); if ((repeat & REPEAT_MON) != 0) { sb.append(c.getString(R.string.range_mon)); } if ((repeat & REPEAT_TUE) != 0) { if (sb.length() > 0) sb.append(", "); sb.append(c.getString(R.string.range_tue)); } if ((repeat & REPEAT_WED) != 0) { if (sb.length() > 0) sb.append(", "); sb.append(c.getString(R.string.range_wed)); } if ((repeat & REPEAT_THU) != 0) { if (sb.length() > 0) sb.append(", "); sb.append(c.getString(R.string.range_thu)); } if ((repeat & REPEAT_FRI) != 0) { if (sb.length() > 0) sb.append(", "); sb.append(c.getString(R.string.range_fri)); } if ((repeat & REPEAT_SAT) != 0) { if (sb.length() > 0) sb.append(", "); sb.append(c.getString(R.string.range_sat)); } if ((repeat & REPEAT_SUN) != 0) { if (sb.length() > 0) sb.append(", "); sb.append(c.getString(R.string.range_sun)); } return sb.toString(); } public SmarterTimeRange(Parcel source) { enabled = (source.readInt() == 1); collapsed = (source.readInt() == 1); startHour = source.readInt(); startMinute = source.readInt(); endHour = source.readInt(); endMinute = source.readInt(); days = source.readInt(); controlWifi = (source.readInt() == 1); wifiOn = (source.readInt() == 1); controlBluetooth = (source.readInt() == 1); bluetoothOn = (source.readInt() == 1); dbid = source.readLong(); aggressive = (source.readInt() == 1); oldStartHour = source.readInt(); oldStartMinute = source.readInt(); oldEndHour = source.readInt(); oldEndMinute = source.readInt(); oldDays = source.readInt(); oldControlWifi = (source.readInt() == 1); oldWifiOn = (source.readInt() == 1); oldControlBluetooth = (source.readInt() == 1); oldBluetoothOn = (source.readInt() == 1); oldAggressive = (source.readInt() == 1); } public void writeToParcel(Parcel dest, int flags) { dest.writeInt(enabled ? 1 : 0); dest.writeInt(collapsed ? 1 : 0); dest.writeInt(startHour); dest.writeInt(startMinute); dest.writeInt(endHour); dest.writeInt(endMinute); dest.writeInt(days); dest.writeInt(controlWifi ? 1 : 0); dest.writeInt(wifiOn ? 1 : 0); dest.writeInt(controlBluetooth ? 1 : 0); dest.writeInt(bluetoothOn ? 1 : 0); dest.writeLong(dbid); dest.writeInt(aggressive ? 1 : 0); dest.writeInt(oldStartHour); dest.writeInt(oldStartMinute); dest.writeInt(oldEndHour); dest.writeInt(oldEndMinute); dest.writeInt(oldDays); dest.writeInt(oldControlWifi ? 1 : 0); dest.writeInt(oldWifiOn ? 1 : 0); dest.writeInt(oldControlBluetooth ? 1 : 0); dest.writeInt(oldBluetoothOn ? 1 : 0); dest.writeInt(oldAggressive ? 1 : 0); } public int describeContents() { return hashCode(); } public static final Parcelable.Creator<SmarterTimeRange> CREATOR = new Creator<SmarterTimeRange>() { public SmarterTimeRange createFromParcel(Parcel source) { return new SmarterTimeRange(source); } public SmarterTimeRange[] newArray(int size) { return new SmarterTimeRange[size]; } }; // returns if time range is valid, and the resource id of why not or -1 public int getRangeValid() { if (!controlWifi && !controlBluetooth) return R.string.range_fail_nocontrol; if (days == 0) return R.string.range_fail_nodays; if (startHour == endHour && startMinute == endMinute) return R.string.range_fail_notime; return -1; } }