How to stop alarm from executing after PendingInte

2019-07-17 04:38发布

问题:

Before closing this issue or marking as duplicate based on the title, it is different from the regular "cancel alarm using AlarmManager and PendingIntent" questions.

I am capable of creating and cancelling pending intents, as long as they are set for a time in the future and haven't gone off yet. I'm testing this using the following terminal command to view the PendingIntents before creating an alarm as well as after:

adb shell dumpsys alarm

Here is my code for scheduling alarms in my custom Alarm class:

/**
 * Schedules a PendingIntent for the alarm.
 * @param context Activity context
 */
public void scheduleAlarm(Context context) {
    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context, MyBroadcastReceiver.class);

    Gson g = new Gson();
    String s = g.toJson(this);
    intent.putExtra("alarm", s);
    String id = this.getId().replaceAll("[^0-9]+", "");
    PendingIntent alarmIntent = PendingIntent.getBroadcast(context, Integer.parseInt(id), intent, PendingIntent.FLAG_UPDATE_CURRENT);

    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR_OF_DAY, this.getHour());
    calendar.set(Calendar.MINUTE, this.getMinute());

    long calendarTime = calendar.getTimeInMillis();
    am.setExact(AlarmManager.RTC_WAKEUP, calendarTime, alarmIntent);
}

Not surprisingly, before creating an alarm, there was no pending intent regarding my app's alarms in the terminal output. After creating the alarm, there was 1 pending intent related to my app in the terminal output, as seen below:

+Batch{b28a2db num=1 start=619295497 end=619385497}: + RTC #0: Alarm{24e4178 tag

alarm:com.google.android.location.internal.action.ULR_BAROMETER_READ_ALARM type 1 when 1501206840000 com.google.android.gms} +

tag=alarm:com.google.android.location.internal.action.ULR_BAROMETER_READ_ALARM + type=1 whenElapsed=+1m59s428ms when=2017-07-27 21:54:00 + window=+1m30s0ms repeatInterval=120000 count=0 flags=0x0 +

operation=PendingIntent{cb99ddd: PendingIntentRecord{f0fbd52

com.google.android.gms startService}}

Note I don't have access to my home computer right now so I can't post exactly what it will be for my app, so I just grabbed the PendingIntent for a different app but it is the same structure.

I cancelled the alarm before it went off using the code found below, reran the adb command from before and the pending intent was no longer in the terminal output so everything worked great.

Here is my code for cancelling alarms:

/**
 * Cancels the PendingIntent for the alarm.
 * @param context
 */
public void cancelAlarm(Context context) {
    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(context, MyBroadcastReceiver.class);
    intent.putExtra("alarm", this);
    String id = this.getId().replaceAll("[^0-9]+", "");
    PendingIntent alarmIntent = PendingIntent.getBroadcast(context, Integer.parseInt(id), intent, 0);
    alarmIntent.cancel();
    am.cancel(alarmIntent);
}

Now, if the PendingIntent was reached (BroadcastReceiver runs its onReceive() code and opens a custom activity), I get the following entry in the terminal output when I rerun that adb command:

  • u0a149:com.my.app +172ms running, 0 wakeups:
    • +172ms 0 wakes 3 alarms, last -5d8h25m0s423ms:
    • alarm:com.google.firebase.INSTANCE_ID_EVENT

but I can no longer see the PendingIntent, as expected. Whether I run the cancelAlarm() code or not, this entry will always stay here.

The result of this is that whenever I open the app after the PendingIntent has "gone off" and my BroadcastReceiver class runs it's code, the app acts as if the alarm is continually going off so it does this repeatedly, but like I said there's no PendingIntent entry in the adb output. I want to know how to shut this alarm off or "dismiss" it if you will.

Here is my BroadcastReceiver class:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        String alarm = intent.getStringExtra("alarm");

        Intent myIntent = new Intent();
        Toast.makeText(context, "Alarm is 1: " + alarm, Toast.LENGTH_SHORT).show();
        myIntent.setClassName("com.my.package.name", "com.my.package.name.AlarmReceivedActivity");
        myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        myIntent.putExtra("alarm", alarm);

        context.startActivity(myIntent);
    }
}

and here's my AlarmReceivedActivity:

public class AlarmReceivedActivity extends AppCompatActivity {

    private Alarm alarmReceived;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alarm_received);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        TextView tvTime = (TextView) findViewById(R.id.tv_time);
        String lTime = "11:05";
        tvTime.setText(lTime);

        Intent intent = getIntent();
        String s = intent.getStringExtra("alarm");
        Toast.makeText(getApplicationContext(), "Alarm is: " + s, Toast.LENGTH_SHORT).show();
        Gson g = new Gson();
        alarmReceived = g.fromJson(s, Alarm.class);

        Uri ringtoneUri = Uri.parse(alarmReceived.getRingtone());
        Toast.makeText(getApplicationContext(), "Ringtone is: " + alarmReceived.getRingtone(), Toast.LENGTH_SHORT).show();
        try {
            MediaPlayer mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setDataSource(this, ringtoneUri);
            final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
            if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
                mMediaPlayer.setLooping(false);
                mMediaPlayer.prepare();
                mMediaPlayer.start();
            }
        } catch (Exception e) {
            Toast.makeText(getApplicationContext(), "Failed to play ringtone", Toast.LENGTH_SHORT).show();
        }
    }

    public void dismissButtonClick(View view) {
        Context context = getApplicationContext();
        alarmReceived.cancelAlarm(context);
        alarmReceived.setIsSet(false);
        writeAlarmToSharedPrefs(alarmReceived, context);
        alarmReceived.cancelAlarm(context);
        System.exit(0);
    }

    private void writeAlarmToSharedPrefs(Alarm alarmReceived, Context context) {
        String alarm = getAlarmObjectAsJson(alarmReceived);
        SharedPreferences sPrefs = getApplicationContext().getSharedPreferences("Sleepin", MODE_PRIVATE);
        SharedPreferences.Editor pe = sPrefs.edit();
        pe.putString(alarmReceived.getId(), alarm);
        pe.apply();
    }

    private String getAlarmObjectAsJson(Alarm a) {
        Gson g = new Gson();
        return g.toJson(a);
    }

    public void snoozeButtonClick(View view) {

    }
}

So I have a couple questions:

1) Since the PendingIntent has been reached, what is this entry in the adb command output referred to as? A "ReachedPendingIntent" (obviously not called this but I hope you get where I'm going with this).

2) How do I stop my app from running the BroadcastReceiver code? My workaround right now is to clear the app's data and cache. After I do this, the second entry from the adb command doesn't appear and the BroadcastReceiver stops running it's code.