[android_alarm_manager] Added oneShotAt method to schedule a alarm at a given time (#1947)

diff --git a/packages/android_alarm_manager/CHANGELOG.md b/packages/android_alarm_manager/CHANGELOG.md
index af2d8b7..f7537a5 100644
--- a/packages/android_alarm_manager/CHANGELOG.md
+++ b/packages/android_alarm_manager/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.4.3
+
+* Added `oneShotAt` method to run `callback` at a given DateTime `time`.
+
 ## 0.4.2
 
 * Added support for setting alarms which work when the phone is in doze mode.
diff --git a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java
index 6a72393..5cc7741 100644
--- a/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java
+++ b/packages/android_alarm_manager/android/src/main/java/io/flutter/plugins/androidalarmmanager/AndroidAlarmManagerPlugin.java
@@ -50,7 +50,7 @@
     // alarmManagerPluginChannel is the channel responsible for receiving the following messages
     // from the main Flutter app:
     // - "AlarmService.start"
-    // - "Alarm.oneShot"
+    // - "Alarm.oneShotAt"
     // - "Alarm.periodic"
     // - "Alarm.cancel"
     final MethodChannel alarmManagerPluginChannel =
@@ -125,7 +125,7 @@
         PeriodicRequest periodicRequest = PeriodicRequest.fromJson((JSONArray) arguments);
         AlarmService.setPeriodic(mContext, periodicRequest);
         result.success(true);
-      } else if (method.equals("Alarm.oneShot")) {
+      } else if (method.equals("Alarm.oneShotAt")) {
         // This message indicates that the Flutter app would like to schedule a one-time
         // task.
         OneShotRequest oneShotRequest = OneShotRequest.fromJson((JSONArray) arguments);
diff --git a/packages/android_alarm_manager/lib/android_alarm_manager.dart b/packages/android_alarm_manager/lib/android_alarm_manager.dart
index 228112a..05ead10 100644
--- a/packages/android_alarm_manager/lib/android_alarm_manager.dart
+++ b/packages/android_alarm_manager/lib/android_alarm_manager.dart
@@ -113,20 +113,74 @@
     bool exact = false,
     bool wakeup = false,
     bool rescheduleOnReboot = false,
+  }) =>
+      oneShotAt(
+        DateTime.now().add(delay),
+        id,
+        callback,
+        alarmClock: alarmClock,
+        allowWhileIdle: allowWhileIdle,
+        exact: exact,
+        wakeup: wakeup,
+        rescheduleOnReboot: rescheduleOnReboot,
+      );
+
+  /// Schedules a one-shot timer to run `callback` at `time`.
+  ///
+  /// The `callback` will run whether or not the main application is running or
+  /// in the foreground. It will run in the Isolate owned by the
+  /// AndroidAlarmManager service.
+  ///
+  /// `callback` must be either a top-level function or a static method from a
+  /// class.
+  ///
+  /// The timer is uniquely identified by `id`. Calling this function again
+  /// again with the same `id` will cancel and replace the existing timer.
+  ///
+  /// If `alarmClock` is passed as `true`, the timer will be created with
+  /// Android's `AlarmManagerCompat.setAlarmClock`.
+  ///
+  /// If `allowWhileIdle` is passed as `true`, the timer will be created with
+  /// Android's `AlarmManagerCompat.setExactAndAllowWhileIdle` or
+  /// `AlarmManagerCompat.setAndAllowWhileIdle`.
+  ///
+  /// If `exact` is passed as `true`, the timer will be created with Android's
+  /// `AlarmManagerCompat.setExact`. When `exact` is `false` (the default), the
+  /// timer will be created with `AlarmManager.set`.
+  ///
+  /// If `wakeup` is passed as `true`, the device will be woken up when the
+  /// alarm fires. If `wakeup` is false (the default), the device will not be
+  /// woken up to service the alarm.
+  ///
+  /// If `rescheduleOnReboot` is passed as `true`, the alarm will be persisted
+  /// across reboots. If `rescheduleOnReboot` is false (the default), the alarm
+  /// will not be rescheduled after a reboot and will not be executed.
+  ///
+  /// Returns a [Future] that resolves to `true` on success and `false` on
+  /// failure.
+  static Future<bool> oneShotAt(
+    DateTime time,
+    int id,
+    dynamic Function() callback, {
+    bool alarmClock = false,
+    bool allowWhileIdle = false,
+    bool exact = false,
+    bool wakeup = false,
+    bool rescheduleOnReboot = false,
   }) async {
-    final int now = DateTime.now().millisecondsSinceEpoch;
-    final int first = now + delay.inMilliseconds;
+    final int startMillis = time.millisecondsSinceEpoch;
     final CallbackHandle handle = PluginUtilities.getCallbackHandle(callback);
     if (handle == null) {
       return false;
     }
-    final bool r = await _channel.invokeMethod<bool>('Alarm.oneShot', <dynamic>[
+    final bool r =
+        await _channel.invokeMethod<bool>('Alarm.oneShotAt', <dynamic>[
       id,
       alarmClock,
       allowWhileIdle,
       exact,
       wakeup,
-      first,
+      startMillis,
       rescheduleOnReboot,
       handle.toRawHandle(),
     ]);
diff --git a/packages/android_alarm_manager/pubspec.yaml b/packages/android_alarm_manager/pubspec.yaml
index 90907d9..b164970 100644
--- a/packages/android_alarm_manager/pubspec.yaml
+++ b/packages/android_alarm_manager/pubspec.yaml
@@ -1,7 +1,7 @@
 name: android_alarm_manager
 description: Flutter plugin for accessing the Android AlarmManager service, and
   running Dart code in the background when alarms fire.
-version: 0.4.2
+version: 0.4.3
 author: Flutter Team <flutter-dev@googlegroups.com>
 homepage: https://github.com/flutter/plugins/tree/master/packages/android_alarm_manager