Home | History | Annotate | Download | only in shadows
      1 package org.robolectric.shadows;
      2 
      3 import static android.app.AlarmManager.RTC_WAKEUP;
      4 import static android.os.Build.VERSION_CODES.KITKAT;
      5 import static android.os.Build.VERSION_CODES.LOLLIPOP;
      6 import static android.os.Build.VERSION_CODES.M;
      7 
      8 import android.annotation.TargetApi;
      9 import android.app.AlarmManager;
     10 import android.app.AlarmManager.AlarmClockInfo;
     11 import android.app.PendingIntent;
     12 import android.content.Intent;
     13 import java.util.ArrayList;
     14 import java.util.Collections;
     15 import java.util.List;
     16 import org.robolectric.Shadows;
     17 import org.robolectric.annotation.Implementation;
     18 import org.robolectric.annotation.Implements;
     19 
     20 @SuppressWarnings({"UnusedDeclaration"})
     21 @Implements(AlarmManager.class)
     22 public class ShadowAlarmManager {
     23 
     24   private final List<ScheduledAlarm> scheduledAlarms = new ArrayList<>();
     25 
     26   @Implementation
     27   public void set(int type, long triggerAtTime, PendingIntent operation) {
     28     internalSet(type, triggerAtTime, 0L, operation, null);
     29   }
     30 
     31   @Implementation(minSdk = KITKAT)
     32   public void setExact(int type, long triggerAtTime, PendingIntent operation) {
     33     internalSet(type, triggerAtTime, 0L, operation, null);
     34   }
     35 
     36   @Implementation(minSdk = KITKAT)
     37   public void setWindow(int type, long windowStartMillis, long windowLengthMillis,
     38       PendingIntent operation) {
     39     internalSet(type, windowStartMillis, 0L, operation, null);
     40   }
     41 
     42   @Implementation(minSdk = M)
     43   public void setAndAllowWhileIdle(int type, long triggerAtTime, PendingIntent operation) {
     44     internalSet(type, triggerAtTime, 0L, operation, null);
     45   }
     46 
     47   @Implementation(minSdk = M)
     48   public void setExactAndAllowWhileIdle(int type, long triggerAtTime, PendingIntent operation) {
     49     internalSet(type, triggerAtTime, 0L, operation, null);
     50   }
     51 
     52   @Implementation
     53   public void setRepeating(int type, long triggerAtTime, long interval, PendingIntent operation) {
     54     internalSet(type, triggerAtTime, interval, operation, null);
     55   }
     56 
     57   @Implementation
     58   public void setInexactRepeating(int type, long triggerAtMillis, long intervalMillis,
     59       PendingIntent operation) {
     60     internalSet(type, triggerAtMillis, intervalMillis, operation, null);
     61   }
     62 
     63   @Implementation(minSdk = LOLLIPOP)
     64   public void setAlarmClock(AlarmClockInfo info, PendingIntent operation) {
     65     internalSet(RTC_WAKEUP, info.getTriggerTime(), 0L, operation, info.getShowIntent());
     66   }
     67 
     68   @Implementation(minSdk = LOLLIPOP)
     69   public AlarmClockInfo getNextAlarmClock() {
     70     for (ScheduledAlarm scheduledAlarm : scheduledAlarms) {
     71       AlarmClockInfo alarmClockInfo = scheduledAlarm.getAlarmClockInfo();
     72       if (alarmClockInfo != null) {
     73         return alarmClockInfo;
     74       }
     75     }
     76     return null;
     77   }
     78 
     79   private void internalSet(int type, long triggerAtTime, long interval, PendingIntent operation,
     80       PendingIntent showIntent) {
     81     cancel(operation);
     82     scheduledAlarms.add(new ScheduledAlarm(type, triggerAtTime, interval, operation, showIntent));
     83     Collections.sort(scheduledAlarms);
     84   }
     85 
     86   /**
     87    * @return the next scheduled alarm after consuming it
     88    */
     89   public ScheduledAlarm getNextScheduledAlarm() {
     90     if (scheduledAlarms.isEmpty()) {
     91       return null;
     92     } else {
     93       return scheduledAlarms.remove(0);
     94     }
     95   }
     96 
     97   /**
     98    * @return the most recently scheduled alarm without consuming it
     99    */
    100   public ScheduledAlarm peekNextScheduledAlarm() {
    101     if (scheduledAlarms.isEmpty()) {
    102       return null;
    103     } else {
    104       return scheduledAlarms.get(0);
    105     }
    106   }
    107 
    108   /**
    109    * @return all scheduled alarms
    110    */
    111   public List<ScheduledAlarm> getScheduledAlarms() {
    112     return scheduledAlarms;
    113   }
    114 
    115   @Implementation
    116   public void cancel(PendingIntent operation) {
    117     ShadowPendingIntent shadowPendingIntent = Shadows.shadowOf(operation);
    118     final Intent toRemove = shadowPendingIntent.getSavedIntent();
    119     final int requestCode = shadowPendingIntent.getRequestCode();
    120     for (ScheduledAlarm scheduledAlarm : scheduledAlarms) {
    121       ShadowPendingIntent scheduledShadowPendingIntent = Shadows.shadowOf(scheduledAlarm.operation);
    122       final Intent scheduledIntent = scheduledShadowPendingIntent.getSavedIntent();
    123       final int scheduledRequestCode = scheduledShadowPendingIntent.getRequestCode();
    124       if (scheduledIntent.filterEquals(toRemove) && scheduledRequestCode == requestCode) {
    125         scheduledAlarms.remove(scheduledAlarm);
    126         break;
    127       }
    128     }
    129   }
    130 
    131   /**
    132    * Container object to hold a PendingIntent and parameters describing when to send it.
    133    */
    134   public static class ScheduledAlarm implements Comparable<ScheduledAlarm> {
    135 
    136     public final int type;
    137     public final long triggerAtTime;
    138     public final long interval;
    139     public final PendingIntent operation;
    140 
    141     // A non-null showIntent implies this alarm has a user interface. (i.e. in an alarm clock app)
    142     public final PendingIntent showIntent;
    143 
    144     public ScheduledAlarm(int type, long triggerAtTime, PendingIntent operation,
    145         PendingIntent showIntent) {
    146       this(type, triggerAtTime, 0, operation, showIntent);
    147     }
    148 
    149     public ScheduledAlarm(int type, long triggerAtTime, long interval, PendingIntent operation,
    150         PendingIntent showIntent) {
    151       this.type = type;
    152       this.triggerAtTime = triggerAtTime;
    153       this.operation = operation;
    154       this.interval = interval;
    155       this.showIntent = showIntent;
    156     }
    157 
    158     @TargetApi(LOLLIPOP)
    159     public AlarmClockInfo getAlarmClockInfo() {
    160       return showIntent == null ? null : new AlarmClockInfo(triggerAtTime, showIntent);
    161     }
    162 
    163     @Override
    164     public int compareTo(ScheduledAlarm scheduledAlarm) {
    165       return Long.compare(triggerAtTime, scheduledAlarm.triggerAtTime);
    166     }
    167   }
    168 }
    169