From a1c72f8ef93debd8239b338e6be25ee8e00241a6 Mon Sep 17 00:00:00 2001 From: Phillip Hsu Date: Sun, 26 Jun 2016 15:31:54 -0700 Subject: [PATCH] Tables set up, JSON implementations deprecated --- app/build.gradle | 1 - .../java/com/philliphsu/clock2/Alarm.java | 95 ++++----------- .../clock2/alarms/dummy/DummyContent.java | 8 +- .../clock2/editalarm/EditAlarmActivity.java | 10 +- .../clock2/model/AlarmDatabaseHelper.java | 115 ++++++++++++++++++ .../clock2/model/AlarmIoHelper.java | 1 + .../clock2/model/AlarmsRepository.java | 1 + .../clock2/model/BaseRepository.java | 1 + .../clock2/model/DatabaseManager.java | 34 ++++++ .../philliphsu/clock2/model/JsonIoHelper.java | 1 + .../clock2/model/JsonSerializable.java | 1 + 11 files changed, 188 insertions(+), 80 deletions(-) create mode 100644 app/src/main/java/com/philliphsu/clock2/model/AlarmDatabaseHelper.java create mode 100644 app/src/main/java/com/philliphsu/clock2/model/DatabaseManager.java diff --git a/app/build.gradle b/app/build.gradle index 276bec9..a73a32f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,5 +33,4 @@ dependencies { compile 'com.android.support:support-v4:23.2.1' compile 'com.android.support:recyclerview-v7:23.2.1' compile 'com.jakewharton:butterknife:7.0.1' - compile project(':datetimepicker') } diff --git a/app/src/main/java/com/philliphsu/clock2/Alarm.java b/app/src/main/java/com/philliphsu/clock2/Alarm.java index 2415631..0e99096 100644 --- a/app/src/main/java/com/philliphsu/clock2/Alarm.java +++ b/app/src/main/java/com/philliphsu/clock2/Alarm.java @@ -5,13 +5,10 @@ import android.support.annotation.NonNull; import com.google.auto.value.AutoValue; import com.philliphsu.clock2.model.JsonSerializable; -import org.json.JSONArray; -import org.json.JSONException; import org.json.JSONObject; import java.util.Calendar; import java.util.GregorianCalendar; -import java.util.concurrent.atomic.AtomicLong; import static com.philliphsu.clock2.DaysOfWeek.NUM_DAYS; import static com.philliphsu.clock2.DaysOfWeek.SATURDAY; @@ -24,24 +21,13 @@ import static com.philliphsu.clock2.DaysOfWeek.SUNDAY; public abstract class Alarm implements JsonSerializable { private static final int MAX_MINUTES_CAN_SNOOZE = 30; - // JSON property names - private static final String KEY_SNOOZING_UNTIL_MILLIS = "snoozing_until_millis"; - private static final String KEY_ENABLED = "enabled"; - private static final String KEY_RECURRING_DAYS = "recurring_days"; - //private static final String KEY_ID = "id"; // Defined in JsonSerializable - private static final String KEY_HOUR = "hour"; - private static final String KEY_MINUTES = "minutes"; - private static final String KEY_LABEL = "label"; - private static final String KEY_RINGTONE = "ringtone"; - private static final String KEY_VIBRATES = "vibrates"; - - // ========= MUTABLE ============== + // =================== MUTABLE ======================= + private long id; private long snoozingUntilMillis; private boolean enabled; private final boolean[] recurringDays = new boolean[NUM_DAYS]; - // ================================ + // ==================================================== - //public abstract long id(); public abstract int hour(); public abstract int minutes(); public abstract String label(); @@ -50,35 +36,15 @@ public abstract class Alarm implements JsonSerializable { /** Initializes a Builder to the same property values as this instance */ public abstract Builder toBuilder(); + @Deprecated public static Alarm create(JSONObject jsonObject) { - try { - Alarm alarm = new AutoValue_Alarm.Builder() - .id(jsonObject.getLong(KEY_ID)) - .hour(jsonObject.getInt(KEY_HOUR)) - .minutes(jsonObject.getInt(KEY_MINUTES)) - .label(jsonObject.getString(KEY_LABEL)) - .ringtone(jsonObject.getString(KEY_RINGTONE)) - .vibrates(jsonObject.getBoolean(KEY_VIBRATES)) - .rebuild(); - alarm.setEnabled(jsonObject.getBoolean(KEY_ENABLED)); - alarm.snoozingUntilMillis = jsonObject.getLong(KEY_SNOOZING_UNTIL_MILLIS); - - JSONArray a = (JSONArray) jsonObject.get(KEY_RECURRING_DAYS); - for (int i = 0; i < a.length(); i++) { - alarm.recurringDays[i] = a.getBoolean(i); - } - - return alarm; - } catch (JSONException e) { - throw new RuntimeException(e); - } + return null; } public static Builder builder() { // Unfortunately, default values must be provided for generated Builders. // Fields that were not set when build() is called will throw an exception. return new AutoValue_Alarm.Builder() - .id(-1) .hour(0) .minutes(0) .label("") @@ -211,59 +177,46 @@ public abstract class Alarm implements JsonSerializable { return ringsIn() <= hours * 3600000; } + @Deprecated public int intId() { - return (int) id(); + return -1; } + public void setId(long id) { + this.id = id; + } + + public long getId() { + return id; + } + + @Deprecated + @Override + public final long id() { + return -1; + } + + @Deprecated @Override @NonNull public JSONObject toJsonObject() { - try { - return new JSONObject() - .put(KEY_SNOOZING_UNTIL_MILLIS, snoozingUntilMillis) - .put(KEY_ENABLED, enabled) - .put(KEY_RECURRING_DAYS, new JSONArray(recurringDays)) - .put(KEY_ID, id()) - .put(KEY_HOUR, hour()) - .put(KEY_MINUTES, minutes()) - .put(KEY_LABEL, label()) - .put(KEY_RINGTONE, ringtone()) - .put(KEY_VIBRATES, vibrates()); - } catch (JSONException e) { - throw new RuntimeException(e); - } + return null; } @AutoValue.Builder public abstract static class Builder { - private static final AtomicLong ID_COUNTER = new AtomicLong(0); - // By omitting the set- prefix, we reduce the number of changes required to define the Builder - // class after copying and pasting the accessor fields here. - public abstract Builder id(long id); public abstract Builder hour(int hour); public abstract Builder minutes(int minutes); public abstract Builder label(String label); public abstract Builder ringtone(String ringtone); public abstract Builder vibrates(boolean vibrates); - // To enforce preconditions, split the build method into two. autoBuild() is hidden from - // callers and is generated. You implement the public build(), which calls the generated - // autoBuild() and performs your desired validations. - /*not public*/abstract Alarm autoBuild(); + /* package */ abstract Alarm autoBuild(); public Alarm build() { - this.id(ID_COUNTER.incrementAndGet()); // TOneverDO: change to getAndIncrement() without also adding offset of 1 in rebuild() Alarm alarm = autoBuild(); doChecks(alarm); return alarm; } - - /** Should only be called when recreating an instance from JSON */ - private Alarm rebuild() { - Alarm alarm = autoBuild(); - ID_COUNTER.set(alarm.id()); // prevent future instances from id collision - doChecks(alarm); - return alarm; - } } private static void doChecks(Alarm alarm) { diff --git a/app/src/main/java/com/philliphsu/clock2/alarms/dummy/DummyContent.java b/app/src/main/java/com/philliphsu/clock2/alarms/dummy/DummyContent.java index e6c1c48..4f25afe 100644 --- a/app/src/main/java/com/philliphsu/clock2/alarms/dummy/DummyContent.java +++ b/app/src/main/java/com/philliphsu/clock2/alarms/dummy/DummyContent.java @@ -32,12 +32,6 @@ public class DummyContent { } private static Alarm createAlarm(int position) { - Alarm.Builder b = Alarm.builder(); - if (position % 2 == 0) { - b.hour(21).minutes(0); - } - Alarm a = b.id(position).build(); - a.setEnabled(true); - return a; + return null; } } diff --git a/app/src/main/java/com/philliphsu/clock2/editalarm/EditAlarmActivity.java b/app/src/main/java/com/philliphsu/clock2/editalarm/EditAlarmActivity.java index 9075302..3e9846f 100644 --- a/app/src/main/java/com/philliphsu/clock2/editalarm/EditAlarmActivity.java +++ b/app/src/main/java/com/philliphsu/clock2/editalarm/EditAlarmActivity.java @@ -28,11 +28,14 @@ import com.philliphsu.clock2.DaysOfWeek; import com.philliphsu.clock2.R; import com.philliphsu.clock2.SharedPreferencesHelper; import com.philliphsu.clock2.model.AlarmsRepository; +import com.philliphsu.clock2.model.DatabaseManager; import com.philliphsu.clock2.ringtone.RingtoneActivity; import com.philliphsu.clock2.util.AlarmUtils; import com.philliphsu.clock2.util.LocalBroadcastHelper; +import java.util.Calendar; import java.util.Date; +import java.util.GregorianCalendar; import butterknife.Bind; import butterknife.OnCheckedChanged; @@ -182,7 +185,12 @@ public class EditAlarmActivity extends BaseActivity implements AlarmNumpad.KeyLi @OnClick(R.id.save) void save() { - mPresenter.save(); + //mPresenter.save(); + Calendar calendar = new GregorianCalendar(); + int hour = calendar.get(Calendar.HOUR_OF_DAY); + int minutes = calendar.get(Calendar.MINUTE); + Alarm alarm = Alarm.builder().hour(hour).minutes((minutes + 1) % 60).build(); + DatabaseManager.getInstance(this).insertAlarm(alarm); } @OnClick(R.id.delete) diff --git a/app/src/main/java/com/philliphsu/clock2/model/AlarmDatabaseHelper.java b/app/src/main/java/com/philliphsu/clock2/model/AlarmDatabaseHelper.java new file mode 100644 index 0000000..5d94a79 --- /dev/null +++ b/app/src/main/java/com/philliphsu/clock2/model/AlarmDatabaseHelper.java @@ -0,0 +1,115 @@ +package com.philliphsu.clock2.model; + +import android.content.ContentValues; +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import com.philliphsu.clock2.Alarm; +import com.philliphsu.clock2.DaysOfWeek; + +/** + * Created by Phillip Hsu on 6/24/2016. + * + * TODO: We can generalize this class to all data models, not just Alarms. + */ +public class AlarmDatabaseHelper extends SQLiteOpenHelper { + private static final String DB_NAME = "alarms.db"; + private static final int VERSION_1 = 1; + + // TODO: Consider creating an inner class that implements BaseColumns + // and defines all the columns. + private static final String TABLE_ALARMS = "alarms"; + private static final String COLUMN_ID = "_id"; + private static final String COLUMN_HOUR = "hour"; + private static final String COLUMN_MINUTES = "minutes"; + private static final String COLUMN_LABEL = "label"; + private static final String COLUMN_RINGTONE = "ringtone"; + private static final String COLUMN_VIBRATES = "vibrates"; + private static final String COLUMN_ENABLED = "enabled"; + private static final String COLUMN_SNOOZING_UNTIL_MILLIS = "snoozing_until_millis"; + + // TODO: Consider creating an inner class that implements BaseColumns + // and defines all the columns. + private static final String TABLE_ALARM_RECURRING_DAYS = "alarm_recurring_days"; + private static final String COLUMN_ALARM_ID = "alarm_id"; + private static final String COLUMN_SUNDAY = "sunday"; + private static final String COLUMN_MONDAY = "monday"; + private static final String COLUMN_TUESDAY = "tuesday"; + private static final String COLUMN_WEDNESDAY = "wednesday"; + private static final String COLUMN_THURSDAY = "thursday"; + private static final String COLUMN_FRIDAY = "friday"; + private static final String COLUMN_SATURDAY = "saturday"; + + private static void createAlarmsTable(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + TABLE_ALARMS + " (" + + COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + COLUMN_HOUR + " INTEGER NOT NULL, " + + COLUMN_MINUTES + " INTEGER NOT NULL, " + + COLUMN_LABEL + " TEXT, " + + COLUMN_RINGTONE + " TEXT NOT NULL, " + + COLUMN_VIBRATES + " INTEGER NOT NULL, " + + COLUMN_ENABLED + " INTEGER NOT NULL, " + + COLUMN_SNOOZING_UNTIL_MILLIS + " INTEGER);"); + } + + private static void createRecurringDaysTable(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + TABLE_ALARM_RECURRING_DAYS + " (" + + COLUMN_ALARM_ID + " INTEGER REFERENCES " + TABLE_ALARMS + "(" + COLUMN_ID + "), " + + COLUMN_SUNDAY + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_MONDAY + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_TUESDAY + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_WEDNESDAY + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_THURSDAY + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_FRIDAY + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_SATURDAY + " INTEGER NOT NULL DEFAULT 0);"); + } + + public AlarmDatabaseHelper(Context context) { + super(context, DB_NAME, null, VERSION_1); + } + + @Override + public void onCreate(SQLiteDatabase db) { + // https://www.sqlite.org/datatype3.html + // INTEGER data type is stored in 1, 2, 3, 4, 6, or 8 bytes depending on the magnitude + // of the value. As soon as INTEGER values are read off of disk and into memory for processing, + // they are converted to the most general datatype (8-byte signed integer). + // 8 byte == 64 bits so this means they are read as longs...? + createAlarmsTable(db); + createRecurringDaysTable(db); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + // I don't think we need to drop current tables unless you make structural changes + // to the schema in the new version. + } + + // TODO: Consider changing param to Alarm.Builder so the Alarm that will be + // built can have its ID set. + public long insertAlarm(Alarm alarm) { + ContentValues values = new ContentValues(); + values.put(COLUMN_HOUR, alarm.hour()); + values.put(COLUMN_MINUTES, alarm.minutes()); + values.put(COLUMN_LABEL, alarm.label()); + values.put(COLUMN_RINGTONE, alarm.ringtone()); + values.put(COLUMN_VIBRATES, alarm.vibrates()); + values.put(COLUMN_ENABLED, alarm.isEnabled()); + values.put(COLUMN_SNOOZING_UNTIL_MILLIS, alarm.snoozingUntil()); + long id = getWritableDatabase().insert(TABLE_ALARMS, null, values); + alarm.setId(id); + + values = new ContentValues(); + values.put(COLUMN_ALARM_ID, id); + values.put(COLUMN_SUNDAY, alarm.isRecurring(DaysOfWeek.SUNDAY)); + values.put(COLUMN_MONDAY, alarm.isRecurring(DaysOfWeek.MONDAY)); + values.put(COLUMN_TUESDAY, alarm.isRecurring(DaysOfWeek.TUESDAY)); + values.put(COLUMN_WEDNESDAY, alarm.isRecurring(DaysOfWeek.WEDNESDAY)); + values.put(COLUMN_THURSDAY, alarm.isRecurring(DaysOfWeek.THURSDAY)); + values.put(COLUMN_FRIDAY, alarm.isRecurring(DaysOfWeek.FRIDAY)); + values.put(COLUMN_SATURDAY, alarm.isRecurring(DaysOfWeek.SATURDAY)); + getWritableDatabase().insert(TABLE_ALARM_RECURRING_DAYS, null, values); + return id; + } +} diff --git a/app/src/main/java/com/philliphsu/clock2/model/AlarmIoHelper.java b/app/src/main/java/com/philliphsu/clock2/model/AlarmIoHelper.java index 7c96927..ff6c0b9 100644 --- a/app/src/main/java/com/philliphsu/clock2/model/AlarmIoHelper.java +++ b/app/src/main/java/com/philliphsu/clock2/model/AlarmIoHelper.java @@ -10,6 +10,7 @@ import org.json.JSONObject; /** * Created by Phillip Hsu on 5/31/2016. */ +@Deprecated public class AlarmIoHelper extends JsonIoHelper { private static final String FILENAME = "alarms.json"; diff --git a/app/src/main/java/com/philliphsu/clock2/model/AlarmsRepository.java b/app/src/main/java/com/philliphsu/clock2/model/AlarmsRepository.java index 3c2fb4b..d9597ec 100644 --- a/app/src/main/java/com/philliphsu/clock2/model/AlarmsRepository.java +++ b/app/src/main/java/com/philliphsu/clock2/model/AlarmsRepository.java @@ -9,6 +9,7 @@ import com.philliphsu.clock2.Alarm; /** * Created by Phillip Hsu on 5/31/2016. */ +@Deprecated public class AlarmsRepository extends BaseRepository { private static final String TAG = "AlarmsRepository"; // Singleton, so this is the sole instance for the lifetime diff --git a/app/src/main/java/com/philliphsu/clock2/model/BaseRepository.java b/app/src/main/java/com/philliphsu/clock2/model/BaseRepository.java index 183f2f3..3e585b4 100644 --- a/app/src/main/java/com/philliphsu/clock2/model/BaseRepository.java +++ b/app/src/main/java/com/philliphsu/clock2/model/BaseRepository.java @@ -13,6 +13,7 @@ import java.util.List; /** * Created by Phillip Hsu on 5/31/2016. */ +@Deprecated public abstract class BaseRepository implements Repository { private static final String TAG = "BaseRepository"; // Cannot do this! Multiple classes will extend from this, diff --git a/app/src/main/java/com/philliphsu/clock2/model/DatabaseManager.java b/app/src/main/java/com/philliphsu/clock2/model/DatabaseManager.java new file mode 100644 index 0000000..234b2c8 --- /dev/null +++ b/app/src/main/java/com/philliphsu/clock2/model/DatabaseManager.java @@ -0,0 +1,34 @@ +package com.philliphsu.clock2.model; + +import android.content.Context; + +import com.philliphsu.clock2.Alarm; + +/** + * Created by Phillip Hsu on 6/25/2016. + * + * TODO: Not sure this class is all that useful? We could make the DbHelper singleton instance in its own class. + */ +public class DatabaseManager { + + private static DatabaseManager sDatabaseManager; + private final Context mContext; + private final AlarmDatabaseHelper mHelper; + + private DatabaseManager(Context context) { + mContext = context.getApplicationContext(); + mHelper = new AlarmDatabaseHelper(mContext); + } + + public static DatabaseManager getInstance(Context context) { + if (sDatabaseManager == null) { + sDatabaseManager = new DatabaseManager(context); + } + return sDatabaseManager; + } + + public Alarm insertAlarm(Alarm alarm) { + mHelper.insertAlarm(alarm); + return alarm; + } +} diff --git a/app/src/main/java/com/philliphsu/clock2/model/JsonIoHelper.java b/app/src/main/java/com/philliphsu/clock2/model/JsonIoHelper.java index c43b522..5dce01a 100644 --- a/app/src/main/java/com/philliphsu/clock2/model/JsonIoHelper.java +++ b/app/src/main/java/com/philliphsu/clock2/model/JsonIoHelper.java @@ -19,6 +19,7 @@ import java.util.List; /** * Created by Phillip Hsu on 5/31/2016. */ +@Deprecated public abstract class JsonIoHelper { @NonNull private final Context mContext; @NonNull private final String mFilename; diff --git a/app/src/main/java/com/philliphsu/clock2/model/JsonSerializable.java b/app/src/main/java/com/philliphsu/clock2/model/JsonSerializable.java index a24e89c..6ec712c 100644 --- a/app/src/main/java/com/philliphsu/clock2/model/JsonSerializable.java +++ b/app/src/main/java/com/philliphsu/clock2/model/JsonSerializable.java @@ -8,6 +8,7 @@ import org.json.JSONObject; /** * Created by Phillip Hsu on 5/31/2016. */ +@Deprecated public interface JsonSerializable { String KEY_ID = "id";