1/* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package androidx.work.impl.background.systemalarm; 18 19import static android.app.AlarmManager.RTC_WAKEUP; 20 21import android.app.AlarmManager; 22import android.app.PendingIntent; 23import android.content.Context; 24import android.content.Intent; 25import android.os.Build; 26import android.support.annotation.NonNull; 27import android.support.annotation.RestrictTo; 28import android.util.Log; 29 30import androidx.work.impl.WorkDatabase; 31import androidx.work.impl.WorkManagerImpl; 32import androidx.work.impl.model.SystemIdInfo; 33import androidx.work.impl.model.SystemIdInfoDao; 34import androidx.work.impl.utils.IdGenerator; 35 36/** 37 * A common class for managing Alarms. 38 * 39 * @hide 40 */ 41@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 42class Alarms { 43 44 private static final String TAG = "Alarms"; 45 46 /** 47 * Sets an exact alarm after cancelling any existing alarms for the given id. 48 * 49 * @param context The application {@link Context}. 50 * @param workManager The instance of {@link WorkManagerImpl}. 51 * @param workSpecId The {@link androidx.work.impl.model.WorkSpec} identifier. 52 * @param triggerAtMillis Determines when to trigger the Alarm. 53 */ 54 public static void setAlarm( 55 @NonNull Context context, 56 @NonNull WorkManagerImpl workManager, 57 @NonNull String workSpecId, 58 long triggerAtMillis) { 59 60 WorkDatabase workDatabase = workManager.getWorkDatabase(); 61 SystemIdInfoDao systemIdInfoDao = workDatabase.systemIdInfoDao(); 62 SystemIdInfo systemIdInfo = systemIdInfoDao.getSystemIdInfo(workSpecId); 63 if (systemIdInfo != null) { 64 cancelExactAlarm(context, workSpecId, systemIdInfo.systemId); 65 setExactAlarm(context, workSpecId, systemIdInfo.systemId, triggerAtMillis); 66 } else { 67 IdGenerator idGenerator = new IdGenerator(context); 68 int alarmId = idGenerator.nextAlarmManagerId(); 69 SystemIdInfo newSystemIdInfo = new SystemIdInfo(workSpecId, alarmId); 70 systemIdInfoDao.insertSystemIdInfo(newSystemIdInfo); 71 setExactAlarm(context, workSpecId, alarmId, triggerAtMillis); 72 } 73 } 74 75 /** 76 * Cancels an existing alarm and removes the {@link SystemIdInfo}. 77 * 78 * @param context The application {@link Context}. 79 * @param workManager The instance of {@link WorkManagerImpl}. 80 * @param workSpecId The {@link androidx.work.impl.model.WorkSpec} identifier. 81 */ 82 public static void cancelAlarm( 83 @NonNull Context context, 84 @NonNull WorkManagerImpl workManager, 85 @NonNull String workSpecId) { 86 87 WorkDatabase workDatabase = workManager.getWorkDatabase(); 88 SystemIdInfoDao systemIdInfoDao = workDatabase.systemIdInfoDao(); 89 SystemIdInfo systemIdInfo = systemIdInfoDao.getSystemIdInfo(workSpecId); 90 if (systemIdInfo != null) { 91 cancelExactAlarm(context, workSpecId, systemIdInfo.systemId); 92 Log.d(TAG, String.format("Removing SystemIdInfo for workSpecId (%s)", workSpecId)); 93 systemIdInfoDao.removeSystemIdInfo(workSpecId); 94 } 95 } 96 97 private static void cancelExactAlarm( 98 @NonNull Context context, 99 @NonNull String workSpecId, 100 int alarmId) { 101 102 AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 103 Intent delayMet = CommandHandler.createDelayMetIntent(context, workSpecId); 104 PendingIntent pendingIntent = PendingIntent.getService( 105 context, alarmId, delayMet, PendingIntent.FLAG_NO_CREATE); 106 if (pendingIntent != null && alarmManager != null) { 107 Log.d(TAG, String.format( 108 "Cancelling existing alarm with (workSpecId, systemId) (%s, %s)", 109 workSpecId, 110 alarmId)); 111 alarmManager.cancel(pendingIntent); 112 } 113 } 114 115 private static void setExactAlarm( 116 @NonNull Context context, 117 @NonNull String workSpecId, 118 int alarmId, 119 long triggerAtMillis) { 120 121 AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 122 Intent delayMet = CommandHandler.createDelayMetIntent(context, workSpecId); 123 PendingIntent pendingIntent = PendingIntent.getService( 124 context, alarmId, delayMet, PendingIntent.FLAG_ONE_SHOT); 125 if (alarmManager != null) { 126 if (Build.VERSION.SDK_INT >= 19) { 127 alarmManager.setExact(RTC_WAKEUP, triggerAtMillis, pendingIntent); 128 } else { 129 alarmManager.set(RTC_WAKEUP, triggerAtMillis, pendingIntent); 130 } 131 } 132 } 133 134 private Alarms() { 135 } 136} 137