Created TimerNotificationService, TimesUpActivity. Schedule alarms with AlarmManager for timers.

This commit is contained in:
Phillip Hsu 2016-08-03 03:26:53 -07:00
parent 6f8d22f15b
commit 9e4369282d
18 changed files with 449 additions and 114 deletions

View File

@ -21,13 +21,13 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
<!--<activity
android:name=".ringtone.RingtoneActivity"
android:excludeFromRecents="true"
android:label="@string/title_activity_ringtone"
android:launchMode="singleTask"
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
</activity>
</activity>-->
<service
android:name=".ringtone.RingtoneService"
@ -79,14 +79,33 @@
android:exported="false">
</service>
<activity android:name=".edittimer.EditTimerActivity"
android:label="@string/title_activity_create_timer"
android:parentActivityName=".MainActivity"
android:windowSoftInputMode="adjustNothing">
<activity
android:name=".edittimer.EditTimerActivity"
android:label="@string/title_activity_create_timer"
android:parentActivityName=".MainActivity"
android:windowSoftInputMode="adjustNothing">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.philliphsu.clock2.MainActivity"/>
</activity>
<service
android:name=".timers.TimerNotificationService"
android:exported="false">
</service>
<activity android:name=".timers.TimesUpActivity"
android:excludeFromRecents="true"
android:label="@string/title_activity_ringtone"
android:launchMode="singleTask"
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
</activity>
<activity android:name=".alarms.AlarmActivity"
android:excludeFromRecents="true"
android:label="@string/title_activity_ringtone"
android:launchMode="singleTask"
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
</activity>
</application>
</manifest>

View File

@ -203,8 +203,9 @@ public abstract class Alarm extends ObjectWithId implements JsonSerializable, Pa
return !ignoreUpcomingRingTime && ringsIn() <= TimeUnit.HOURS.toMillis(hours);
}
// TODO: Rename to getIntId() so usages refer to ObjectWithId#getIntId(), then delete this method.
public int intId() {
return (int) getId();
return getIntId();
}
// TODO: Remove method signature from JsonSerializable interface.

View File

@ -1,14 +1,22 @@
package com.philliphsu.clock2;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.util.Log;
import com.philliphsu.clock2.alarms.ScrollHandler;
import com.philliphsu.clock2.model.TimersTableManager;
import com.philliphsu.clock2.timers.TimerNotificationService;
import com.philliphsu.clock2.timers.TimesUpActivity;
/**
* Created by Phillip Hsu on 8/2/2016.
*/
public final class AsyncTimersTableUpdateHandler extends AsyncDatabaseTableUpdateHandler<Timer, TimersTableManager> {
private static final String TAG = "TimersTableUpdater"; // TAG max 23 chars
public AsyncTimersTableUpdateHandler(Context context, ScrollHandler scrollHandler) {
super(context, scrollHandler);
@ -21,16 +29,55 @@ public final class AsyncTimersTableUpdateHandler extends AsyncDatabaseTableUpdat
@Override
protected void onPostAsyncDelete(Integer result, Timer timer) {
// TODO: Cancel the alarm scheduled for this timer
cancelAlarm(timer);
}
@Override
protected void onPostAsyncInsert(Long result, Timer timer) {
// TODO: if running, schedule alarm
Log.d(TAG, "onPostAsyncInsert()");
if (timer.isRunning()) {
Log.d(TAG, "Scheduling alarm for timer launch");
scheduleAlarm(timer);
}
}
@Override
protected void onPostAsyncUpdate(Long result, Timer timer) {
// TODO: cancel and reschedule
if (timer.isRunning()) {
// We don't need to cancel the previous alarm, because this one
// will remove and replace it.
scheduleAlarm(timer);
} else {
cancelAlarm(timer);
}
}
// TODO: Consider changing to just a long id param
private PendingIntent createTimesUpIntent(Timer timer) {
Intent intent = new Intent(getContext(), TimesUpActivity.class);
// intent.putExtra(TimesUpActivity.EXTRA_ITEM_ID, timer.getId());
// There's no point to determining whether to retrieve a previous instance, because
// we chose to ignore it since we had issues with NPEs. TODO: Perhaps these issues
// were caused by you using the same reference variable for every Intent/PI that
// needed to be recreated, and you reassigning the reference each time you were done with
// one of them, which leaves the one before unreferenced and hence eligible for GC.
return PendingIntent.getActivity(getContext(), timer.getIntId(), intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
private void scheduleAlarm(Timer timer) {
Log.d(TAG, String.format("now = %d, endTime = %d", SystemClock.elapsedRealtime(), timer.endTime()));
AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, timer.endTime(), createTimesUpIntent(timer));
TimerNotificationService.showNotification(getContext(), timer.getId());
}
private void cancelAlarm(Timer timer) {
// Cancel the alarm scheduled. If one was never scheduled, does nothing.
AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = createTimesUpIntent(timer);
// Now can't be null
am.cancel(pi);
pi.cancel();
TimerNotificationService.cancelNotification(getContext(), timer.getId());
}
}

View File

@ -0,0 +1,78 @@
package com.philliphsu.clock2.alarms;
import android.os.Bundle;
import android.support.v4.content.Loader;
import android.view.View;
import android.widget.Button;
import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.model.AlarmLoader;
import com.philliphsu.clock2.ringtone.RingtoneActivity;
import com.philliphsu.clock2.util.AlarmController;
public class AlarmActivity extends RingtoneActivity<Alarm> {
private AlarmController mAlarmController;
// TODO: Write a getter method instead in the base class?
private Alarm mAlarm;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAlarmController = new AlarmController(this, null);
// TODO: Butterknife binding
Button snooze = (Button) findViewById(R.id.btn_snooze);
snooze.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
snooze();
}
});
Button dismiss = (Button) findViewById(R.id.btn_dismiss);
dismiss.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
@Override
public Loader<Alarm> onCreateLoader(long id) {
return new AlarmLoader(this, id);
}
@Override
public void onLoadFinished(Loader<Alarm> loader, Alarm data) {
super.onLoadFinished(loader, data);
mAlarm = data;
if (data != null) {
// TODO: If the upcoming alarm notification isn't present, verify other notifications aren't affected.
// This could be the case if we're starting a new instance of this activity after leaving the first launch.
mAlarmController.removeUpcomingAlarmNotification(data);
}
}
@Override
public int layoutResource() {
return R.layout.activity_ringtone;
}
private void snooze() {
if (mAlarm != null) {
mAlarmController.snoozeAlarm(mAlarm);
}
// Can't call dismiss() because we don't want to also call cancelAlarm()! Why? For example,
// we don't want the alarm, if it has no recurrence, to be turned off right now.
stopAndFinish();
}
private void dismiss() {
if (mAlarm != null) {
// TODO do we really need to cancel the intent and alarm?
mAlarmController.cancelAlarm(mAlarm, false);
}
stopAndFinish();
}
}

View File

@ -28,8 +28,8 @@ import com.philliphsu.clock2.BaseActivity;
import com.philliphsu.clock2.DaysOfWeek;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.SharedPreferencesHelper;
import com.philliphsu.clock2.alarms.AlarmActivity;
import com.philliphsu.clock2.model.AlarmLoader;
import com.philliphsu.clock2.ringtone.RingtoneActivity;
import com.philliphsu.clock2.util.AlarmController;
import com.philliphsu.clock2.util.AlarmUtils;
import com.philliphsu.clock2.util.DateFormatUtils;
@ -543,8 +543,8 @@ public class EditAlarmActivity extends BaseActivity implements
@Override
public void cancelAlarm(Alarm alarm, boolean showToast) {
new AlarmController(this, mMainContent).cancelAlarm(alarm, true);
if (RingtoneActivity.isAlive()) {
LocalBroadcastHelper.sendBroadcast(this, RingtoneActivity.ACTION_FINISH);
if (AlarmActivity.isAlive()) {
LocalBroadcastHelper.sendBroadcast(this, AlarmActivity.ACTION_FINISH);
}
}

View File

@ -11,6 +11,8 @@ public class AlarmLoader extends DataLoader<Alarm> {
private long mAlarmId;
// TODO: Consider writing a super ctor that has the id param, so
// subclasses don't need to write their own.
public AlarmLoader(Context context, long alarmId) {
super(context);
mAlarmId = alarmId;

View File

@ -6,6 +6,9 @@ import android.support.v4.content.AsyncTaskLoader;
/**
* Created by Phillip Hsu on 6/30/2016.
*/
// TODO: Consider adding a DatabaseTableManager type param, so we can then
// implement loadInBackground for subclasses. You would, however, need to write
// an abstract method getTableManager() that subclasses implement for us.
public abstract class DataLoader<D> extends AsyncTaskLoader<D> {
private D mData;

View File

@ -15,4 +15,8 @@ public abstract class ObjectWithId {
public final void setId(long id) {
this.id = id;
}
public final int getIntId() {
return (int) id;
}
}

View File

@ -0,0 +1,25 @@
package com.philliphsu.clock2.model;
import android.content.Context;
import com.philliphsu.clock2.Timer;
/**
* Created by Phillip Hsu on 8/3/2016.
*/
public class TimerLoader extends DataLoader<Timer> {
private long mTimerId;
// TODO: Consider writing a super ctor that has the id param, so
// subclasses don't need to write their own.
public TimerLoader(Context context, long timerId) {
super(context);
mTimerId = timerId;
}
@Override
public Timer loadInBackground() {
return new TimersTableManager(getContext()).queryItem(mTimerId).getItem();
}
}

View File

@ -4,26 +4,20 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.LayoutRes;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.model.AlarmLoader;
import com.philliphsu.clock2.util.AlarmController;
import com.philliphsu.clock2.util.LocalBroadcastHelper;
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*
* TODO: Make this abstract and make appropriate subclasses for Alarms and Timers.
*/
public class RingtoneActivity extends AppCompatActivity implements
android.support.v4.app.LoaderManager.LoaderCallbacks<Alarm> {
public abstract class RingtoneActivity<T> extends AppCompatActivity implements LoaderCallbacks<T> {
private static final String TAG = "RingtoneActivity";
// Shared with RingtoneService
@ -32,14 +26,19 @@ public class RingtoneActivity extends AppCompatActivity implements
private static boolean sIsAlive = false;
private long mAlarmId;
private Alarm mAlarm;
private AlarmController mAlarmController;
private long mItemId;
private T mItem;
public abstract Loader<T> onCreateLoader(long itemId);
// TODO: Should we extend from BaseActivity instead?
@LayoutRes
public abstract int layoutResource();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ringtone);
setContentView(layoutResource());
sIsAlive = true;
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
@ -47,8 +46,8 @@ public class RingtoneActivity extends AppCompatActivity implements
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
mAlarmId = getIntent().getLongExtra(EXTRA_ITEM_ID, -1);
if (mAlarmId < 0) {
mItemId = getIntent().getLongExtra(EXTRA_ITEM_ID, -1);
if (mItemId < 0) {
throw new IllegalStateException("Cannot start RingtoneActivity without item's id");
}
// The reason we don't use a thread to load the alarm is because this is an
@ -57,43 +56,31 @@ public class RingtoneActivity extends AppCompatActivity implements
getSupportLoaderManager().initLoader(0, null, this);
Intent intent = new Intent(this, RingtoneService.class)
.putExtra(EXTRA_ITEM_ID, mAlarmId);
.putExtra(EXTRA_ITEM_ID, mItemId);
startService(intent);
mAlarmController = new AlarmController(this, null);
// TODO: Butterknife binding
Button snooze = (Button) findViewById(R.id.btn_snooze);
snooze.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
snooze();
}
});
Button dismiss = (Button) findViewById(R.id.btn_dismiss);
dismiss.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
@Override
protected void onResume() {
super.onResume();
// TODO: Do we need this anymore? I think this broadcast was only sent from
// EditAlarmActivity?
LocalBroadcastHelper.registerReceiver(this, mFinishReceiver, ACTION_FINISH);
}
@Override
protected void onPause() {
super.onPause();
// TODO: Do we need this anymore? I think this broadcast was only sent from
// EditAlarmActivity?
LocalBroadcastHelper.unregisterReceiver(this, mFinishReceiver);
}
@Override
protected void onNewIntent(Intent intent) {
//super.onNewIntent(intent); // Not needed since no fragments hosted?
// TODO: Do we need this anymore? I think the broadcast that calls through to
// this was only sent from EditAlarmActivity?
// Notifies alarm missed and stops the service
LocalBroadcastHelper.sendBroadcast(this, RingtoneService.ACTION_NOTIFY_MISSED);
@ -138,22 +125,17 @@ public class RingtoneActivity extends AppCompatActivity implements
}
@Override
public Loader<Alarm> onCreateLoader(int id, Bundle args) {
return new AlarmLoader(this, mAlarmId);
public Loader<T> onCreateLoader(int id, Bundle args) {
return onCreateLoader(mItemId);
}
@Override
public void onLoadFinished(Loader<Alarm> loader, Alarm data) {
mAlarm = data;
if (mAlarm != null) {
// TODO: If the upcoming alarm notification isn't present, verify other notifications aren't affected.
// This could be the case if we're starting a new instance of this activity after leaving the first launch.
mAlarmController.removeUpcomingAlarmNotification(mAlarm);
}
public void onLoadFinished(Loader<T> loader, T data) {
mItem = data;
}
@Override
public void onLoaderReset(Loader<Alarm> loader) {
public void onLoaderReset(Loader<T> loader) {
// Do nothing
}
@ -161,28 +143,17 @@ public class RingtoneActivity extends AppCompatActivity implements
return sIsAlive;
}
private void snooze() {
if (mAlarm != null) {
mAlarmController.snoozeAlarm(mAlarm);
}
// Can't call dismiss() because we don't want to also call cancelAlarm()! Why? For example,
// we don't want the alarm, if it has no recurrence, to be turned off right now.
stopAndFinish();
}
private void dismiss() {
if (mAlarm != null) {
// TODO do we really need to cancel the intent and alarm?
mAlarmController.cancelAlarm(mAlarm, false);
}
stopAndFinish();
}
private void stopAndFinish() {
/**
* Exposed to subclasses so they can force us to stop the
* ringtone and finish us.
*/
protected final void stopAndFinish() {
stopService(new Intent(this, RingtoneService.class));
finish();
}
// TODO: Do we need this anymore? I think this broadcast was only sent from
// EditAlarmActivity?
private final BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {

View File

@ -220,6 +220,10 @@ public class RingtoneService extends Service { // TODO: abstract this, make subc
}
private void finishActivity() {
// I think this will be received by all instances of RingtoneActivity
// subclasses in memory.. but since we realistically expect only one
// instance alive at any given time, we don't need to worry about having
// to restrict the broadcast to only the subclass that's alive.
LocalBroadcastHelper.sendBroadcast(this, RingtoneActivity.ACTION_FINISH);
}

View File

@ -1,7 +1,5 @@
package com.philliphsu.clock2.timers;
import android.widget.ImageButton;
import com.philliphsu.clock2.Timer;
/**
@ -9,27 +7,26 @@ import com.philliphsu.clock2.Timer;
*/
public class TimerController {
private final Timer mTimer;
private final CountdownChronometer mChronometer;
private final ImageButton mAddOneMinute;
private final ImageButton mStartPause;
private final ImageButton mStop;
public TimerController(Timer timer, CountdownChronometer chronometer, ImageButton addOneMinute,
ImageButton startPause, ImageButton stop) {
mTimer = timer;
mChronometer = chronometer;
mAddOneMinute = addOneMinute;
mStartPause = startPause;
mStop = stop;
// init();
/**
* Calls the appropriate state on the given Timer, based on
* its current state.
*/
public static void startPause(Timer timer) {
if (timer.hasStarted()) {
if (timer.isRunning()) {
timer.pause();
} else {
timer.resume();
}
} else {
timer.start();
}
}
public TimerController(Timer timer) {
mTimer = timer;
}
// private void init() {
// mChronometer.setBase(SystemClock.elapsedRealtime() + mTimer.duration());
// updateStartPauseIcon();
// setSecondaryButtonsVisible(false);
// }
public void start() {
mTimer.start();

View File

@ -0,0 +1,171 @@
package com.philliphsu.clock2.timers;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.DrawableRes;
import android.support.v4.app.NotificationCompat;
import com.philliphsu.clock2.MainActivity;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.Timer;
import com.philliphsu.clock2.model.TimersTableManager;
/**
* An {@link IntentService} subclass for handling asynchronous task requests in
* a service on a separate handler thread.
* <p/>
* TODO: Customize class - update intent actions, extra parameters and static
* helper methods.
*/
public class TimerNotificationService extends IntentService {
private static final String TAG = "TimerNotificationService";
public static final String ACTION_ADD_ONE_MINUTE = "com.philliphsu.clock2.timers.action.ADD_ONE_MINUTE";
public static final String ACTION_START_PAUSE = "com.philliphsu.clock2.timers.action.START_PAUSE";
public static final String ACTION_STOP = "com.philliphsu.clock2.timers.action.STOP";
public static final String EXTRA_TIMER_ID = "com.philliphsu.clock2.timers.extra.TIMER_ID";
private TimersTableManager mTableManager;
public TimerNotificationService() {
super("TimerNotificationService");
}
/**
* Helper method to start this Service for its default action: to show
* the notification for the Timer with the given id.
*/
public static void showNotification(Context context, long timerId) {
Intent intent = new Intent(context, TimerNotificationService.class);
intent.putExtra(EXTRA_TIMER_ID, timerId);
context.startService(intent);
}
/**
* Helper method to cancel the notification previously shown from calling
* {@link #showNotification(Context, long)}. This does NOT start the Service
* and call through to {@link #onHandleIntent(Intent)}.
* @param timerId the id of the Timer associated with the notification
* you want to cancel
*/
public static void cancelNotification(Context context, long timerId) {
NotificationManager nm = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel(TAG, (int) timerId);
}
@Override
public void onCreate() {
super.onCreate();
mTableManager = new TimersTableManager(this);
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
final long timerId = intent.getLongExtra(EXTRA_TIMER_ID, -1);
if (timerId == -1) {
throw new IllegalStateException("Did not pass in timer id");
}
final String action = intent.getAction();
if (action == null) {
showNotification(timerId);
} else if (ACTION_ADD_ONE_MINUTE.equals(action)) {
handleAddOneMinute(timerId);
} else if (ACTION_START_PAUSE.equals(action)) {
handleStartPause(timerId);
} else if (ACTION_STOP.equals(action)) {
handleStop(timerId);
}
}
}
private void showNotification(long timerId) {
Timer timer = getTimer(timerId);
// Base note
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
// TODO: correct icon
.setSmallIcon(R.drawable.ic_half_day_1_black_24dp)
.setShowWhen(false)
.setOngoing(true);
// TODO: Set content intent so that when clicked, we launch
// TimersFragment and scroll to the given timer id. The following
// is merely pseudocode.
Intent contentIntent = new Intent(this, MainActivity.class);
contentIntent.putExtra(null/*TODO:MainActivity.EXTRA_SHOW_PAGE*/,
1/*TODO:The tab index of the timers page*/);
contentIntent.putExtra(null/*TODO:MainActivity.EXTRA_SCROLL_TO_ID*/,
timerId);
builder.setContentIntent(PendingIntent.getActivity(
this,
0, // TODO: Request code not needed? Since any multiple notifications
// should be able to use the same PendingIntent for this action....
// unless the underlying *Intent* and its id extra are overwritten
// per notification when retrieving the PendingIntent..
contentIntent,
0/*Shouldn't need a flag..*/));
// TODO: Use a handler to continually update the countdown text
String title = timer.label();
if (title.isEmpty()) {
title = getString(R.string.timer);
}
builder.setContentTitle(title);
addAction(builder, ACTION_ADD_ONE_MINUTE,
timer.getId(), R.drawable.ic_add_circle_24dp/*TODO: correct icon*/);
addAction(builder, ACTION_START_PAUSE,
timer.getId(), R.drawable.ic_add_circle_24dp/*TODO: correct icon*/);
addAction(builder, ACTION_STOP,
timer.getId(), R.drawable.ic_add_circle_24dp/*TODO: correct icon*/);
NotificationManager nm = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(TAG, timer.getIntId(), builder.build());
}
/**
* Builds and adds the specified action to the notification's builder.
*/
private void addAction(NotificationCompat.Builder noteBuilder, String action,
long timerId, @DrawableRes int icon) {
Intent intent = new Intent(this, TimerNotificationService.class)
.setAction(action)
.putExtra(EXTRA_TIMER_ID, timerId);
PendingIntent pi = PendingIntent.getService(this,
(int) timerId, intent, 0/*no flags*/);
noteBuilder.addAction(icon, ""/*no action title*/, pi);
}
private void handleAddOneMinute(long timerId) {
Timer timer = getTimer(timerId);
timer.addOneMinute();
updateTimer(timer);
// TODO: Verify the notification countdown is extended by one minute.
}
private void handleStartPause(long timerId) {
Timer t = getTimer(timerId);
TimerController.startPause(t);
updateTimer(t);
}
private void handleStop(long timerId) {
Timer t = getTimer(timerId);
t.stop();
updateTimer(t);
}
private void updateTimer(Timer timer) {
mTableManager.updateItem(timer.getId(), timer);
}
private Timer getTimer(long timerId) {
return mTableManager.queryItem(timerId).getItem();
}
}

View File

@ -1,6 +1,5 @@
package com.philliphsu.clock2.timers;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
@ -52,17 +51,7 @@ public class TimerViewHolder extends BaseViewHolder<Timer> {
@OnClick(R.id.start_pause)
void startPause() {
Timer t = getItem();
if (t.isRunning()) {
// mController.pause();
t.pause();
} else {
if (t.hasStarted()) {
t.resume();
} else {
t.start();
}
}
TimerController.startPause(getItem());
// Persist value changes
update();
}

View File

@ -0,0 +1,22 @@
package com.philliphsu.clock2.timers;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class TimesUpActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
// @Override
// public Loader<Timer> onCreateLoader(long itemId) {
// return new TimerLoader(this, itemId);
// }
// @Override
// public int layoutResource() {
// return R.layout.activity_ringtone;
// }
}

View File

@ -12,8 +12,8 @@ import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.PendingAlarmScheduler;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.UpcomingAlarmReceiver;
import com.philliphsu.clock2.alarms.AlarmActivity;
import com.philliphsu.clock2.model.AlarmsTableManager;
import com.philliphsu.clock2.ringtone.RingtoneActivity;
import com.philliphsu.clock2.ringtone.RingtoneService;
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
@ -183,8 +183,8 @@ public final class AlarmController {
private PendingIntent alarmIntent(Alarm alarm, boolean retrievePrevious) {
// TODO: Use appropriate subclass instead
Intent intent = new Intent(mAppContext, RingtoneActivity.class)
.putExtra(RingtoneActivity.EXTRA_ITEM_ID, alarm.id());
Intent intent = new Intent(mAppContext, AlarmActivity.class)
.putExtra(AlarmActivity.EXTRA_ITEM_ID, alarm.id());
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
PendingIntent pi = getActivity(mAppContext, alarm.intId(), intent, flag);
// Even when we try to retrieve a previous instance that actually did exist,

View File

@ -13,8 +13,8 @@ import com.philliphsu.clock2.Alarm;
import com.philliphsu.clock2.PendingAlarmScheduler;
import com.philliphsu.clock2.R;
import com.philliphsu.clock2.UpcomingAlarmReceiver;
import com.philliphsu.clock2.alarms.AlarmActivity;
import com.philliphsu.clock2.model.AlarmsTableManager;
import com.philliphsu.clock2.ringtone.RingtoneActivity;
import com.philliphsu.clock2.ringtone.RingtoneService;
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
@ -180,8 +180,8 @@ public final class AlarmUtils {
private static PendingIntent alarmIntent(Context context, Alarm alarm, boolean retrievePrevious) {
// TODO: Use appropriate subclass instead
Intent intent = new Intent(context, RingtoneActivity.class)
.putExtra(RingtoneActivity.EXTRA_ITEM_ID, alarm.id());
Intent intent = new Intent(context, AlarmActivity.class)
.putExtra(AlarmActivity.EXTRA_ITEM_ID, alarm.id());
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
PendingIntent pi = getActivity(context, alarm.intId(), intent, flag);
// Even when we try to retrieve a previous instance that actually did exist,

View File

@ -191,4 +191,6 @@
<!-- TODO: Remove or change this placeholder text -->
<string name="title_activity_create_timer">CreateTimerActivity</string>
<string name="timer">Timer</string>
</resources>