package com.parentalmonitor.child.ui.permissions import android.accessibilityservice.AccessibilityServiceInfo import android.app.AppOpsManager import android.app.admin.DevicePolicyManager import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.os.Bundle import android.os.PowerManager import android.provider.Settings import android.view.LayoutInflater import android.view.View import android.view.accessibility.AccessibilityManager import android.widget.ImageView import android.widget.LinearLayout import android.widget.ProgressBar import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.lifecycle.lifecycleScope import com.google.android.material.button.MaterialButton import com.parentalmonitor.child.ParentalMonitorApp import com.parentalmonitor.child.R import com.parentalmonitor.child.models.PermissionsData import com.parentalmonitor.child.receivers.DeviceAdminReceiver import com.parentalmonitor.child.services.MonitoringService import com.parentalmonitor.child.ui.main.MainActivity import kotlinx.coroutines.launch class PermissionsSetupActivity : AppCompatActivity() { private val apiClient by lazy { (application as ParentalMonitorApp).apiClient } private lateinit var permissionsContainer: LinearLayout private lateinit var progressBar: ProgressBar private lateinit var tvProgress: TextView private lateinit var btnComplete: MaterialButton companion object { private const val REQUEST_CODE_PERMISSIONS = 1001 private val RUNTIME_PERMISSIONS = mutableListOf( android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.READ_CALL_LOG, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.WRITE_CONTACTS, android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO ).apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { add(android.Manifest.permission.POST_NOTIFICATIONS) add(android.Manifest.permission.READ_MEDIA_IMAGES) } else { add(android.Manifest.permission.READ_EXTERNAL_STORAGE) } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { add(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION) } } } data class PermissionItem( val key: String, val name: String, val description: String, val iconRes: Int, val checkFn: () -> Boolean, val intentFn: () -> Intent, val runtimePermissions: List? = null ) private lateinit var permissionItems: List override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_permissions_setup) permissionsContainer = findViewById(R.id.permissionsContainer) progressBar = findViewById(R.id.progressBar) tvProgress = findViewById(R.id.tvProgress) btnComplete = findViewById(R.id.btnComplete) initPermissionItems() btnComplete.setOnClickListener { syncPermissions() startMonitoringService() startActivity(Intent(this, MainActivity::class.java)) finish() } requestAllRuntimePermissions() refreshPermissions() } override fun onResume() { super.onResume() refreshPermissions() } private fun requestAllRuntimePermissions() { val notGranted = RUNTIME_PERMISSIONS.filter { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }.toTypedArray() if (notGranted.isNotEmpty()) { ActivityCompat.requestPermissions(this, notGranted, REQUEST_CODE_PERMISSIONS) } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_CODE_PERMISSIONS) { refreshPermissions() } } private fun initPermissionItems() { permissionItems = listOf( PermissionItem( "accessibility_service", "Accessibility Service", "Required for app usage monitoring", android.R.drawable.ic_menu_view, { isAccessibilityEnabled() }, { Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS) } ), PermissionItem( "usage_stats_access", "Usage Stats Access", "Required to track app usage time", android.R.drawable.ic_menu_recent_history, { isUsageStatsEnabled() }, { Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS) } ), PermissionItem( "notification_access", "Notification Access", "Required to monitor notifications", android.R.drawable.ic_popup_reminder, { isNotificationListenerEnabled() }, { Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS) } ), PermissionItem( "device_admin", "Device Admin", "Required for device lock/wipe commands", android.R.drawable.ic_lock_lock, { isDeviceAdminEnabled() }, { Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN).apply { putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, ComponentName(this@PermissionsSetupActivity, DeviceAdminReceiver::class.java)) putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Required for remote device management") } } ), PermissionItem( "location_permission", "Location Permission", "Required to track device location", android.R.drawable.ic_menu_mylocation, { isLocationPermissionGranted() }, { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } }, runtimePermissions = listOf( android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION ) ), PermissionItem( "call_logs_permission", "Call Logs", "Required to monitor call history", android.R.drawable.ic_menu_call, { ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED }, { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } }, runtimePermissions = listOf(android.Manifest.permission.READ_CALL_LOG) ), PermissionItem( "contacts_permission", "Contacts", "Required to monitor and manage contacts", android.R.drawable.ic_menu_my_calendar, { ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED }, { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } }, runtimePermissions = listOf( android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.WRITE_CONTACTS ) ), PermissionItem( "phone_permission", "Phone", "Required to monitor phone state", android.R.drawable.ic_menu_call, { ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED }, { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } }, runtimePermissions = listOf(android.Manifest.permission.READ_PHONE_STATE) ), PermissionItem( "sms_permission", "SMS", "Required to monitor text messages", android.R.drawable.ic_dialog_email, { ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED }, { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } }, runtimePermissions = listOf(android.Manifest.permission.READ_SMS) ), PermissionItem( "camera_permission", "Camera", "Required for remote camera capture", android.R.drawable.ic_menu_camera, { ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED }, { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } }, runtimePermissions = listOf(android.Manifest.permission.CAMERA) ), PermissionItem( "microphone_permission", "Microphone", "Required for remote audio recording", android.R.drawable.ic_btn_speak_now, { ContextCompat.checkSelfPermission(this, android.Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED }, { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } }, runtimePermissions = listOf(android.Manifest.permission.RECORD_AUDIO) ), PermissionItem( "overlay_permission", "Overlay Permission", "Required for screen overlay features", android.R.drawable.ic_menu_edit, { Settings.canDrawOverlays(this) }, { Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:$packageName")) } ), PermissionItem( "write_settings", "Modify System Settings", "Required for brightness control and other settings", android.R.drawable.ic_menu_manage, { Settings.System.canWrite(this) }, { Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:$packageName")) } ), PermissionItem( "battery_optimization", "Battery Optimization", "Disable battery optimization for stable monitoring", android.R.drawable.ic_lock_idle_charging, { isBatteryOptimizationIgnored() }, { Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse("package:$packageName")) } ), PermissionItem( "auto_start", "Auto Start", "Allow app to auto-start after reboot", android.R.drawable.ic_media_play, { true }, { getAutoStartIntent() } ), PermissionItem( "storage_permission", "Storage Permission", "Required for screenshot storage", android.R.drawable.ic_menu_gallery, { isStoragePermissionGranted() }, { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } }, runtimePermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) listOf(android.Manifest.permission.READ_MEDIA_IMAGES) else listOf(android.Manifest.permission.READ_EXTERNAL_STORAGE) ), PermissionItem( "post_notifications", "Post Notifications", "Required to show monitoring status notification", android.R.drawable.ic_popup_reminder, { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { ContextCompat.checkSelfPermission(this, android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED } else { true } }, { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } }, runtimePermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) listOf(android.Manifest.permission.POST_NOTIFICATIONS) else null ) ) } private fun refreshPermissions() { permissionsContainer.removeAllViews() var grantedCount = 0 for (item in permissionItems) { val isGranted = item.checkFn() if (isGranted) grantedCount++ val view = LayoutInflater.from(this).inflate(R.layout.item_permission, permissionsContainer, false) view.findViewById(R.id.ivPermIcon).setImageResource(item.iconRes) view.findViewById(R.id.tvPermName).text = item.name view.findViewById(R.id.tvPermDescription).text = item.description val tvStatus = view.findViewById(R.id.tvPermStatus) val btnOpen = view.findViewById(R.id.btnOpenSettings) if (isGranted) { tvStatus.text = "ON" tvStatus.setTextColor(ContextCompat.getColor(this, R.color.permission_on)) btnOpen.text = "Enabled" btnOpen.isEnabled = false } else { tvStatus.text = "OFF" tvStatus.setTextColor(ContextCompat.getColor(this, R.color.permission_off)) btnOpen.text = "Enable" btnOpen.isEnabled = true } btnOpen.setOnClickListener { if (item.runtimePermissions != null) { val notGranted = item.runtimePermissions.filter { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }.toTypedArray() if (notGranted.isNotEmpty()) { val shouldShowRationale = notGranted.any { ActivityCompat.shouldShowRequestPermissionRationale(this, it) } if (!shouldShowRationale && getSharedPreferences("parental_monitor", MODE_PRIVATE) .getBoolean("asked_${item.key}", false)) { startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") }) } else { getSharedPreferences("parental_monitor", MODE_PRIVATE) .edit().putBoolean("asked_${item.key}", true).apply() ActivityCompat.requestPermissions(this, notGranted, REQUEST_CODE_PERMISSIONS) } } } else { try { startActivity(item.intentFn()) } catch (e: Exception) { startActivity(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") }) } } } permissionsContainer.addView(view) } val total = permissionItems.size progressBar.max = total progressBar.progress = grantedCount tvProgress.text = "$grantedCount / $total Permissions Completed" // Enable complete button if critical permissions are granted (at least 10) btnComplete.isEnabled = grantedCount >= 10 if (grantedCount == total) { btnComplete.text = "Complete Setup" } else if (grantedCount >= 10) { btnComplete.text = "Continue ($grantedCount/$total)" } } private fun syncPermissions() { lifecycleScope.launch { val permissions = PermissionsData( accessibilityService = isAccessibilityEnabled(), usageStatsAccess = isUsageStatsEnabled(), notificationAccess = isNotificationListenerEnabled(), deviceAdmin = isDeviceAdminEnabled(), locationPermission = isLocationPermissionGranted(), overlayPermission = Settings.canDrawOverlays(this@PermissionsSetupActivity), batteryOptimization = isBatteryOptimizationIgnored(), backgroundActivity = isBatteryOptimizationIgnored(), autoStart = true, storagePermission = isStoragePermissionGranted() ) apiClient.updatePermissions(permissions) } } private fun startMonitoringService() { val intent = Intent(this, MonitoringService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(intent) } else { startService(intent) } } // Permission check methods private fun isAccessibilityEnabled(): Boolean { val am = getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager val services = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_GENERIC) return services.any { it.resolveInfo.serviceInfo.packageName == packageName } } private fun isUsageStatsEnabled(): Boolean { val appOps = getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager val mode = appOps.unsafeCheckOpNoThrow( AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), packageName ) return mode == AppOpsManager.MODE_ALLOWED } private fun isNotificationListenerEnabled(): Boolean { val flat = Settings.Secure.getString(contentResolver, "enabled_notification_listeners") return flat?.contains(packageName) == true } private fun isDeviceAdminEnabled(): Boolean { val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager return dpm.isAdminActive(ComponentName(this, DeviceAdminReceiver::class.java)) } private fun isLocationPermissionGranted(): Boolean { return ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == android.content.pm.PackageManager.PERMISSION_GRANTED } private fun isBatteryOptimizationIgnored(): Boolean { val pm = getSystemService(Context.POWER_SERVICE) as PowerManager return pm.isIgnoringBatteryOptimizations(packageName) } private fun isStoragePermissionGranted(): Boolean { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { true // Not needed for app-specific storage } else { ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) == android.content.pm.PackageManager.PERMISSION_GRANTED } } private fun getAutoStartIntent(): Intent { val manufacturer = Build.MANUFACTURER.lowercase() return when { manufacturer.contains("xiaomi") || manufacturer.contains("redmi") -> { Intent().apply { component = ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity") } } manufacturer.contains("oppo") || manufacturer.contains("realme") -> { Intent().apply { component = ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity") } } manufacturer.contains("vivo") -> { Intent().apply { component = ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity") } } manufacturer.contains("huawei") || manufacturer.contains("honor") -> { Intent().apply { component = ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity") } } manufacturer.contains("samsung") -> { Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } } else -> Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = Uri.parse("package:$packageName") } } } }