package com.jttools.datacontrol.ui import android.annotation.SuppressLint import android.app.NotificationManager import android.content.Context import android.content.Intent import android.net.Uri import android.net.VpnService import android.os.Build import android.os.PowerManager import android.provider.Settings import androidx.activity.ComponentActivity import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat import com.jttools.datacontrol.vpn.TunnelManager /** * Regroupe les autorisations système nécessaires (VPN, notifications, batterie) pour que * les écrans Compose puissent les demander sans dépendre directement de l'Activity. */ class SystemActions(private val activity: ComponentActivity) { private var onVpnResult: ((Boolean) -> Unit)? = null private var onNotificationResult: ((Boolean) -> Unit)? = null private val vpnLauncher: ActivityResultLauncher = activity.registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> onVpnResult?.invoke(result.resultCode == android.app.Activity.RESULT_OK) } private val notificationLauncher: ActivityResultLauncher = activity.registerForActivityResult( ActivityResultContracts.RequestPermission() ) { granted -> onNotificationResult?.invoke(granted) } private var onLocationResult: ((Boolean) -> Unit)? = null private var onBackgroundLocationResult: ((Boolean) -> Unit)? = null private var onAdminResult: ((Boolean) -> Unit)? = null private val locationLauncher: ActivityResultLauncher> = activity.registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { granted -> onLocationResult?.invoke(granted.values.any { it }) } private val backgroundLocationLauncher: ActivityResultLauncher = activity.registerForActivityResult( ActivityResultContracts.RequestPermission() ) { granted -> onBackgroundLocationResult?.invoke(granted) } private val adminLauncher: ActivityResultLauncher = activity.registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> onAdminResult?.invoke(result.resultCode == android.app.Activity.RESULT_OK) } fun hasLocationPermission(): Boolean = ContextCompat.checkSelfPermission( activity, android.Manifest.permission.ACCESS_FINE_LOCATION ) == android.content.pm.PackageManager.PERMISSION_GRANTED fun hasBackgroundLocationPermission(): Boolean = Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || ContextCompat.checkSelfPermission( activity, android.Manifest.permission.ACCESS_BACKGROUND_LOCATION ) == android.content.pm.PackageManager.PERMISSION_GRANTED fun requestLocationPermission(onResult: (Boolean) -> Unit) { onLocationResult = onResult locationLauncher.launch( arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION) ) } /** À demander APRÈS la position au premier plan (exigence Android 11+). */ fun requestBackgroundLocationPermission(onResult: (Boolean) -> Unit) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { onResult(true); return } onBackgroundLocationResult = onResult backgroundLocationLauncher.launch(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION) } fun isGuardEnabled(): Boolean = com.jttools.datacontrol.guard.AppGuardService.isEnabled(activity) fun openAccessibilitySettings() { activity.startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)) } fun isAdminActive(): Boolean = com.jttools.datacontrol.admin.AdminController.isActive(activity) fun requestAdmin(onResult: (Boolean) -> Unit) { onAdminResult = onResult adminLauncher.launch(com.jttools.datacontrol.admin.AdminController.requestIntent(activity)) } fun deactivateAdmin() = com.jttools.datacontrol.admin.AdminController.deactivate(activity) fun isVpnPrepared(): Boolean = TunnelManager.isPrepared(activity) fun requestVpnPermission(onResult: (Boolean) -> Unit) { val intent = VpnService.prepare(activity) if (intent == null) { onResult(true) } else { onVpnResult = onResult vpnLauncher.launch(intent) } } fun hasNotificationPermission(): Boolean { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return true return ContextCompat.checkSelfPermission( activity, android.Manifest.permission.POST_NOTIFICATIONS ) == android.content.pm.PackageManager.PERMISSION_GRANTED } fun requestNotificationPermission(onResult: (Boolean) -> Unit) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { onResult(true) return } onNotificationResult = onResult notificationLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS) } fun isIgnoringBatteryOptimizations(): Boolean { val pm = activity.getSystemService(Context.POWER_SERVICE) as PowerManager return pm.isIgnoringBatteryOptimizations(activity.packageName) } @SuppressLint("BatteryLife") fun requestIgnoreBatteryOptimizations() { val intent = Intent( Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse("package:${activity.packageName}") ) activity.startActivity(intent) } }