Fixed alarm not ringing because of RingtoneActivity being resumed on next launch and not created
This commit is contained in:
parent
1ea774f21b
commit
53d5eed670
@ -24,8 +24,6 @@
|
|||||||
android:label="@string/title_activity_ringtone"
|
android:label="@string/title_activity_ringtone"
|
||||||
android:theme="@style/AppTheme.NoActionBar"
|
android:theme="@style/AppTheme.NoActionBar"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:finishOnTaskLaunch="true"
|
|
||||||
android:launchMode="singleTask"
|
|
||||||
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
|
android:taskAffinity="com.philliphsu.clock2.RingtoneActivity">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
package com.philliphsu.clock2.ringtone;
|
package com.philliphsu.clock2.ringtone;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
@ -20,7 +24,8 @@ import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
|
|||||||
* TODO: Make this abstract and make appropriate subclasses for Alarms and Timers.
|
* TODO: Make this abstract and make appropriate subclasses for Alarms and Timers.
|
||||||
* TODO: Implement dismiss and extend logic here.
|
* TODO: Implement dismiss and extend logic here.
|
||||||
*/
|
*/
|
||||||
public class RingtoneActivity extends AppCompatActivity {
|
public class RingtoneActivity extends AppCompatActivity implements RingtoneService.RingtoneCallback {
|
||||||
|
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";
|
||||||
@ -37,12 +42,15 @@ public class RingtoneActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
mAlarm = checkNotNull(AlarmsRepository.getInstance(this).getItem(id));
|
mAlarm = checkNotNull(AlarmsRepository.getInstance(this).getItem(id));
|
||||||
|
|
||||||
|
// 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.
|
||||||
AlarmUtils.removeUpcomingAlarmNotification(this, mAlarm);
|
AlarmUtils.removeUpcomingAlarmNotification(this, mAlarm);
|
||||||
|
|
||||||
// Play the ringtone
|
// Play the ringtone
|
||||||
Intent intent = new Intent(this, RingtoneService.class)
|
Intent intent = new Intent(this, RingtoneService.class)
|
||||||
.putExtra(EXTRA_ITEM_ID, mAlarm.id());
|
.putExtra(EXTRA_ITEM_ID, mAlarm.id());
|
||||||
startService(intent);
|
startService(intent);
|
||||||
|
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
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() {
|
||||||
@ -84,6 +92,24 @@ public class RingtoneActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
// Capture the back press and return. We want to limit the user's options for leaving
|
||||||
|
// this activity as much as possible.
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
unbindService(mConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutoSilence() {
|
||||||
|
// Service should have stopped itself by this point
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
private void snooze() {
|
private void snooze() {
|
||||||
mAlarm.snooze(1); // TODO: Read snooze duration from prefs
|
mAlarm.snooze(1); // TODO: Read snooze duration from prefs
|
||||||
AlarmUtils.scheduleAlarm(this, mAlarm);
|
AlarmUtils.scheduleAlarm(this, mAlarm);
|
||||||
@ -97,4 +123,19 @@ public class RingtoneActivity extends AppCompatActivity {
|
|||||||
// TODO: Do we need to cancel the PendingIntent and the alarm in AlarmManager?
|
// TODO: Do we need to cancel the PendingIntent and the alarm in AlarmManager?
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RingtoneService mBoundService; // TODO: Don't need? Only used locally in ServiceConnection.
|
||||||
|
|
||||||
|
private ServiceConnection mConnection = new ServiceConnection() {
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
|
mBoundService = ((RingtoneService.RingtoneBinder) service).getService();
|
||||||
|
mBoundService.setRingtoneCallback(RingtoneActivity.this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
mBoundService = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@ -9,6 +9,7 @@ import android.media.AudioManager;
|
|||||||
import android.media.Ringtone;
|
import android.media.Ringtone;
|
||||||
import android.media.RingtoneManager;
|
import android.media.RingtoneManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Binder;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
@ -28,6 +29,17 @@ import static com.philliphsu.clock2.util.Preconditions.checkNotNull;
|
|||||||
* of the RingtoneService will be tied to that of its RingtoneActivity because users are not likely to
|
* of the RingtoneService will be tied to that of its RingtoneActivity because users are not likely to
|
||||||
* navigate away from the Activity without making an action. But if they do accidentally navigate away,
|
* navigate away from the Activity without making an action. But if they do accidentally navigate away,
|
||||||
* they have plenty of time to make the desired action via the notification.
|
* they have plenty of time to make the desired action via the notification.
|
||||||
|
*
|
||||||
|
* This is both a started and bound service. See https://developer.android.com/guide/components/bound-services.html#Lifecycle
|
||||||
|
* "... the service runs until the service stops itself with stopSelf() or another component
|
||||||
|
* calls stopService(), regardless of whether it is bound to any clients."
|
||||||
|
* The regardless phrase didn't work for me. I had to unbind in RingtoneActivity first before calling
|
||||||
|
* stopSelf() on this service for the ringtone to stop playing.
|
||||||
|
* TODO: Consider making this purely a bound service, so you don't have to bind/unbind AND start/stop
|
||||||
|
* manually. Instead of implementing onStartCommand() and calling startService(), you would write a public
|
||||||
|
* method that the activity calls to start playing the ringtone. When the activity calls its onDestroy(), it unbinds
|
||||||
|
* itself from this service, and the system will know to destroy this service instead of you manually
|
||||||
|
* calling stopSelf() or stopService().
|
||||||
*/
|
*/
|
||||||
public class RingtoneService extends Service { // TODO: abstract this, make subclasses
|
public class RingtoneService extends Service { // TODO: abstract this, make subclasses
|
||||||
private static final String TAG = "RingtoneService";
|
private static final String TAG = "RingtoneService";
|
||||||
@ -37,6 +49,7 @@ public class RingtoneService extends Service { // TODO: abstract this, make subc
|
|||||||
private Alarm mAlarm;
|
private Alarm mAlarm;
|
||||||
private String mNormalRingTime;
|
private String mNormalRingTime;
|
||||||
private boolean mAutoSilenced = false;
|
private boolean mAutoSilenced = false;
|
||||||
|
private RingtoneCallback mRingtoneCallback;
|
||||||
// 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();
|
||||||
@ -44,9 +57,17 @@ public class RingtoneService extends Service { // TODO: abstract this, make subc
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mAutoSilenced = true;
|
mAutoSilenced = true;
|
||||||
|
if (mRingtoneCallback != null) {
|
||||||
|
// Finish the activity, which fires onDestroy() and then unbinds itself from this service.
|
||||||
|
// All clients must be unbound before stopSelf() (and stopService()?) will succeed.
|
||||||
|
// See https://developer.android.com/guide/components/bound-services.html#Lifecycle
|
||||||
|
// Figure 1 regarding the lifecycle of started and bound services.
|
||||||
|
mRingtoneCallback.onAutoSilence();
|
||||||
|
}
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private final IBinder mBinder = new RingtoneBinder();
|
||||||
|
|
||||||
// TODO: Apply the setting for "Silence after" here by using an AlarmManager to
|
// TODO: Apply the setting for "Silence after" here by using an AlarmManager to
|
||||||
// schedule an alarm in the future to stop this service, and also update the foreground
|
// schedule an alarm in the future to stop this service, and also update the foreground
|
||||||
@ -121,7 +142,22 @@ public class RingtoneService extends Service { // TODO: abstract this, make subc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBinder onBind(Intent intent) {
|
public IBinder onBind(Intent intent) {
|
||||||
return null; // Binding to this service is not supported
|
return mBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRingtoneCallback(RingtoneCallback callback) {
|
||||||
|
mRingtoneCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Needed so clients can get the Service instance and e.g. call setRingtoneCallback().
|
||||||
|
public class RingtoneBinder extends Binder {
|
||||||
|
RingtoneService getService() {
|
||||||
|
return RingtoneService.this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface RingtoneCallback {
|
||||||
|
void onAutoSilence();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleAutoSilence() {
|
private void scheduleAutoSilence() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user