Merge "Use expedited to job to update alarms." into sc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c93bb8e..3f52171 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -109,5 +109,9 @@
             </intent-filter>
         </receiver>
 
+        <service android:name="CalendarProviderJobService"
+                 android:exported="false"
+                 android:permission="android.permission.BIND_JOB_SERVICE" />
+
     </application>
 </manifest>
diff --git a/src/com/android/providers/calendar/CalendarProviderBroadcastReceiver.java b/src/com/android/providers/calendar/CalendarProviderBroadcastReceiver.java
index 10c76c0..c27044f 100644
--- a/src/com/android/providers/calendar/CalendarProviderBroadcastReceiver.java
+++ b/src/com/android/providers/calendar/CalendarProviderBroadcastReceiver.java
@@ -17,10 +17,12 @@
 package com.android.providers.calendar;
 
 import android.app.Activity;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.app.job.JobWorkItem;
 import android.content.BroadcastReceiver;
-import android.content.ContentProvider;
+import android.content.ComponentName;
 import android.content.Context;
-import android.content.IContentProvider;
 import android.content.Intent;
 import android.provider.CalendarContract;
 import android.util.Log;
@@ -41,33 +43,17 @@
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "Received intent: " + intent);
         }
-        final IContentProvider iprovider =
-                context.getContentResolver().acquireProvider(CalendarContract.AUTHORITY);
-        final ContentProvider cprovider = ContentProvider.coerceToLocalContentProvider(iprovider);
 
-        if (!(cprovider instanceof CalendarProvider2)) {
-            Slog.wtf(TAG, "CalendarProvider2 not found in CalendarProviderBroadcastReceiver.");
-            return;
+        JobWorkItem jwi = new JobWorkItem(intent);
+        JobInfo alarmJob = new JobInfo.Builder(CalendarProviderJobService.JOB_ID,
+                new ComponentName(context, CalendarProviderJobService.class))
+                .setExpedited(true)
+                .build();
+        JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+        if (jobScheduler.enqueue(alarmJob, jwi) == JobScheduler.RESULT_SUCCESS) {
+            setResultCode(Activity.RESULT_OK);
+        } else {
+            Slog.wtf(TAG, "Failed to schedule expedited job");
         }
-
-        final CalendarProvider2 provider = (CalendarProvider2) cprovider;
-
-        final PendingResult result = goAsync();
-
-        new Thread(() -> {
-            // Schedule the next alarm. Please be noted that for ACTION_EVENT_REMINDER broadcast,
-            // we never remove scheduled alarms.
-            final boolean removeAlarms = intent
-                    .getBooleanExtra(CalendarAlarmManager.KEY_REMOVE_ALARMS, false);
-            provider.getOrCreateCalendarAlarmManager().runScheduleNextAlarm(removeAlarms, provider);
-
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "Next alarm set.");
-            }
-
-            result.setResultCode(Activity.RESULT_OK);
-            result.finish();
-        }).start();
-
     }
 }
diff --git a/src/com/android/providers/calendar/CalendarProviderJobService.java b/src/com/android/providers/calendar/CalendarProviderJobService.java
new file mode 100644
index 0000000..bfec48a
--- /dev/null
+++ b/src/com/android/providers/calendar/CalendarProviderJobService.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.calendar;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.app.job.JobWorkItem;
+import android.content.ContentProvider;
+import android.content.IContentProvider;
+import android.provider.CalendarContract;
+import android.util.Log;
+import android.util.Slog;
+
+public class CalendarProviderJobService extends JobService {
+    private static final String TAG = CalendarProvider2.TAG;
+    static final int JOB_ID = CalendarProviderJobService.class.hashCode();
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        if (!params.isExpeditedJob()) {
+            Slog.w(TAG, "job not running as expedited");
+        }
+
+        final IContentProvider iprovider =
+                getContentResolver().acquireProvider(CalendarContract.AUTHORITY);
+        final ContentProvider cprovider = ContentProvider.coerceToLocalContentProvider(iprovider);
+
+        if (!(cprovider instanceof CalendarProvider2)) {
+            Slog.wtf(TAG, "CalendarProvider2 not found in CalendarProviderJobService.");
+            return false;
+        }
+
+        final CalendarProvider2 provider = (CalendarProvider2) cprovider;
+
+        new Thread(() -> {
+            for (JobWorkItem jwi = params.dequeueWork(); jwi != null; jwi = params.dequeueWork()) {
+                // Schedule the next alarm. Please be noted that for ACTION_EVENT_REMINDER
+                // broadcast, we never remove scheduled alarms.
+                final boolean removeAlarms = jwi.getIntent()
+                        .getBooleanExtra(CalendarAlarmManager.KEY_REMOVE_ALARMS, false);
+                provider.getOrCreateCalendarAlarmManager()
+                        .runScheduleNextAlarm(removeAlarms, provider);
+
+                if (Log.isLoggable(TAG, Log.DEBUG)) {
+                    Log.d(TAG, "Next alarm set.");
+                }
+                params.completeWork(jwi);
+            }
+        }).start();
+        return true;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        // The work should be very quick, so it'll be surprising if JS has to stop us.
+        Slog.wtf(TAG, "CalendarProviderJobService was stopped due to "
+                + JobParameters.getInternalReasonCodeDescription(params.getInternalStopReasonCode())
+                + "(" + params.getStopReason() + ")");
+        return true;
+    }
+}