Search code examples
androidandroid-intentalarmmanagerclockandroid-pendingintent

New alarm with different data overrides already set alarm


I'm creating a simple app that will turn my wifi off/on at specified time in future. For example I have wifi on and I want to switch its state (turn it off) at 10PM and switch back and 8 AM (Turn on). To do that, I've written some block of code which has one bug. Well, when I set first alarm (let's accord to the example above) at 10PM and second at 8AM only the second one will fire. According to the answer here: Editing scheduled pending intends about pending intents I checked those alarms' pending intents while setting them and they were different.

Okay, I'll provide some code, I will not give whole bunch of code to set up calendar because the bug is not there.

WiFi.class

 //This class also stores and loads scheduled alarm from database, 
 //that's why here is variable Uri = mUri. 
    private void setAlarm(){
    ContentValues values = new ContentValues();
    values.put(AlarmReminderEntry.KEY_TITLE, title);
    values.put(AlarmReminderEntry.KEY_DATE, mDate);
    values.put(AlarmReminderEntry.KEY_TIME, mTime);
    values.put(AlarmReminderEntry.KEY_REPEAT, repeat);
    values.put(AlarmReminderEntry.KEY_YEAR, mYear);
    values.put(AlarmReminderEntry.KEY_MONTH, mMonth);
    values.put(AlarmReminderEntry.KEY_DAY, mDay);
    values.put(AlarmReminderEntry.KEY_HOUR, mHour);
    values.put(AlarmReminderEntry.KEY_MINUTE, mMinute);
    values.put(AlarmReminderEntry.KEY_REPEAT_NO, mRepeatNo);

    if (mUri == null) {
        Uri newUri = 
  getContentResolver().insert(AlarmReminderEntry.CONTENT_URI, values);
    if (newUri == null) {
            Toast.makeText(context, "error saving alarm", 
                Toast.LENGTH_SHORT).show();
} else {
//WiFiScheduler() is an instance of another class, see code below
//setAlarm(Context context, long timeInMilis, Uri uri)
     new WiFiScheduler().setAlarm(getApplicationContext(), 
 calendar.getTimeInMillis(), mUri);
 Toast.makeText(context, "Alarm will fire one time 
 only", Toast.LENGTH_SHORT).show();
                Log.v("Alarm time", 
String.valueOf(calendar.getTime()));
}

WifiScheduler.class --> class where the method setAlarm is called from. public class WiFiScheduler {

public void setAlarm(Context context, long alarmTime, Uri 
reminderTask) {
            AlarmManager alarmManager = (AlarmManager) 
                   context.getSystemService(Context.ALARM_SERVICE); 
    Log.v("AlarmManager", "Initializing AM");

//Here in PendingIntent instance there is another class called called
// WiFiService
    PendingIntent operation =
            WiFiService.getReminderPendingIntent
                           (context,reminderTask);
    if (Build.VERSION.SDK_INT >= 23) {
        assert alarmManager != null;
 alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, 
                                           alarmTime, operation);
    } else {
        assert alarmManager != null;
        alarmManager.setExact(AlarmManager.RTC_WAKEUP,
                                 alarmTime,operation);
    }
  }
}

And finally WiFiService.class

 public class WiFiService extends IntentService {
 private static final String TAG = WiFiService.class.getSimpleName();
 public static PendingIntent getReminderPendingIntent(Context context, 
 Uri uri) {
    Intent action = new Intent(context, WiFiService.class);
    action.setData(uri);
    Log.v(TAG, "uri passed into intent");
    String pi = String.valueOf(PendingIntent.getService(context, 0, 
 action, PendingIntent.FLAG_UPDATE_CURRENT));
    Log.v(TAG, pi); <-- 

Those outputs of 2 alarms I'll give in the end of this post, but they were different

    return PendingIntent.getService(context, 0, action, 
PendingIntent.FLAG_UPDATE_CURRENT);
}


public WiFiService() {
    super(TAG);
}

@Override
protected void onHandleIntent(@Nullable Intent intent) {
    WifiManager wifiManager = (WifiManager) 
 getApplicationContext().getSystemService(WIFI_SERVICE);
    if (wifiManager.isWifiEnabled()) {
        wifiManager.setWifiEnabled(false);
        Log.v(TAG, "Wifi is turning off");
    } else {
        wifiManager.setWifiEnabled(true);
        Log.v(TAG, "Wifi is turning on");
    }
    Calendar calendar = Calendar.getInstance();
    int h = calendar.get(Calendar.HOUR_OF_DAY);
    int m = calendar.get(Calendar.MINUTE);
    int ms = calendar.get(Calendar.SECOND);
    Log.v("Time", String.valueOf(h) + ":" + String.valueOf(m) + ":" + 
  String.valueOf(ms));
  }
}

WiFiService.class defined in Manifest as:

service android:name=".WiFiScheduler.WiFiService"
android:exported="false"

No brackets above, page didn't want to accept them, in the code obviously they are.

And now outputs of PendingIntent.getBroadcast, read twice, first after first alarm was set and second after second was set.

V/WiFiService: PendingIntent{d3aacca: android.os.BinderProxy@dd4e3b}
V/WiFiService: PendingIntent{3acdbb: android.os.BinderProxy@d5ac2d8}

So, where may I did an error?

And for the end, may I ask where can I find Oreo stock alarm app source code or app alike? (It must be written for Marshmallow and above, most apps on GitHub are written for Lollipop and above, I found just 2 for Nougat)

Bests


Solution

  • Check the Uri that you put in the Intent and ensure that the 2 Uris are different for the 2 different calls. Also, make absolutely sure that the times are correct that you pass to AlarmManager.

    The other thing you can do is, after you set each alarm, do adb shell dumpsys alarm and check that the alarm has been set with the correct values. See this question if you need help understanding how to read the output of adb shell dumpsys alarm