Add API to watch permission state
This commit is contained in:
parent
b5005ee4ea
commit
e9703ad778
@ -94,7 +94,7 @@ class CalendarEvent(
|
||||
val results = mutableListOf<CalendarEvent>()
|
||||
if (!query.isEmpty() && query.length < 3) return results
|
||||
if (!LauncherPreferences.instance.searchCalendars) return listOf()
|
||||
if (!permissionsManager.checkPermission(PermissionGroup.Calendar)) {
|
||||
if (!permissionsManager.checkPermissionOnce(PermissionGroup.Calendar)) {
|
||||
return emptyList()
|
||||
}
|
||||
val builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
|
||||
|
||||
@ -81,7 +81,7 @@ class Contact(
|
||||
return mutableListOf()
|
||||
}
|
||||
val permissionsManager: PermissionsManager = get()
|
||||
if (!permissionsManager.checkPermission(PermissionGroup.Contacts)) {
|
||||
if (!permissionsManager.checkPermissionOnce(PermissionGroup.Contacts)) {
|
||||
return mutableListOf()
|
||||
}
|
||||
val proj = arrayOf(
|
||||
|
||||
@ -30,7 +30,7 @@ class LocalFileDeserializer(
|
||||
) : SearchableDeserializer, KoinComponent {
|
||||
override fun deserialize(serialized: String): Searchable? {
|
||||
val permissionsManager: PermissionsManager = get()
|
||||
if (!permissionsManager.checkPermission(
|
||||
if (!permissionsManager.checkPermissionOnce(
|
||||
PermissionGroup.ExternalStorage
|
||||
)
|
||||
) return null
|
||||
|
||||
@ -5,7 +5,6 @@ import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.AdaptiveIconDrawable
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.location.Geocoder
|
||||
import android.media.MediaMetadataRetriever
|
||||
import android.media.ThumbnailUtils
|
||||
@ -13,7 +12,6 @@ import android.os.Build
|
||||
import android.provider.MediaStore
|
||||
import android.text.format.DateUtils
|
||||
import android.util.Size
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.database.getStringOrNull
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
@ -170,7 +168,7 @@ open class LocalFile(
|
||||
if (!LauncherPreferences.instance.searchFiles) return results
|
||||
if (query.isBlank()) return results
|
||||
val permissionsManager: PermissionsManager = get()
|
||||
if (!permissionsManager.checkPermission(
|
||||
if (!permissionsManager.checkPermissionOnce(
|
||||
PermissionGroup.ExternalStorage
|
||||
)
|
||||
) return results
|
||||
|
||||
@ -35,7 +35,7 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.kotlin.stdlib)
|
||||
implementation(libs.bundles.kotlin)
|
||||
implementation(libs.androidx.core)
|
||||
implementation(libs.androidx.appcompat)
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package de.mm20.launcher2.permissions
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
@ -11,11 +12,26 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import de.mm20.launcher2.ktx.checkPermission
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
interface PermissionsManager {
|
||||
fun requestPermission(context: AppCompatActivity, permissionGroup: PermissionGroup)
|
||||
|
||||
fun checkPermission(permissionGroup: PermissionGroup): Boolean
|
||||
/**
|
||||
* Check if this permission is granted right now without receiving further updates
|
||||
* about the granted state.
|
||||
* @return true if the given permission group is fully granted
|
||||
*/
|
||||
fun checkPermissionOnce(permissionGroup: PermissionGroup): Boolean
|
||||
|
||||
fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
)
|
||||
|
||||
fun hasPermission(permissionGroup: PermissionGroup): Flow<Boolean>
|
||||
}
|
||||
|
||||
enum class PermissionGroup {
|
||||
@ -27,18 +43,43 @@ enum class PermissionGroup {
|
||||
|
||||
class PermissionsManagerImpl(
|
||||
private val context: Context
|
||||
): PermissionsManager {
|
||||
) : PermissionsManager {
|
||||
|
||||
private val calendarPermissionState = MutableStateFlow(
|
||||
checkPermissionOnce(PermissionGroup.Calendar)
|
||||
)
|
||||
private val contactsPermissionState = MutableStateFlow(
|
||||
checkPermissionOnce(PermissionGroup.Contacts)
|
||||
)
|
||||
private val externalStoragePermissionState = MutableStateFlow(
|
||||
checkPermissionOnce(PermissionGroup.ExternalStorage)
|
||||
)
|
||||
private val locationPermissionState = MutableStateFlow(
|
||||
checkPermissionOnce(PermissionGroup.Location)
|
||||
)
|
||||
|
||||
override fun requestPermission(activity: AppCompatActivity, permissionGroup: PermissionGroup) {
|
||||
when (permissionGroup) {
|
||||
PermissionGroup.Calendar -> {
|
||||
ActivityCompat.requestPermissions(activity, calendarPermissions, permissionGroup.ordinal)
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
calendarPermissions,
|
||||
permissionGroup.ordinal
|
||||
)
|
||||
}
|
||||
PermissionGroup.Location -> {
|
||||
ActivityCompat.requestPermissions(activity, locationPermissions, permissionGroup.ordinal)
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
locationPermissions,
|
||||
permissionGroup.ordinal
|
||||
)
|
||||
}
|
||||
PermissionGroup.Contacts -> {
|
||||
ActivityCompat.requestPermissions(activity, contactPermissions, permissionGroup.ordinal)
|
||||
ActivityCompat.requestPermissions(
|
||||
activity,
|
||||
contactPermissions,
|
||||
permissionGroup.ordinal
|
||||
)
|
||||
}
|
||||
PermissionGroup.ExternalStorage -> {
|
||||
if (isAtLeastApiLevel(Build.VERSION_CODES.R)) {
|
||||
@ -58,7 +99,7 @@ class PermissionsManagerImpl(
|
||||
}
|
||||
}
|
||||
|
||||
override fun checkPermission(permissionGroup: PermissionGroup): Boolean {
|
||||
override fun checkPermissionOnce(permissionGroup: PermissionGroup): Boolean {
|
||||
return when (permissionGroup) {
|
||||
PermissionGroup.Calendar -> {
|
||||
calendarPermissions.all { context.checkPermission(it) }
|
||||
@ -76,7 +117,30 @@ class PermissionsManagerImpl(
|
||||
externalStoragePermissions.all { context.checkPermission(it) }
|
||||
}
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasPermission(permissionGroup: PermissionGroup): Flow<Boolean> {
|
||||
return when (permissionGroup) {
|
||||
PermissionGroup.Calendar -> calendarPermissionState
|
||||
PermissionGroup.Location -> locationPermissionState
|
||||
PermissionGroup.Contacts -> contactsPermissionState
|
||||
PermissionGroup.ExternalStorage -> externalStoragePermissionState
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
val permissionGroup = PermissionGroup.values().getOrNull(requestCode) ?: return
|
||||
val granted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
|
||||
when (permissionGroup) {
|
||||
PermissionGroup.Calendar -> calendarPermissionState.value = granted
|
||||
PermissionGroup.Location -> locationPermissionState.value = granted
|
||||
PermissionGroup.Contacts -> contactsPermissionState.value = granted
|
||||
PermissionGroup.ExternalStorage -> externalStoragePermissionState.value = granted
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
19
ui/src/main/java/de/mm20/launcher2/ui/base/BaseActivity.kt
Normal file
19
ui/src/main/java/de/mm20/launcher2/ui/base/BaseActivity.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package de.mm20.launcher2.ui.base
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
|
||||
abstract class BaseActivity : AppCompatActivity(), KoinComponent {
|
||||
private val permissionsManager: PermissionsManager by inject()
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
package de.mm20.launcher2.ui.legacy.activity
|
||||
|
||||
import android.Manifest
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.LayoutTransition
|
||||
import android.animation.ObjectAnimator
|
||||
@ -25,15 +24,12 @@ import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Toast
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.*
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.afollestad.materialdialogs.LayoutMode
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
@ -48,11 +44,11 @@ import de.mm20.launcher2.ktx.dp
|
||||
import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
||||
import de.mm20.launcher2.ktx.isBrightColor
|
||||
import de.mm20.launcher2.legacy.helper.ActivityStarter
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.LauncherPreferences
|
||||
import de.mm20.launcher2.transition.ChangingLayoutTransition
|
||||
import de.mm20.launcher2.transition.OneShotLayoutTransition
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.base.BaseActivity
|
||||
import de.mm20.launcher2.ui.databinding.ActivityLauncherBinding
|
||||
import de.mm20.launcher2.ui.launcher.modals.EditFavoritesView
|
||||
import de.mm20.launcher2.ui.launcher.modals.HiddenItemsView
|
||||
@ -60,7 +56,6 @@ import de.mm20.launcher2.ui.launcher.search.SearchViewModel
|
||||
import de.mm20.launcher2.ui.legacy.component.WidgetView
|
||||
import de.mm20.launcher2.ui.legacy.helper.ThemeHelper
|
||||
import de.mm20.launcher2.ui.settings.SettingsActivity
|
||||
import de.mm20.launcher2.weather.WeatherViewModel
|
||||
import de.mm20.launcher2.widgets.Widget
|
||||
import de.mm20.launcher2.widgets.WidgetType
|
||||
import de.mm20.launcher2.widgets.WidgetViewModel
|
||||
@ -71,7 +66,7 @@ import java.util.*
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
class LauncherActivity : AppCompatActivity() {
|
||||
class LauncherActivity : BaseActivity() {
|
||||
|
||||
/**
|
||||
* True if the search result list is visible
|
||||
|
||||
@ -47,7 +47,7 @@ class CalendarView : FrameLayout, KoinComponent {
|
||||
visibility = View.GONE
|
||||
return@observe
|
||||
}
|
||||
if (it.isEmpty() && LauncherPreferences.instance.searchCalendars && !permissionsManager.checkPermission(
|
||||
if (it.isEmpty() && LauncherPreferences.instance.searchCalendars && !permissionsManager.checkPermissionOnce(
|
||||
PermissionGroup.Calendar
|
||||
)
|
||||
) {
|
||||
|
||||
@ -6,7 +6,6 @@ import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.SearchView
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.LiveData
|
||||
@ -47,7 +46,7 @@ class ContactView : FrameLayout, KoinComponent {
|
||||
visibility = View.GONE
|
||||
return@observe
|
||||
}
|
||||
if (it.isEmpty() && LauncherPreferences.instance.searchContacts && !permissionsManager.checkPermission(
|
||||
if (it.isEmpty() && LauncherPreferences.instance.searchContacts && !permissionsManager.checkPermissionOnce(
|
||||
PermissionGroup.Contacts
|
||||
)
|
||||
) {
|
||||
|
||||
@ -45,7 +45,7 @@ class FileView : FrameLayout, KoinComponent {
|
||||
visibility = View.GONE
|
||||
return@observe
|
||||
}
|
||||
if (it.isEmpty() && !permissionsManager.checkPermission(
|
||||
if (it.isEmpty() && !permissionsManager.checkPermissionOnce(
|
||||
PermissionGroup.ExternalStorage
|
||||
)
|
||||
) {
|
||||
|
||||
@ -3,7 +3,6 @@ package de.mm20.launcher2.ui.settings
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.animation.core.tween
|
||||
@ -20,16 +19,15 @@ import de.mm20.launcher2.licenses.OpenSourceLicenses
|
||||
import de.mm20.launcher2.preferences.Settings
|
||||
import de.mm20.launcher2.ui.LegacyLauncherTheme
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.legacy.helper.ThemeHelper
|
||||
import de.mm20.launcher2.ui.base.BaseActivity
|
||||
import de.mm20.launcher2.ui.locals.LocalNavController
|
||||
import de.mm20.launcher2.ui.screens.settings.SettingsLicenseScreen
|
||||
import de.mm20.launcher2.ui.settings.about.AboutScreen
|
||||
import de.mm20.launcher2.ui.settings.appearance.AppearanceScreen
|
||||
import de.mm20.launcher2.ui.settings.license.LicenseScreen
|
||||
import de.mm20.launcher2.ui.settings.main.MainScreen
|
||||
import de.mm20.launcher2.ui.settings.weather.WeatherScreen
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
class SettingsActivity : BaseActivity() {
|
||||
|
||||
private val viewModel: SettingsActivityVM by viewModels()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user