1 /* 2 ** Copyright 2006, 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 ** See the License for the specific language governing permissions and 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** limitations under the License. 15 */ 16 17 package com.android.providers.calendar; 18 19 import android.app.AlarmManager; 20 import android.app.PendingIntent; 21 import android.content.BroadcastReceiver; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.os.PowerManager; 26 import android.os.SystemProperties; 27 import android.util.Log; 28 29 import java.util.concurrent.TimeUnit; 30 31 /** 32 * This IntentReceiver executes when the boot completes and ensures that 33 * the Calendar provider has started and then initializes the alarm 34 * scheduler for the Calendar provider. This needs to be done after 35 * the boot completes because the alarm manager may not have been started 36 * yet. 37 */ 38 public class CalendarReceiver extends BroadcastReceiver { 39 private static final String TAG = CalendarProvider2.TAG; 40 41 private static final long NEXT_EVENT_CHECK_INTERVAL = 42 SystemProperties.getLong("debug.calendar.check_interval", TimeUnit.HOURS.toMillis(6)); 43 private static final int NEXT_EVENT_CHECK_PENDING_CODE = 100; 44 45 private PowerManager.WakeLock mWakeLock; 46 47 @Override onReceive(Context context, Intent intent)48 public void onReceive(Context context, Intent intent) { 49 final String action = intent.getAction(); 50 51 if (!Intent.ACTION_BOOT_COMPLETED.equals(action)) { 52 Log.w(TAG, "Unexpected broadcast: " + action); 53 return; 54 } 55 if (Log.isLoggable(TAG, Log.DEBUG)) { 56 Log.d(TAG, "BOOT_COMPLETED"); 57 } 58 59 if (mWakeLock == null) { 60 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 61 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CalendarReceiver_Provider"); 62 mWakeLock.setReferenceCounted(true); 63 } 64 mWakeLock.acquire(); 65 66 final ContentResolver cr = context.getContentResolver(); 67 final PendingResult result = goAsync(); 68 69 new Thread(() -> { 70 setCalendarCheckAlarm(context); 71 removeScheduledAlarms(cr); 72 result.finish(); 73 mWakeLock.release(); 74 }).start(); 75 } 76 77 /* 78 * Remove alarms from the CalendarAlerts table that have been marked 79 * as "scheduled" but not fired yet. We do this because the 80 * AlarmManagerService loses all information about alarms when the 81 * power turns off but we store the information in a database table 82 * that persists across reboots. See the documentation for 83 * scheduleNextAlarmLocked() for more information. 84 * 85 * We don't expect this to be called more than once. If it were, we would have to 86 * worry about serializing the use of the service. 87 */ removeScheduledAlarms(ContentResolver resolver)88 private void removeScheduledAlarms(ContentResolver resolver) { 89 resolver.update(CalendarAlarmManager.SCHEDULE_ALARM_REMOVE_URI, null /* values */, 90 null /* where */, null /* selectionArgs */); 91 } 92 setCalendarCheckAlarm(Context context)93 private static void setCalendarCheckAlarm(Context context) { 94 final PendingIntent checkIntent = PendingIntent.getBroadcast(context, 95 NEXT_EVENT_CHECK_PENDING_CODE, 96 CalendarAlarmManager.getCheckNextAlarmIntentForBroadcast(context), 97 PendingIntent.FLAG_UPDATE_CURRENT); 98 99 final AlarmManager am = context.getSystemService(AlarmManager.class); 100 101 am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 102 NEXT_EVENT_CHECK_INTERVAL, NEXT_EVENT_CHECK_INTERVAL, checkIntent); 103 } 104 } 105