/** * PermissionManager.java * * Specialized manager for permission handling and notification settings * Handles notification permissions, channel management, and exact alarm settings * * @author Matthew Raymer * @version 2.0.0 - Modular Architecture */ package com.timesafari.dailynotification; import android.Manifest; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.provider.Settings; import android.util.Log; import androidx.core.app.NotificationManagerCompat; import com.getcapacitor.JSObject; import com.getcapacitor.PluginCall; /** * Manager class for permission and settings management * * Responsibilities: * - Request notification permissions * - Check permission status * - Manage notification channels * - Handle exact alarm settings * - Provide comprehensive status checking */ public class PermissionManager { private static final String TAG = "PermissionManager"; private final Context context; private final ChannelManager channelManager; /** * Initialize the PermissionManager * * @param context Android context * @param channelManager Channel manager for notification channels */ public PermissionManager(Context context, ChannelManager channelManager) { this.context = context; this.channelManager = channelManager; Log.d(TAG, "PermissionManager initialized"); } /** * Request notification permissions from the user * * @param call Plugin call */ public void requestNotificationPermissions(PluginCall call) { try { Log.d(TAG, "Requesting notification permissions"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { // For Android 13+, request POST_NOTIFICATIONS permission requestPermission(Manifest.permission.POST_NOTIFICATIONS, call); } else { // For older versions, permissions are granted at install time JSObject result = new JSObject(); result.put("success", true); result.put("granted", true); result.put("message", "Notifications enabled (pre-Android 13)"); call.resolve(result); } } catch (Exception e) { Log.e(TAG, "Error requesting notification permissions", e); call.reject("Failed to request permissions: " + e.getMessage()); } } /** * Check the current status of notification permissions * * @param call Plugin call */ public void checkPermissionStatus(PluginCall call) { try { Log.d(TAG, "Checking permission status"); boolean postNotificationsGranted = false; boolean exactAlarmsGranted = false; // Check POST_NOTIFICATIONS permission if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { postNotificationsGranted = context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED; } else { postNotificationsGranted = NotificationManagerCompat.from(context).areNotificationsEnabled(); } // Check exact alarm permission if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { android.app.AlarmManager alarmManager = (android.app.AlarmManager) context.getSystemService(Context.ALARM_SERVICE); exactAlarmsGranted = alarmManager.canScheduleExactAlarms(); } else { exactAlarmsGranted = true; // Pre-Android 12, exact alarms are always allowed } JSObject result = new JSObject(); result.put("success", true); result.put("postNotificationsGranted", postNotificationsGranted); result.put("exactAlarmsGranted", exactAlarmsGranted); result.put("channelEnabled", channelManager.isChannelEnabled()); result.put("channelImportance", channelManager.getChannelImportance()); call.resolve(result); } catch (Exception e) { Log.e(TAG, "Error checking permission status", e); call.reject("Failed to check permissions: " + e.getMessage()); } } /** * Open exact alarm settings for the user * * @param call Plugin call */ public void openExactAlarmSettings(PluginCall call) { try { Log.d(TAG, "Opening exact alarm settings"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM); intent.setData(android.net.Uri.parse("package:" + context.getPackageName())); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { context.startActivity(intent); JSObject result = new JSObject(); result.put("success", true); result.put("message", "Exact alarm settings opened"); call.resolve(result); } catch (Exception e) { Log.e(TAG, "Failed to open exact alarm settings", e); call.reject("Failed to open exact alarm settings: " + e.getMessage()); } } else { JSObject result = new JSObject(); result.put("success", true); result.put("message", "Exact alarms not supported on this Android version"); call.resolve(result); } } catch (Exception e) { Log.e(TAG, "Error opening exact alarm settings", e); call.reject("Failed to open exact alarm settings: " + e.getMessage()); } } /** * Check if the notification channel is enabled * * @param call Plugin call */ public void isChannelEnabled(PluginCall call) { try { Log.d(TAG, "Checking channel status"); boolean enabled = channelManager.isChannelEnabled(); int importance = channelManager.getChannelImportance(); JSObject result = new JSObject(); result.put("success", true); result.put("enabled", enabled); result.put("importance", importance); result.put("channelId", channelManager.getDefaultChannelId()); call.resolve(result); } catch (Exception e) { Log.e(TAG, "Error checking channel status", e); call.reject("Failed to check channel status: " + e.getMessage()); } } /** * Open notification channel settings for the user * * @param call Plugin call */ public void openChannelSettings(PluginCall call) { try { Log.d(TAG, "Opening channel settings"); boolean opened = channelManager.openChannelSettings(); JSObject result = new JSObject(); result.put("success", true); result.put("opened", opened); result.put("message", opened ? "Channel settings opened" : "Failed to open channel settings"); call.resolve(result); } catch (Exception e) { Log.e(TAG, "Error opening channel settings", e); call.reject("Failed to open channel settings: " + e.getMessage()); } } /** * Get comprehensive status of the notification system * * @param call Plugin call */ public void checkStatus(PluginCall call) { try { Log.d(TAG, "Checking comprehensive status"); // Check permissions boolean postNotificationsGranted = false; boolean exactAlarmsGranted = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { postNotificationsGranted = context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED; } else { postNotificationsGranted = NotificationManagerCompat.from(context).areNotificationsEnabled(); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { android.app.AlarmManager alarmManager = (android.app.AlarmManager) context.getSystemService(Context.ALARM_SERVICE); exactAlarmsGranted = alarmManager.canScheduleExactAlarms(); } else { exactAlarmsGranted = true; } // Check channel status boolean channelEnabled = channelManager.isChannelEnabled(); int channelImportance = channelManager.getChannelImportance(); // Determine overall status boolean canScheduleNow = postNotificationsGranted && channelEnabled && exactAlarmsGranted; JSObject result = new JSObject(); result.put("success", true); result.put("canScheduleNow", canScheduleNow); result.put("postNotificationsGranted", postNotificationsGranted); result.put("exactAlarmsGranted", exactAlarmsGranted); result.put("channelEnabled", channelEnabled); result.put("channelImportance", channelImportance); result.put("channelId", channelManager.getDefaultChannelId()); result.put("androidVersion", Build.VERSION.SDK_INT); call.resolve(result); } catch (Exception e) { Log.e(TAG, "Error checking comprehensive status", e); call.reject("Failed to check status: " + e.getMessage()); } } /** * Request a specific permission * * @param permission Permission to request * @param call Plugin call */ private void requestPermission(String permission, PluginCall call) { try { // This would typically be handled by the Capacitor framework // For now, we'll check if the permission is already granted boolean granted = context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED; JSObject result = new JSObject(); result.put("success", true); result.put("granted", granted); result.put("permission", permission); result.put("message", granted ? "Permission already granted" : "Permission not granted"); call.resolve(result); } catch (Exception e) { Log.e(TAG, "Error requesting permission: " + permission, e); call.reject("Failed to request permission: " + e.getMessage()); } } }