requestAlarmPermission method

  1. @override
Future<String> requestAlarmPermission()
override

Request alarm permission

Implementation

@override
Future<String> requestAlarmPermission() async {
  debugPrint('Requesting alarm permission');

  // Handle alarm permission differently based on platform
  if (Platform.isIOS) {
    // On iOS, we use notifications for alarms
    debugPrint(
      'Using notification permission for alarm functionality on iOS',
    );
    final result = await _invokePermissionMethod(
      'requestNotificationPermission',
    );
    return result;
  } else if (Platform.isAndroid) {
    try {
      final androidVersion = await methodChannel.invokeMethod<int>(
        'getAndroidVersion',
      );
      debugPrint('Android version: $androidVersion');

      // Android 12+ has additional restrictions
      if (androidVersion != null && androidVersion >= 31) {
        debugPrint(
          'Android 12+ detected, checking if can schedule exact alarms',
        );

        // First check if we have a saved permission status
        final savedStatus = await methodChannel
            .invokeMethod<String>('storage_read', {
              'key':
                  'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
              'defaultValue': '',
            });

        debugPrint('Saved alarm permission status: $savedStatus');

        if (savedStatus == 'GRANTED') {
          debugPrint('Using saved GRANTED status for alarm permission');
          return 'GRANTED';
        }

        // For Android 12+, check if the app can schedule exact alarms
        final canScheduleExactAlarms = await methodChannel.invokeMethod<bool>(
          'canScheduleExactAlarms',
        );
        debugPrint('Can schedule exact alarms: $canScheduleExactAlarms');

        if (canScheduleExactAlarms == true) {
          // Save the permission status
          await methodChannel.invokeMethod<bool>('storage_write', {
            'key':
                'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
            'value': 'GRANTED',
          });
          return 'GRANTED';
        }

        // If we can't schedule exact alarms, we need to request the permission
        debugPrint('Need to request alarm permission');

        // Open the alarm settings immediately
        await methodChannel.invokeMethod('openAlarmSettings');

        // Show a waiting dialog immediately
        if (_context != null) {
          // Show a waiting dialog
          await showDialog(
            context: _context!,
            barrierDismissible: false,
            builder:
                (context) => AlertDialog(
                  title: const Text('Grant Permission'),
                  content: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: const [
                      CircularProgressIndicator(),
                      SizedBox(height: 16),
                      Text(
                        'Please tap "Allow" or "Allow precise alarms" on the settings screen.',
                      ),
                    ],
                  ),
                  actions: [
                    TextButton(
                      child: const Text('I\'ve Granted Permission'),
                      onPressed: () => Navigator.pop(context),
                    ),
                  ],
                ),
          );
        } else {
          // If no context, just wait a bit longer
          await Future.delayed(const Duration(seconds: 5));
        }

        // Wait a bit more to ensure the permission status is updated
        await Future.delayed(const Duration(milliseconds: 500));

        // Check if the permission was granted
        final checkResult = await methodChannel.invokeMethod<bool>(
          'checkAlarmPermissionAfterSettings',
        );
        debugPrint('Alarm permission after settings: $checkResult');

        // Try again if still not granted
        if (checkResult != true) {
          debugPrint('Permission still not granted, checking again...');
          await Future.delayed(const Duration(seconds: 1));
          final secondCheck = await methodChannel.invokeMethod<bool>(
            'checkAlarmPermissionAfterSettings',
          );
          debugPrint('Second check result: $secondCheck');

          if (secondCheck == true) {
            // Save the result as granted
            await methodChannel.invokeMethod<bool>('storage_write', {
              'key':
                  'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
              'value': 'GRANTED',
            });
            return 'GRANTED';
          }
        }

        // Save the result
        final status = checkResult == true ? 'GRANTED' : 'DENIED';
        await methodChannel.invokeMethod<bool>('storage_write', {
          'key': 'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
          'value': status,
        });

        return status;
      } else {
        // For Android 11 and below, no special permission is needed
        debugPrint('Android 11 or below, no special alarm permission needed');

        // Save the granted status
        await methodChannel.invokeMethod<bool>('storage_write', {
          'key': 'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
          'value': 'GRANTED',
        });

        return 'GRANTED';
      }
    } catch (e) {
      debugPrint('Error handling alarm permission: $e');
      return 'ERROR';
    }
  }

  // Fallback to the native implementation
  try {
    debugPrint('Using native implementation for alarm permission');
    final result = await methodChannel.invokeMethod<dynamic>(
      'requestAlarmPermission',
    );
    debugPrint('Alarm permission result from native: $result');

    // If we get a boolean result, convert it to a string status
    if (result is bool) {
      final status = result ? 'GRANTED' : 'DENIED';

      // Save the status
      await methodChannel.invokeMethod<bool>('storage_write', {
        'key': 'permission_android.permission.SCHEDULE_EXACT_ALARM_status',
        'value': status,
      });

      return status;
    }

    return 'DENIED';
  } catch (e) {
    debugPrint('Error requesting alarm permission: $e');
    return 'ERROR';
  }
}