11package com.itsaky.androidide.utils
22
33import android.Manifest
4+ import android.app.Activity
5+ import android.app.ActivityManager
46import android.content.Context
7+ import android.content.Intent
58import android.content.pm.PackageManager
9+ import android.net.Uri
610import android.os.Build
711import android.os.Environment
812import android.provider.Settings
13+ import androidx.annotation.StringRes
914import androidx.annotation.RequiresApi
1015import androidx.core.app.ActivityCompat
1116import com.itsaky.androidide.R
@@ -16,6 +21,18 @@ import com.itsaky.androidide.models.OnboardingPermissionItem
1621 */
1722object PermissionsHelper {
1823
24+ enum class OverlayPermissionState {
25+ GRANTED ,
26+ REQUESTABLE ,
27+ UNSUPPORTED ,
28+ }
29+
30+ data class OverlayPermissionAvailability (
31+ val state : OverlayPermissionState ,
32+ @StringRes val messageRes : Int? = null ,
33+ val shouldOpenAppInfo : Boolean = false ,
34+ )
35+
1936 fun getRequiredPermissions (context : Context ): List <OnboardingPermissionItem > {
2037 val permissions = mutableListOf<OnboardingPermissionItem >()
2138
@@ -48,15 +65,6 @@ object PermissionsHelper {
4865 ),
4966 )
5067
51- permissions.add(
52- OnboardingPermissionItem (
53- Manifest .permission.SYSTEM_ALERT_WINDOW ,
54- R .string.permission_title_overlay_window,
55- R .string.permission_desc_overlay_window,
56- canDrawOverlays(context),
57- ),
58- )
59-
6068 return permissions
6169 }
6270
@@ -68,6 +76,78 @@ object PermissionsHelper {
6876
6977 fun canDrawOverlays (context : Context ): Boolean = Settings .canDrawOverlays(context)
7078
79+ fun getOverlayPermissionAvailability (
80+ context : Context ,
81+ afterRequest : Boolean = false,
82+ ): OverlayPermissionAvailability = when {
83+ canDrawOverlays(context) ->
84+ OverlayPermissionAvailability (OverlayPermissionState .GRANTED )
85+ ! isOverlayPermissionSupported(context) ->
86+ OverlayPermissionAvailability (
87+ OverlayPermissionState .UNSUPPORTED ,
88+ R .string.permission_overlay_unsupported_hint,
89+ )
90+ afterRequest ->
91+ OverlayPermissionAvailability (
92+ OverlayPermissionState .REQUESTABLE ,
93+ R .string.permission_overlay_restricted_settings_hint,
94+ shouldOpenAppInfo = true ,
95+ )
96+ else ->
97+ OverlayPermissionAvailability (OverlayPermissionState .REQUESTABLE )
98+ }
99+
100+ fun notifyOverlayPermissionUnavailable (
101+ context : Context ,
102+ afterRequest : Boolean = false,
103+ ): OverlayPermissionAvailability =
104+ getOverlayPermissionAvailability(context, afterRequest).also { availability ->
105+ availability.messageRes?.let (::flashError)
106+ }
107+
108+ fun requestOverlayPermission (context : Context ): OverlayPermissionAvailability {
109+ val availability = getOverlayPermissionAvailability(context)
110+ if (availability.state != OverlayPermissionState .REQUESTABLE ) {
111+ return notifyOverlayPermissionUnavailable(context)
112+ }
113+
114+ context.launchAppSettingsIntent(Settings .ACTION_MANAGE_OVERLAY_PERMISSION )
115+ return availability
116+ }
117+
118+ fun handlePostOverlayPermissionRequest (context : Context ): OverlayPermissionAvailability =
119+ notifyOverlayPermissionUnavailable(context, afterRequest = true ).also { availability ->
120+ if (availability.shouldOpenAppInfo) {
121+ context.launchAppSettingsIntent(Settings .ACTION_APPLICATION_DETAILS_SETTINGS )
122+ }
123+ }
124+
125+ private fun Context.launchAppSettingsIntent (action : String ) {
126+ val intent =
127+ Intent (action).apply {
128+ putExtra(Settings .EXTRA_APP_PACKAGE , packageName)
129+ data = Uri .fromParts(" package" , packageName, null )
130+ if (this @launchAppSettingsIntent !is Activity ) {
131+ addFlags(Intent .FLAG_ACTIVITY_NEW_TASK )
132+ }
133+ }
134+
135+ try {
136+ startActivity(intent)
137+ } catch (_: Throwable ) {
138+ flashError(getString(R .string.err_no_activity_to_handle_action, action))
139+ }
140+ }
141+
142+ private fun isOverlayPermissionSupported (context : Context ): Boolean {
143+ val activityManager = context.getSystemService(Activity .ACTIVITY_SERVICE ) as ? ActivityManager
144+ val isAndroid10 = Build .VERSION .SDK_INT == Build .VERSION_CODES .Q
145+ val isLowRamDevice = activityManager?.isLowRamDevice ? : false
146+
147+ val isAndroid10GoLike = isAndroid10 && isLowRamDevice
148+ return ! isAndroid10GoLike
149+ }
150+
71151
72152 fun areAllPermissionsGranted (context : Context ): Boolean =
73153 getRequiredPermissions(context).all { it.isOptional || it.isGranted }
@@ -110,4 +190,4 @@ object PermissionsHelper {
110190 context,
111191 permission,
112192 ) == PackageManager .PERMISSION_GRANTED
113- }
193+ }
0 commit comments