@@ -18,7 +18,7 @@ import com.appcontrolx.model.AppInfo
1818import com.appcontrolx.model.ExecutionMode
1919import com.appcontrolx.rollback.ActionLog
2020import com.appcontrolx.rollback.RollbackManager
21- import com.appcontrolx.service.BackgroundStatus
21+
2222import com.appcontrolx.service.BatteryPolicyManager
2323import com.appcontrolx.service.PermissionBridge
2424import com.appcontrolx.utils.SafetyValidator
@@ -28,9 +28,7 @@ import kotlinx.coroutines.Dispatchers
2828import kotlinx.coroutines.launch
2929import kotlinx.coroutines.withContext
3030import java.io.File
31- import java.text.SimpleDateFormat
32- import java.util.Date
33- import java.util.Locale
31+
3432
3533class AppDetailBottomSheet : BottomSheetDialogFragment () {
3634
@@ -42,7 +40,7 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
4240 private var policyManager: BatteryPolicyManager ? = null
4341 private var rollbackManager: RollbackManager ? = null
4442 private var executionMode: ExecutionMode = ExecutionMode .None
45- private var currentBgStatus : BackgroundStatus = BackgroundStatus . DEFAULT
43+
4644
4745 var onActionCompleted: (() -> Unit )? = null
4846
@@ -132,17 +130,6 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
132130 binding.tvMinSdk.text = getString(R .string.detail_sdk_format,
133131 packageInfo.applicationInfo.minSdkVersion)
134132
135- // Dates
136- val dateFormat = SimpleDateFormat (" MMM dd, yyyy HH:mm" , Locale .getDefault())
137- binding.tvInstallDate.text = dateFormat.format(Date (packageInfo.firstInstallTime))
138- binding.tvUpdateDate.text = dateFormat.format(Date (packageInfo.lastUpdateTime))
139-
140- // Status
141- binding.tvStatus.text = if (isEnabled) getString(R .string.status_enabled)
142- else getString(R .string.status_disabled)
143- binding.tvStatus.setTextColor(resources.getColor(
144- if (isEnabled) R .color.status_positive else R .color.status_negative, null ))
145-
146133 // Permissions count
147134 val permCount = packageInfo.requestedPermissions?.size ? : 0
148135 binding.tvPermissions.text = getString(R .string.detail_permissions_count, permCount)
@@ -170,34 +157,46 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
170157 val packageName = arguments?.getString(ARG_PACKAGE_NAME ) ? : return
171158
172159 lifecycleScope.launch {
173- currentBgStatus = withContext(Dispatchers .IO ) {
174- policyManager?.getBackgroundStatus(packageName) ? : BackgroundStatus .DEFAULT
160+ // Load detailed background state via root commands
161+ val (runInBg, runAnyInBg) = withContext(Dispatchers .IO ) {
162+ if (executor != null ) {
163+ val runInBgResult = executor!! .execute(" appops get $packageName RUN_IN_BACKGROUND" )
164+ val runAnyInBgResult = executor!! .execute(" appops get $packageName RUN_ANY_IN_BACKGROUND" )
165+ Pair (
166+ parseAppOpsOutput(runInBgResult.getOrDefault(" " )),
167+ parseAppOpsOutput(runAnyInBgResult.getOrDefault(" " ))
168+ )
169+ } else {
170+ Pair (" N/A" , " N/A" )
171+ }
175172 }
176173
177- updateBatteryStatusUI()
174+ updateBatteryStatusUI(runInBg, runAnyInBg )
178175 }
179176 }
180177
181- private fun updateBatteryStatusUI () {
182- val (text, color) = when (currentBgStatus) {
183- BackgroundStatus .RESTRICTED -> Pair (
184- getString(R .string.status_restricted),
185- R .color.status_negative
186- )
187- BackgroundStatus .ALLOWED -> Pair (
188- getString(R .string.status_allowed),
189- R .color.status_positive
190- )
191- BackgroundStatus .DEFAULT -> Pair (
192- getString(R .string.status_default),
193- R .color.status_neutral
194- )
178+ private fun parseAppOpsOutput (output : String ): String {
179+ return when {
180+ output.contains(" ignore" ) -> " ignore"
181+ output.contains(" deny" ) -> " deny"
182+ output.contains(" allow" ) -> " allow"
183+ output.contains(" default" ) -> " default"
184+ else -> " unknown"
195185 }
186+ }
187+
188+ private fun updateBatteryStatusUI (runInBg : String , runAnyInBg : String ) {
189+ // RUN_IN_BACKGROUND
190+ binding.tvRunInBg.text = runInBg
191+ binding.tvRunInBg.setTextColor(resources.getColor(
192+ if (runInBg == " ignore" || runInBg == " deny" ) R .color.status_negative
193+ else R .color.status_positive, null ))
196194
197- binding.tvBatteryStatus.text = text
198- binding.tvBatteryStatus.setTextColor(resources.getColor(color, null ))
199-
200- // Both buttons always visible - no hide/show
195+ // RUN_ANY_IN_BACKGROUND
196+ binding.tvRunAnyInBg.text = runAnyInBg
197+ binding.tvRunAnyInBg.setTextColor(resources.getColor(
198+ if (runAnyInBg == " ignore" || runAnyInBg == " deny" ) R .color.status_negative
199+ else R .color.status_positive, null ))
201200 }
202201
203202 private fun setupButtons () {
@@ -277,6 +276,7 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
277276
278277 binding.btnLaunchApp.setOnClickListener { launchApp() }
279278 binding.btnOpenSettings.setOnClickListener { openAppSettings() }
279+ binding.btnAospInfo.setOnClickListener { openAospAppInfo() }
280280 }
281281
282282 private fun launchApp () {
@@ -382,12 +382,8 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
382382 }
383383
384384 if (success) {
385- // Refresh background status
386- val packageName = appInfo?.packageName ? : return @launch
387- currentBgStatus = withContext(Dispatchers .IO ) {
388- policyManager?.getBackgroundStatus(packageName) ? : BackgroundStatus .DEFAULT
389- }
390- updateBatteryStatusUI()
385+ // Refresh background status display
386+ loadBatteryStatus()
391387
392388 binding.tvActionStatus.text = getString(R .string.action_completed, actionName)
393389 binding.tvActionStatus.setTextColor(resources.getColor(R .color.status_positive, null ))
@@ -418,6 +414,7 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
418414 binding.btnUninstall.isEnabled = enabled
419415 binding.btnLaunchApp.isEnabled = enabled
420416 binding.btnOpenSettings.isEnabled = enabled
417+ binding.btnAospInfo.isEnabled = enabled
421418 }
422419
423420 private fun setButtonEnabled (button : MaterialButton , enabled : Boolean ) {
@@ -436,6 +433,29 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
436433 }
437434 }
438435
436+ private fun openAospAppInfo () {
437+ val packageName = appInfo?.packageName ? : return
438+ try {
439+ // Use explicit AOSP Settings intent that won't be overridden by custom ROMs
440+ val intent = Intent ().apply {
441+ setClassName(" com.android.settings" , " com.android.settings.applications.InstalledAppDetails" )
442+ putExtra(" package" , packageName)
443+ putExtra(" com.android.settings.ApplicationPkgName" , packageName)
444+ addFlags(Intent .FLAG_ACTIVITY_NEW_TASK )
445+ }
446+ startActivity(intent)
447+ } catch (e: Exception ) {
448+ // Fallback to standard settings
449+ try {
450+ startActivity(Intent (Settings .ACTION_APPLICATION_DETAILS_SETTINGS ).apply {
451+ data = Uri .parse(" package:$packageName " )
452+ })
453+ } catch (e2: Exception ) {
454+ Toast .makeText(context, R .string.error_open_settings, Toast .LENGTH_SHORT ).show()
455+ }
456+ }
457+ }
458+
439459 private fun formatFileSize (size : Long ): String = when {
440460 size >= 1024 * 1024 * 1024 -> String .format(" %.2f GB" , size / (1024.0 * 1024 * 1024 ))
441461 size >= 1024 * 1024 -> String .format(" %.2f MB" , size / (1024.0 * 1024 ))
0 commit comments