Pass alarm directly to AlarmActivity and AlarmRingtoneService
This commit is contained in:
parent
9e4369282d
commit
25c544df43
@ -21,19 +21,21 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<!--<activity
|
<!--
|
||||||
|
<activity
|
||||||
android:name=".ringtone.RingtoneActivity"
|
android:name=".ringtone.RingtoneActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:label="@string/title_activity_ringtone"
|
android:label="@string/title_activity_ringtone"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
|
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
|
||||||
</activity>-->
|
</activity>
|
||||||
|
-->
|
||||||
|
|
||||||
<service
|
<!--<service
|
||||||
android:name=".ringtone.RingtoneService"
|
android:name=".ringtone.RingtoneService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false">
|
android:exported="false">
|
||||||
</service>
|
</service>-->
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".UpcomingAlarmReceiver"
|
android:name=".UpcomingAlarmReceiver"
|
||||||
@ -94,18 +96,26 @@
|
|||||||
android:exported="false">
|
android:exported="false">
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<activity android:name=".timers.TimesUpActivity"
|
<activity
|
||||||
android:excludeFromRecents="true"
|
android:name=".timers.TimesUpActivity"
|
||||||
android:label="@string/title_activity_ringtone"
|
android:excludeFromRecents="true"
|
||||||
android:launchMode="singleTask"
|
android:label="@string/title_activity_ringtone"
|
||||||
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
|
android:launchMode="singleTask"
|
||||||
|
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name=".alarms.AlarmActivity"
|
<activity
|
||||||
android:excludeFromRecents="true"
|
android:name=".alarms.AlarmActivity"
|
||||||
android:label="@string/title_activity_ringtone"
|
android:excludeFromRecents="true"
|
||||||
android:launchMode="singleTask"
|
android:label="@string/title_activity_ringtone"
|
||||||
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
|
android:launchMode="singleTask"
|
||||||
|
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".alarms.AlarmRingtoneService"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false">
|
||||||
|
</service>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@ -4,8 +4,6 @@ import android.app.AlarmManager;
|
|||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.philliphsu.clock2.alarms.ScrollHandler;
|
import com.philliphsu.clock2.alarms.ScrollHandler;
|
||||||
import com.philliphsu.clock2.model.TimersTableManager;
|
import com.philliphsu.clock2.model.TimersTableManager;
|
||||||
@ -29,14 +27,12 @@ public final class AsyncTimersTableUpdateHandler extends AsyncDatabaseTableUpdat
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostAsyncDelete(Integer result, Timer timer) {
|
protected void onPostAsyncDelete(Integer result, Timer timer) {
|
||||||
cancelAlarm(timer);
|
cancelAlarm(timer, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostAsyncInsert(Long result, Timer timer) {
|
protected void onPostAsyncInsert(Long result, Timer timer) {
|
||||||
Log.d(TAG, "onPostAsyncInsert()");
|
|
||||||
if (timer.isRunning()) {
|
if (timer.isRunning()) {
|
||||||
Log.d(TAG, "Scheduling alarm for timer launch");
|
|
||||||
scheduleAlarm(timer);
|
scheduleAlarm(timer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -48,7 +44,7 @@ public final class AsyncTimersTableUpdateHandler extends AsyncDatabaseTableUpdat
|
|||||||
// will remove and replace it.
|
// will remove and replace it.
|
||||||
scheduleAlarm(timer);
|
scheduleAlarm(timer);
|
||||||
} else {
|
} else {
|
||||||
cancelAlarm(timer);
|
cancelAlarm(timer, !timer.hasStarted());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,19 +61,20 @@ public final class AsyncTimersTableUpdateHandler extends AsyncDatabaseTableUpdat
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleAlarm(Timer timer) {
|
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);
|
AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
|
||||||
am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, timer.endTime(), createTimesUpIntent(timer));
|
am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, timer.endTime(), createTimesUpIntent(timer));
|
||||||
TimerNotificationService.showNotification(getContext(), timer.getId());
|
TimerNotificationService.showNotification(getContext(), timer.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cancelAlarm(Timer timer) {
|
private void cancelAlarm(Timer timer, boolean removeNotification) {
|
||||||
// Cancel the alarm scheduled. If one was never scheduled, does nothing.
|
// Cancel the alarm scheduled. If one was never scheduled, does nothing.
|
||||||
AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
|
AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
|
||||||
PendingIntent pi = createTimesUpIntent(timer);
|
PendingIntent pi = createTimesUpIntent(timer);
|
||||||
// Now can't be null
|
// Now can't be null
|
||||||
am.cancel(pi);
|
am.cancel(pi);
|
||||||
pi.cancel();
|
pi.cancel();
|
||||||
TimerNotificationService.cancelNotification(getContext(), timer.getId());
|
if (removeNotification) {
|
||||||
|
TimerNotificationService.cancelNotification(getContext(), timer.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
package com.philliphsu.clock2.alarms;
|
package com.philliphsu.clock2.alarms;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.content.Loader;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
import com.philliphsu.clock2.Alarm;
|
import com.philliphsu.clock2.Alarm;
|
||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.model.AlarmLoader;
|
|
||||||
import com.philliphsu.clock2.ringtone.RingtoneActivity;
|
import com.philliphsu.clock2.ringtone.RingtoneActivity;
|
||||||
|
import com.philliphsu.clock2.ringtone.RingtoneService;
|
||||||
import com.philliphsu.clock2.util.AlarmController;
|
import com.philliphsu.clock2.util.AlarmController;
|
||||||
|
|
||||||
public class AlarmActivity extends RingtoneActivity<Alarm> {
|
public class AlarmActivity extends RingtoneActivity<Alarm> {
|
||||||
@ -20,7 +19,13 @@ public class AlarmActivity extends RingtoneActivity<Alarm> {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
if ((mAlarm = getIntent().getParcelableExtra(EXTRA_ITEM)) == null) {
|
||||||
|
throw new IllegalStateException("Cannot start AlarmActivity without an Alarm");
|
||||||
|
}
|
||||||
mAlarmController = new AlarmController(this, null);
|
mAlarmController = new AlarmController(this, 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);
|
||||||
// TODO: Butterknife binding
|
// TODO: Butterknife binding
|
||||||
Button snooze = (Button) findViewById(R.id.btn_snooze);
|
Button snooze = (Button) findViewById(R.id.btn_snooze);
|
||||||
snooze.setOnClickListener(new View.OnClickListener() {
|
snooze.setOnClickListener(new View.OnClickListener() {
|
||||||
@ -38,27 +43,32 @@ public class AlarmActivity extends RingtoneActivity<Alarm> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public Loader<Alarm> onCreateLoader(long id) {
|
// public Loader<Alarm> onCreateLoader(long id) {
|
||||||
return new AlarmLoader(this, id);
|
// return new AlarmLoader(this, id);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onLoadFinished(Loader<Alarm> loader, Alarm data) {
|
// public void onLoadFinished(Loader<Alarm> loader, Alarm data) {
|
||||||
super.onLoadFinished(loader, data);
|
// super.onLoadFinished(loader, data);
|
||||||
mAlarm = data;
|
// mAlarm = data;
|
||||||
if (data != null) {
|
// if (data != null) {
|
||||||
// TODO: If the upcoming alarm notification isn't present, verify other notifications aren't affected.
|
// // 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.
|
// // This could be the case if we're starting a new instance of this activity after leaving the first launch.
|
||||||
mAlarmController.removeUpcomingAlarmNotification(data);
|
// mAlarmController.removeUpcomingAlarmNotification(data);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int layoutResource() {
|
public int layoutResource() {
|
||||||
return R.layout.activity_ringtone;
|
return R.layout.activity_ringtone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<? extends RingtoneService> getRingtoneServiceClass() {
|
||||||
|
return AlarmRingtoneService.class;
|
||||||
|
}
|
||||||
|
|
||||||
private void snooze() {
|
private void snooze() {
|
||||||
if (mAlarm != null) {
|
if (mAlarm != null) {
|
||||||
mAlarmController.snoozeAlarm(mAlarm);
|
mAlarmController.snoozeAlarm(mAlarm);
|
||||||
|
|||||||
@ -0,0 +1,127 @@
|
|||||||
|
package com.philliphsu.clock2.alarms;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.media.Ringtone;
|
||||||
|
import android.media.RingtoneManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
|
||||||
|
import com.philliphsu.clock2.Alarm;
|
||||||
|
import com.philliphsu.clock2.R;
|
||||||
|
import com.philliphsu.clock2.ringtone.RingtoneService;
|
||||||
|
import com.philliphsu.clock2.util.AlarmController;
|
||||||
|
import com.philliphsu.clock2.util.AlarmUtils;
|
||||||
|
|
||||||
|
import static com.philliphsu.clock2.util.DateFormatUtils.formatTime;
|
||||||
|
|
||||||
|
public class AlarmRingtoneService extends RingtoneService<Alarm> {
|
||||||
|
private static final String TAG = "AlarmRingtoneService";
|
||||||
|
/* TOneverDO: not private */
|
||||||
|
private static final String ACTION_SNOOZE = "com.philliphsu.clock2.ringtone.action.SNOOZE";
|
||||||
|
private static final String ACTION_DISMISS = "com.philliphsu.clock2.ringtone.action.DISMISS";
|
||||||
|
|
||||||
|
private String mNormalRingTime;
|
||||||
|
private AlarmController mAlarmController;
|
||||||
|
private Alarm mAlarm;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
// TOneverDO: Call super before our custom logic
|
||||||
|
if (intent.getAction() == null) {
|
||||||
|
// final long id = intent.getLongExtra(EXTRA_ITEM_ID, -1);
|
||||||
|
// if (id < 0)
|
||||||
|
// throw new IllegalStateException("No item id set");
|
||||||
|
// http://stackoverflow.com/q/8696146/5055032
|
||||||
|
// Start our own thread to load the alarm instead of using a loader,
|
||||||
|
// because Services do not have a built-in LoaderManager (because they have no need for one since
|
||||||
|
// their lifecycle is not complex like in Activities/Fragments) and our
|
||||||
|
// work is simple enough that getting loaders to work here is not
|
||||||
|
// worth the effort.
|
||||||
|
// // TODO: Will using the Runnable like this cause a memory leak?
|
||||||
|
// new Thread(new Runnable() {
|
||||||
|
// @Override
|
||||||
|
// public void run() {
|
||||||
|
// // TODO: We don't actually need the exact same Alarm instance as the
|
||||||
|
// // one from our calling component, because we won't mutate any of its
|
||||||
|
// // fields. Since we only read values, we could just pass in the Alarm
|
||||||
|
// // to the intent as a Parcelable.
|
||||||
|
// AlarmCursor cursor = new AlarmsTableManager(AlarmRingtoneService.this).queryItem(id);
|
||||||
|
// mAlarm = checkNotNull(cursor.getItem());
|
||||||
|
// }
|
||||||
|
// }).start();
|
||||||
|
if ((mAlarm = intent.getParcelableExtra(EXTRA_ITEM)) == null) {
|
||||||
|
throw new IllegalStateException("Cannot start AlarmRingtoneService without an Alarm");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ACTION_SNOOZE.equals(intent.getAction())) {
|
||||||
|
mAlarmController.snoozeAlarm(mAlarm);
|
||||||
|
} else if (ACTION_DISMISS.equals(intent.getAction())) {
|
||||||
|
mAlarmController.cancelAlarm(mAlarm, false); // TODO do we really need to cancel the intent and alarm?
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
// ==========================================================================
|
||||||
|
stopSelf(startId);
|
||||||
|
finishActivity();
|
||||||
|
}
|
||||||
|
return super.onStartCommand(intent, flags, startId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
mAlarmController = new AlarmController(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onAutoSilenced() {
|
||||||
|
// TODO do we really need to cancel the alarm and intent?
|
||||||
|
mAlarmController.cancelAlarm(mAlarm, false);
|
||||||
|
// Post notification that alarm was missed
|
||||||
|
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
Notification note = new NotificationCompat.Builder(this)
|
||||||
|
.setContentTitle(getString(R.string.missed_alarm))
|
||||||
|
.setContentText(mNormalRingTime)
|
||||||
|
.setSmallIcon(R.mipmap.ic_launcher)
|
||||||
|
.build();
|
||||||
|
nm.notify(TAG, mAlarm.intId(), note);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Ringtone getRingtone() {
|
||||||
|
Uri ringtone = Uri.parse(mAlarm.ringtone());
|
||||||
|
return RingtoneManager.getRingtone(this, ringtone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Notification getForegroundNotification() {
|
||||||
|
String title = mAlarm.label().isEmpty()
|
||||||
|
? getString(R.string.alarm)
|
||||||
|
: mAlarm.label();
|
||||||
|
mNormalRingTime = formatTime(this, System.currentTimeMillis()); // now
|
||||||
|
return new NotificationCompat.Builder(this)
|
||||||
|
// Required contents
|
||||||
|
.setSmallIcon(R.mipmap.ic_launcher) // TODO: alarm icon
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setContentText(mNormalRingTime)
|
||||||
|
.addAction(R.mipmap.ic_launcher,
|
||||||
|
getString(R.string.snooze),
|
||||||
|
getPendingIntent(ACTION_SNOOZE, mAlarm))
|
||||||
|
.addAction(R.mipmap.ic_launcher,
|
||||||
|
getString(R.string.dismiss),
|
||||||
|
getPendingIntent(ACTION_DISMISS, mAlarm))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean doesVibrate() {
|
||||||
|
return mAlarm.vibrates();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int minutesToAutoSilence() {
|
||||||
|
return AlarmUtils.minutesToSilenceAfter(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -73,9 +73,9 @@ public abstract class DatabaseTableManager<T extends ObjectWithId> {
|
|||||||
toContentValues(newItem),
|
toContentValues(newItem),
|
||||||
COLUMN_ID + " = " + id,
|
COLUMN_ID + " = " + id,
|
||||||
null);
|
null);
|
||||||
if (rowsUpdated == 0) {
|
// if (rowsUpdated == 0) {
|
||||||
throw new IllegalStateException("wtf?");
|
// throw new IllegalStateException("wtf?");
|
||||||
}
|
// }
|
||||||
notifyContentChanged();
|
notifyContentChanged();
|
||||||
return rowsUpdated;
|
return rowsUpdated;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,9 +4,8 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.support.annotation.LayoutRes;
|
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.support.v7.app.AppCompatActivity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
@ -17,24 +16,27 @@ import com.philliphsu.clock2.util.LocalBroadcastHelper;
|
|||||||
* An example full-screen activity that shows and hides the system UI (i.e.
|
* An example full-screen activity that shows and hides the system UI (i.e.
|
||||||
* status bar and navigation/system bar) with user interaction.
|
* status bar and navigation/system bar) with user interaction.
|
||||||
*/
|
*/
|
||||||
public abstract class RingtoneActivity<T> extends AppCompatActivity implements LoaderCallbacks<T> {
|
public abstract class RingtoneActivity<T extends Parcelable> extends AppCompatActivity /*implements LoaderCallbacks<T>*/ {
|
||||||
private static final String TAG = "RingtoneActivity";
|
private static final String TAG = "RingtoneActivity";
|
||||||
|
|
||||||
// Shared with RingtoneService
|
// Shared with RingtoneService
|
||||||
public static final String EXTRA_ITEM_ID = "com.philliphsu.clock2.ringtone.extra.ITEM_ID";
|
// public static final String EXTRA_ITEM_ID = "com.philliphsu.clock2.ringtone.extra.ITEM_ID";
|
||||||
public static final String ACTION_FINISH = "com.philliphsu.clock2.ringtone.action.UNBIND";
|
public static final String ACTION_FINISH = "com.philliphsu.clock2.ringtone.action.FINISH";
|
||||||
|
public static final String EXTRA_ITEM = "com.philliphsu.clock2.ringtone.extra.ITEM";
|
||||||
|
|
||||||
private static boolean sIsAlive = false;
|
private static boolean sIsAlive = false;
|
||||||
|
|
||||||
private long mItemId;
|
// private long mItemId;
|
||||||
private T mItem;
|
// private T mItem;
|
||||||
|
|
||||||
public abstract Loader<T> onCreateLoader(long itemId);
|
// public abstract Loader<T> onCreateLoader(long itemId);
|
||||||
|
|
||||||
// TODO: Should we extend from BaseActivity instead?
|
// TODO: Should we extend from BaseActivity instead?
|
||||||
@LayoutRes
|
@LayoutRes
|
||||||
public abstract int layoutResource();
|
public abstract int layoutResource();
|
||||||
|
|
||||||
|
protected abstract Class<? extends RingtoneService> getRingtoneServiceClass();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -46,17 +48,17 @@ public abstract class RingtoneActivity<T> extends AppCompatActivity implements L
|
|||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
|
||||||
|
|
||||||
mItemId = getIntent().getLongExtra(EXTRA_ITEM_ID, -1);
|
// mItemId = getIntent().getLongExtra(EXTRA_ITEM_ID, -1);
|
||||||
if (mItemId < 0) {
|
// if (mItemId < 0) {
|
||||||
throw new IllegalStateException("Cannot start RingtoneActivity without item's id");
|
// 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
|
// The reason we don't use a thread to load the alarm is because this is an
|
||||||
// Activity, which has complex lifecycle. LoaderManager is designed to help
|
// Activity, which has complex lifecycle. LoaderManager is designed to help
|
||||||
// us through the vagaries of the lifecycle that could affect loading data.
|
// us through the vagaries of the lifecycle that could affect loading data.
|
||||||
getSupportLoaderManager().initLoader(0, null, this);
|
// getSupportLoaderManager().initLoader(0, null, this);
|
||||||
|
|
||||||
Intent intent = new Intent(this, RingtoneService.class)
|
Intent intent = new Intent(this, getRingtoneServiceClass())
|
||||||
.putExtra(EXTRA_ITEM_ID, mItemId);
|
.putExtra(EXTRA_ITEM, getIntent().getParcelableExtra(EXTRA_ITEM));
|
||||||
startService(intent);
|
startService(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,20 +126,20 @@ public abstract class RingtoneActivity<T> extends AppCompatActivity implements L
|
|||||||
sIsAlive = false;
|
sIsAlive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public Loader<T> onCreateLoader(int id, Bundle args) {
|
// public Loader<T> onCreateLoader(int id, Bundle args) {
|
||||||
return onCreateLoader(mItemId);
|
// return onCreateLoader(mItemId);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onLoadFinished(Loader<T> loader, T data) {
|
// public void onLoadFinished(Loader<T> loader, T data) {
|
||||||
mItem = data;
|
// mItem = data;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void onLoaderReset(Loader<T> loader) {
|
// public void onLoaderReset(Loader<T> loader) {
|
||||||
// Do nothing
|
// // Do nothing
|
||||||
}
|
// }
|
||||||
|
|
||||||
public static boolean isAlive() {
|
public static boolean isAlive() {
|
||||||
return sIsAlive;
|
return sIsAlive;
|
||||||
@ -148,7 +150,7 @@ public abstract class RingtoneActivity<T> extends AppCompatActivity implements L
|
|||||||
* ringtone and finish us.
|
* ringtone and finish us.
|
||||||
*/
|
*/
|
||||||
protected final void stopAndFinish() {
|
protected final void stopAndFinish() {
|
||||||
stopService(new Intent(this, RingtoneService.class));
|
stopService(new Intent(this, getRingtoneServiceClass()));
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,34 +1,23 @@
|
|||||||
package com.philliphsu.clock2.ringtone;
|
package com.philliphsu.clock2.ringtone;
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.Ringtone;
|
import android.media.Ringtone;
|
||||||
import android.media.RingtoneManager;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.philliphsu.clock2.Alarm;
|
import com.philliphsu.clock2.Alarm;
|
||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.model.AlarmCursor;
|
|
||||||
import com.philliphsu.clock2.model.AlarmsTableManager;
|
|
||||||
import com.philliphsu.clock2.util.AlarmController;
|
|
||||||
import com.philliphsu.clock2.util.AlarmUtils;
|
|
||||||
import com.philliphsu.clock2.util.LocalBroadcastHelper;
|
import com.philliphsu.clock2.util.LocalBroadcastHelper;
|
||||||
|
|
||||||
import static com.philliphsu.clock2.util.DateFormatUtils.formatTime;
|
import java.util.concurrent.TimeUnit;
|
||||||
import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs in the foreground. While it can still be killed by the system, it stays alive significantly
|
* Runs in the foreground. While it can still be killed by the system, it stays alive significantly
|
||||||
@ -40,89 +29,104 @@ import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
|
|||||||
*
|
*
|
||||||
* TOneverDO: Change this to not be a started service!
|
* TOneverDO: Change this to not be a started service!
|
||||||
*/
|
*/
|
||||||
public class RingtoneService extends Service { // TODO: abstract this, make subclasses
|
// TODO: Remove this from manifest, keep only the subclasses.
|
||||||
|
public abstract class RingtoneService<T> extends Service {
|
||||||
private static final String TAG = "RingtoneService";
|
private static final String TAG = "RingtoneService";
|
||||||
|
|
||||||
/* TOneverDO: not private */
|
|
||||||
private static final String ACTION_SNOOZE = "com.philliphsu.clock2.ringtone.action.SNOOZE";
|
|
||||||
private static final String ACTION_DISMISS = "com.philliphsu.clock2.ringtone.action.DISMISS";
|
|
||||||
// public okay
|
// public okay
|
||||||
public static final String ACTION_NOTIFY_MISSED = "com.philliphsu.clock2.ringtone.action.NOTIFY_MISSED";
|
public static final String ACTION_NOTIFY_MISSED = "com.philliphsu.clock2.ringtone.action.NOTIFY_MISSED";
|
||||||
// TODO: Same value as RingtoneActivity.EXTRA_ITEM_ID. Is it important enough to define a different constant?
|
// public static final String EXTRA_ITEM_ID = RingtoneActivity.EXTRA_ITEM_ID;
|
||||||
private static final String EXTRA_ITEM_ID = "com.philliphsu.clock2.ringtone.extra.ITEM_ID";
|
public static final String EXTRA_ITEM = RingtoneActivity.EXTRA_ITEM;
|
||||||
|
|
||||||
private AudioManager mAudioManager;
|
private AudioManager mAudioManager;
|
||||||
@Nullable private Vibrator mVibrator;
|
|
||||||
private Ringtone mRingtone;
|
private Ringtone mRingtone;
|
||||||
private Alarm mAlarm;
|
@Nullable private Vibrator mVibrator;
|
||||||
private String mNormalRingTime;
|
|
||||||
private AlarmController mAlarmController;
|
|
||||||
private boolean mAutoSilenced = false;
|
|
||||||
// TODO: Using Handler for this is ill-suited? Alarm ringing could outlast the
|
// TODO: Using Handler for this is ill-suited? Alarm ringing could outlast the
|
||||||
// application's life. Use AlarmManager API instead.
|
// application's life. Use AlarmManager API instead.
|
||||||
private final Handler mSilenceHandler = new Handler();
|
private final Handler mSilenceHandler = new Handler();
|
||||||
|
|
||||||
private final Runnable mSilenceRunnable = new Runnable() {
|
private final Runnable mSilenceRunnable = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mAutoSilenced = true;
|
onAutoSilenced();
|
||||||
// TODO do we really need to cancel the alarm and intent?
|
// TODO: Consider not finishing the activity, but update
|
||||||
mAlarmController.cancelAlarm(mAlarm, false);
|
// its view to display that this ringing was missed?
|
||||||
finishActivity();
|
finishActivity();
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private final BroadcastReceiver mNotifyMissedReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
// Pretty sure we don't need this anymore...
|
||||||
public void onReceive(Context context, Intent intent) {
|
// private final BroadcastReceiver mNotifyMissedReceiver = new BroadcastReceiver() {
|
||||||
mAutoSilenced = true;
|
// @Override
|
||||||
// TODO: Do we need to call mAlarmController.cancelAlarm()?
|
// public void onReceive(Context context, Intent intent) {
|
||||||
stopSelf();
|
// // TODO: Do we need to call mAlarmController.cancelAlarm()?
|
||||||
// Activity finishes itself
|
// onAutoSilenced();
|
||||||
}
|
// stopSelf();
|
||||||
};
|
// // Activity finishes itself
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
protected abstract void onAutoSilenced();
|
||||||
|
|
||||||
|
protected abstract Ringtone getRingtone();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the notification to show when this Service starts in the foreground
|
||||||
|
*/
|
||||||
|
protected abstract Notification getForegroundNotification();
|
||||||
|
|
||||||
|
protected abstract boolean doesVibrate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of minutes to keep ringing before auto silence
|
||||||
|
*/
|
||||||
|
protected abstract int minutesToAutoSilence();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
final long id = intent.getLongExtra(EXTRA_ITEM_ID, -1);
|
// Play ringtone, if not already playing
|
||||||
if (id < 0)
|
if (mAudioManager == null && mRingtone == null) {
|
||||||
throw new IllegalStateException("No item id set");
|
// TOneverDO: Pass 0 as the first argument
|
||||||
if (intent.getAction() == null) {
|
startForeground(R.id.ringtone_service_notification, getForegroundNotification());
|
||||||
// http://stackoverflow.com/q/8696146/5055032
|
|
||||||
// Start our own thread to load the alarm instead of using a loader,
|
|
||||||
// because Services do not have a built-in LoaderManager (because they have no need for one since
|
|
||||||
// their lifecycle is not complex like in Activities/Fragments) and our
|
|
||||||
// work is simple enough that getting loaders to work here is not
|
|
||||||
// worth the effort.
|
|
||||||
// TODO: Will using the Runnable like this cause a memory leak?
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
AlarmCursor cursor = new AlarmsTableManager(RingtoneService.this).queryItem(id);
|
|
||||||
mAlarm = checkNotNull(cursor.getItem());
|
|
||||||
playRingtone();
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
} else {
|
|
||||||
if (ACTION_SNOOZE.equals(intent.getAction())) {
|
|
||||||
mAlarmController.snoozeAlarm(mAlarm);
|
|
||||||
} else if (ACTION_DISMISS.equals(intent.getAction())) {
|
|
||||||
mAlarmController.cancelAlarm(mAlarm, false); // TODO do we really need to cancel the intent and alarm?
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
// ==========================================================================
|
|
||||||
stopSelf(startId);
|
|
||||||
finishActivity();
|
|
||||||
}
|
|
||||||
|
|
||||||
return START_NOT_STICKY; // If killed while started, don't recreate. Should be sufficient.
|
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
|
||||||
|
// Request audio focus first, so we don't play our ringtone on top of any
|
||||||
|
// other apps that currently have playback.
|
||||||
|
int result = mAudioManager.requestAudioFocus(
|
||||||
|
null, // Playback will likely be short, so don't worry about listening for focus changes
|
||||||
|
AudioManager.STREAM_ALARM,
|
||||||
|
// Request permanent focus, as ringing could last several minutes
|
||||||
|
AudioManager.AUDIOFOCUS_GAIN);
|
||||||
|
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||||
|
mRingtone = getRingtone();
|
||||||
|
// Deprecated, but the alternative AudioAttributes requires API 21
|
||||||
|
mRingtone.setStreamType(AudioManager.STREAM_ALARM);
|
||||||
|
mRingtone.play();
|
||||||
|
if (doesVibrate()) {
|
||||||
|
mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
||||||
|
mVibrator.vibrate(new long[] { // apply pattern
|
||||||
|
0, // millis to wait before turning vibrator on
|
||||||
|
500, // millis to keep vibrator on before turning off
|
||||||
|
500, // millis to wait before turning back on
|
||||||
|
500 // millis to keep on before turning off
|
||||||
|
}, 2 /* start repeating at this index of the array, after one cycle */);
|
||||||
|
}
|
||||||
|
// Schedule auto silence
|
||||||
|
mSilenceHandler.postDelayed(mSilenceRunnable,
|
||||||
|
TimeUnit.MINUTES.toMillis(minutesToAutoSilence()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If killed while started, don't recreate. Should be sufficient.
|
||||||
|
return START_NOT_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
LocalBroadcastHelper.registerReceiver(this, mNotifyMissedReceiver, ACTION_NOTIFY_MISSED);
|
// Pretty sure this won't ever get called anymore...
|
||||||
mAlarmController = new AlarmController(this, null);
|
// LocalBroadcastHelper.registerReceiver(this, mNotifyMissedReceiver, ACTION_NOTIFY_MISSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -134,103 +138,40 @@ public class RingtoneService extends Service { // TODO: abstract this, make subc
|
|||||||
mVibrator.cancel();
|
mVibrator.cancel();
|
||||||
}
|
}
|
||||||
mSilenceHandler.removeCallbacks(mSilenceRunnable);
|
mSilenceHandler.removeCallbacks(mSilenceRunnable);
|
||||||
if (mAutoSilenced) {
|
|
||||||
// Post notification that alarm was missed, or timer expired.
|
|
||||||
// TODO: You should probably do this in the appropriate subclass.
|
|
||||||
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
|
||||||
Notification note = new NotificationCompat.Builder(this)
|
|
||||||
.setContentTitle(getString(R.string.missed_alarm))
|
|
||||||
.setContentText(mNormalRingTime)
|
|
||||||
.setSmallIcon(R.mipmap.ic_launcher)
|
|
||||||
.build();
|
|
||||||
// A tag with the name of the subclass is used in addition to the item's id to prevent
|
|
||||||
// conflicting notifications for items of different class types. Items of any class type
|
|
||||||
// have ids starting from 0.
|
|
||||||
nm.notify(getClass().getName(), mAlarm.intId(), note);
|
|
||||||
}
|
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
LocalBroadcastHelper.unregisterReceiver(this, mNotifyMissedReceiver);
|
// LocalBroadcastHelper.unregisterReceiver(this, mNotifyMissedReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public final IBinder onBind(Intent intent) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playRingtone() {
|
/**
|
||||||
if (mAudioManager == null && mRingtone == null) {
|
* Exposed to let subclasses finish their designated activity from, e.g. a
|
||||||
// TODO: The below call requires a notification, and there is no way to provide one suitable
|
* notification action.
|
||||||
// for both Alarms and Timers. Consider making this class abstract, and have subclasses
|
*/
|
||||||
// implement an abstract method that calls startForeground(). You would then call that
|
protected void finishActivity() {
|
||||||
// method here instead.
|
|
||||||
String title = mAlarm.label().isEmpty()
|
|
||||||
? getString(R.string.alarm)
|
|
||||||
: mAlarm.label();
|
|
||||||
mNormalRingTime = formatTime(this, System.currentTimeMillis()); // now
|
|
||||||
Notification note = new NotificationCompat.Builder(this)
|
|
||||||
// Required contents
|
|
||||||
.setSmallIcon(R.mipmap.ic_launcher) // TODO: alarm icon
|
|
||||||
.setContentTitle(title)
|
|
||||||
.setContentText(mNormalRingTime)
|
|
||||||
.addAction(R.mipmap.ic_launcher,
|
|
||||||
getString(R.string.snooze),
|
|
||||||
getPendingIntent(ACTION_SNOOZE, mAlarm))
|
|
||||||
.addAction(R.mipmap.ic_launcher,
|
|
||||||
getString(R.string.dismiss),
|
|
||||||
getPendingIntent(ACTION_DISMISS, mAlarm))
|
|
||||||
.build();
|
|
||||||
startForeground(R.id.ringtone_service_notification, note); // TOneverDO: Pass 0 as the first argument
|
|
||||||
|
|
||||||
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
|
|
||||||
if (mAlarm.vibrates()) {
|
|
||||||
mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
|
||||||
}
|
|
||||||
// Request audio focus first, so we don't play our ringtone on top of any
|
|
||||||
// other apps that currently have playback.
|
|
||||||
int result = mAudioManager.requestAudioFocus(
|
|
||||||
null, // Playback will likely be short, so don't worry about listening for focus changes
|
|
||||||
AudioManager.STREAM_ALARM,
|
|
||||||
// Request permanent focus, as ringing could last several minutes
|
|
||||||
AudioManager.AUDIOFOCUS_GAIN);
|
|
||||||
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
|
||||||
Uri ringtone = Uri.parse(mAlarm.ringtone());
|
|
||||||
mRingtone = RingtoneManager.getRingtone(this, ringtone);
|
|
||||||
// Deprecated, but the alternative AudioAttributes requires API 21
|
|
||||||
mRingtone.setStreamType(AudioManager.STREAM_ALARM);
|
|
||||||
mRingtone.play();
|
|
||||||
if (mVibrator != null) {
|
|
||||||
mVibrator.vibrate(new long[] { // apply pattern
|
|
||||||
0, // millis to wait before turning vibrator on
|
|
||||||
500, // millis to keep vibrator on before turning off
|
|
||||||
500, // millis to wait before turning back on
|
|
||||||
500 // millis to keep on before turning off
|
|
||||||
}, 2 /* start repeating at this index of the array, after one cycle */);
|
|
||||||
}
|
|
||||||
scheduleAutoSilence();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: For Timers, update the foreground notification to say "timer expired". Also,
|
|
||||||
// if Alarms and Timers will have distinct settings for the minutes to silence after, then consider
|
|
||||||
// doing this in the respective subclass of this service.
|
|
||||||
private void scheduleAutoSilence() {
|
|
||||||
int minutes = AlarmUtils.minutesToSilenceAfter(this);
|
|
||||||
mSilenceHandler.postDelayed(mSilenceRunnable, /*minutes * 60000*/70000); // TODO: uncomment
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finishActivity() {
|
|
||||||
// I think this will be received by all instances of RingtoneActivity
|
// I think this will be received by all instances of RingtoneActivity
|
||||||
// subclasses in memory.. but since we realistically expect only one
|
// subclasses in memory.. but since we realistically expect only one
|
||||||
// instance alive at any given time, we don't need to worry about having
|
// 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.
|
// to restrict the broadcast to only the subclass that's alive.
|
||||||
|
// TODO: If we cared, we could write an abstract method called getFinishAction()
|
||||||
|
// that subclasses implement, and call that here instead. The subclass of
|
||||||
|
// RingtoneActivity would define their own ACTION_FINISH constants, and
|
||||||
|
// the RingtoneService subclass retrieves that constant and returns it to us.
|
||||||
LocalBroadcastHelper.sendBroadcast(this, RingtoneActivity.ACTION_FINISH);
|
LocalBroadcastHelper.sendBroadcast(this, RingtoneActivity.ACTION_FINISH);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PendingIntent getPendingIntent(@NonNull String action, Alarm alarm) {
|
/**
|
||||||
|
* Exposed so subclasses can create their notification actions.
|
||||||
|
*/
|
||||||
|
// TODO: Consider changing Alarm param to int requestCode param.
|
||||||
|
protected final PendingIntent getPendingIntent(@NonNull String action, Alarm alarm) {
|
||||||
Intent intent = new Intent(this, getClass())
|
Intent intent = new Intent(this, getClass())
|
||||||
.setAction(action)
|
.setAction(action);
|
||||||
.putExtra(EXTRA_ITEM_ID, alarm.id());
|
// TODO: Why do we need this?
|
||||||
|
// .putExtra(EXTRA_ITEM_ID, alarm.id());
|
||||||
return PendingIntent.getService(
|
return PendingIntent.getService(
|
||||||
this,
|
this,
|
||||||
alarm.intId(),
|
alarm.intId(),
|
||||||
|
|||||||
@ -13,8 +13,8 @@ import com.philliphsu.clock2.PendingAlarmScheduler;
|
|||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.UpcomingAlarmReceiver;
|
import com.philliphsu.clock2.UpcomingAlarmReceiver;
|
||||||
import com.philliphsu.clock2.alarms.AlarmActivity;
|
import com.philliphsu.clock2.alarms.AlarmActivity;
|
||||||
|
import com.philliphsu.clock2.alarms.AlarmRingtoneService;
|
||||||
import com.philliphsu.clock2.model.AlarmsTableManager;
|
import com.philliphsu.clock2.model.AlarmsTableManager;
|
||||||
import com.philliphsu.clock2.ringtone.RingtoneService;
|
|
||||||
|
|
||||||
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
|
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
|
||||||
import static android.app.PendingIntent.FLAG_NO_CREATE;
|
import static android.app.PendingIntent.FLAG_NO_CREATE;
|
||||||
@ -146,7 +146,7 @@ public final class AlarmController {
|
|||||||
save(alarm);
|
save(alarm);
|
||||||
|
|
||||||
// If service is not running, nothing happens
|
// If service is not running, nothing happens
|
||||||
mAppContext.stopService(new Intent(mAppContext, RingtoneService.class));
|
mAppContext.stopService(new Intent(mAppContext, AlarmRingtoneService.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void snoozeAlarm(Alarm alarm) {
|
public void snoozeAlarm(Alarm alarm) {
|
||||||
@ -184,7 +184,7 @@ public final class AlarmController {
|
|||||||
private PendingIntent alarmIntent(Alarm alarm, boolean retrievePrevious) {
|
private PendingIntent alarmIntent(Alarm alarm, boolean retrievePrevious) {
|
||||||
// TODO: Use appropriate subclass instead
|
// TODO: Use appropriate subclass instead
|
||||||
Intent intent = new Intent(mAppContext, AlarmActivity.class)
|
Intent intent = new Intent(mAppContext, AlarmActivity.class)
|
||||||
.putExtra(AlarmActivity.EXTRA_ITEM_ID, alarm.id());
|
.putExtra(AlarmActivity.EXTRA_ITEM, alarm);
|
||||||
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
|
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
|
||||||
PendingIntent pi = getActivity(mAppContext, alarm.intId(), intent, flag);
|
PendingIntent pi = getActivity(mAppContext, alarm.intId(), intent, flag);
|
||||||
// Even when we try to retrieve a previous instance that actually did exist,
|
// Even when we try to retrieve a previous instance that actually did exist,
|
||||||
|
|||||||
@ -14,8 +14,8 @@ import com.philliphsu.clock2.PendingAlarmScheduler;
|
|||||||
import com.philliphsu.clock2.R;
|
import com.philliphsu.clock2.R;
|
||||||
import com.philliphsu.clock2.UpcomingAlarmReceiver;
|
import com.philliphsu.clock2.UpcomingAlarmReceiver;
|
||||||
import com.philliphsu.clock2.alarms.AlarmActivity;
|
import com.philliphsu.clock2.alarms.AlarmActivity;
|
||||||
|
import com.philliphsu.clock2.alarms.AlarmRingtoneService;
|
||||||
import com.philliphsu.clock2.model.AlarmsTableManager;
|
import com.philliphsu.clock2.model.AlarmsTableManager;
|
||||||
import com.philliphsu.clock2.ringtone.RingtoneService;
|
|
||||||
|
|
||||||
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
|
import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
|
||||||
import static android.app.PendingIntent.FLAG_NO_CREATE;
|
import static android.app.PendingIntent.FLAG_NO_CREATE;
|
||||||
@ -140,7 +140,7 @@ public final class AlarmUtils {
|
|||||||
save(c, a);
|
save(c, a);
|
||||||
|
|
||||||
// If service is not running, nothing happens
|
// If service is not running, nothing happens
|
||||||
c.stopService(new Intent(c, RingtoneService.class));
|
c.stopService(new Intent(c, AlarmRingtoneService.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void snoozeAlarm(Context c, Alarm a) {
|
public static void snoozeAlarm(Context c, Alarm a) {
|
||||||
@ -181,7 +181,7 @@ public final class AlarmUtils {
|
|||||||
private static PendingIntent alarmIntent(Context context, Alarm alarm, boolean retrievePrevious) {
|
private static PendingIntent alarmIntent(Context context, Alarm alarm, boolean retrievePrevious) {
|
||||||
// TODO: Use appropriate subclass instead
|
// TODO: Use appropriate subclass instead
|
||||||
Intent intent = new Intent(context, AlarmActivity.class)
|
Intent intent = new Intent(context, AlarmActivity.class)
|
||||||
.putExtra(AlarmActivity.EXTRA_ITEM_ID, alarm.id());
|
.putExtra(AlarmActivity.EXTRA_ITEM, alarm);
|
||||||
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
|
int flag = retrievePrevious ? FLAG_NO_CREATE : FLAG_CANCEL_CURRENT;
|
||||||
PendingIntent pi = getActivity(context, alarm.intId(), intent, flag);
|
PendingIntent pi = getActivity(context, alarm.intId(), intent, flag);
|
||||||
// Even when we try to retrieve a previous instance that actually did exist,
|
// Even when we try to retrieve a previous instance that actually did exist,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user