Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 027e67a8 authored by Jonathan Klee's avatar Jonathan Klee
Browse files

feat: ask required runtime permission when adding new account

parent 3bbc08f2
Loading
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import at.bitfire.davdroid.settings.SettingsManager
import at.bitfire.davdroid.syncadapter.AccountUtils
import at.bitfire.davdroid.syncadapter.SyncWorker
import at.bitfire.davdroid.ui.setup.LoginActivity
import at.bitfire.davdroid.util.PermissionUtils
import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
@@ -35,6 +36,7 @@ class AccountsActivity : AppCompatActivity(), NavigationView.OnNavigationItemSel

    private lateinit var binding: ActivityAccountsBinding
    val model by viewModels<Model>()
    private var hasAskedRequiredPermissions = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
@@ -79,6 +81,11 @@ class AccountsActivity : AppCompatActivity(), NavigationView.OnNavigationItemSel
    override fun onResume() {
        super.onResume()
        accountsDrawerHandler.initMenu(this, binding.navView.menu)

        if (!hasAskedRequiredPermissions && PermissionUtils.collectMissingRequiredPermissions(this).isNotEmpty()) {
            hasAskedRequiredPermissions = true
            startActivity(Intent(this, PermissionsActivity::class.java))
        }
    }

    override fun onNavigationItemSelected(item: MenuItem): Boolean {
+5 −4
Original line number Diff line number Diff line
@@ -12,10 +12,11 @@ class PermissionsActivity: AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (savedInstanceState == null)
        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                .add(android.R.id.content, PermissionsFragment())
                .commit()
        }
    }

}
+32 −11
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.MainThread
import androidx.core.content.ContextCompat
@@ -25,31 +26,43 @@ import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import at.bitfire.davdroid.BuildConfig
import at.bitfire.davdroid.PackageChangedReceiver
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.ActivityPermissionsBinding
import at.bitfire.davdroid.util.PermissionUtils
import at.bitfire.davdroid.util.PermissionUtils.CALENDAR_PERMISSIONS
import at.bitfire.davdroid.util.PermissionUtils.CONTACT_PERMISSIONS
import at.bitfire.davdroid.util.PermissionUtils.havePermissions
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.ActivityPermissionsBinding
import at.bitfire.ical4android.TaskProvider
import at.bitfire.ical4android.TaskProvider.ProviderName

class PermissionsFragment: Fragment() {

    val model by viewModels<Model>()

    private lateinit var requestPermission: ActivityResultLauncher<Array<String>>
    private var hasAskedRequiredPermissions = false

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        val binding = ActivityPermissionsBinding.inflate(inflater, container, false)
        binding.lifecycleOwner = viewLifecycleOwner
        binding.model = model

        binding.text.text = getString(R.string.permissions_text, getString(R.string.app_name))

        val requestPermission = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
        initPermissionLauncher()
        observePermissionToggles()
        binding.appSettings.setOnClickListener {
            PermissionUtils.showAppSettings(requireActivity())
        }

        return binding.root
    }

    private fun initPermissionLauncher() {
        requestPermission = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
            model.checkPermissions()
        }
    }

    private fun observePermissionToggles() {
        model.needAutoResetPermission.observe(viewLifecycleOwner) { keepPermissions ->
            if (keepPermissions == true && model.haveAutoResetPermission.value == false) {
                Toast.makeText(requireActivity(), R.string.permissions_autoreset_instruction, Toast.LENGTH_LONG).show()
@@ -95,17 +108,25 @@ class PermissionsFragment: Fragment() {
                requestPermission.launch(all.toTypedArray())
            }
        }

        binding.appSettings.setOnClickListener {
            PermissionUtils.showAppSettings(requireActivity())
        }

        return binding.root
    }

    override fun onResume() {
        super.onResume()
        model.checkPermissions()
        requestMissingPermissions()
    }

    private fun requestMissingPermissions() {
        if (hasAskedRequiredPermissions) {
            return
        }

        val missing = PermissionUtils.collectMissingRequiredPermissions(requireContext())

        if (missing.isNotEmpty()) {
            hasAskedRequiredPermissions = true
            requestPermission.launch(missing.toTypedArray())
        }
    }


+30 −17
Original line number Diff line number Diff line
@@ -13,6 +13,11 @@ import androidx.activity.addCallback
import androidx.annotation.WorkerThread
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import at.bitfire.davdroid.R
import at.bitfire.davdroid.log.Logger
import com.github.appintro.AppIntro2
@@ -50,23 +55,6 @@ class IntroActivity: AppIntro2() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val factories = EntryPointAccessors.fromActivity(this, IntroActivityEntryPoint::class.java).introFragmentFactories()
        for (factory in factories)
            Logger.log.fine("Found intro fragment factory ${factory::class.java} with order ${factory.getOrder(this)}")

        val factoriesWithOrder = factories
            .associateWith { it.getOrder(this) }
            .filterValues { it != IntroFragmentFactory.DONT_SHOW }

        val anyPositiveOrder = factoriesWithOrder.values.any { it > 0 }
        if (anyPositiveOrder) {
            val factoriesSortedByOrder = factoriesWithOrder
                .toList()
                .sortedBy { (_, v) -> v }       // sort by value (= getOrder())
            for ((factory, _) in factoriesSortedByOrder)
                addSlide(factory.create())
        }

        setBarColor(ResourcesCompat.getColor(resources, R.color.accentColor, null))
        isSkipButtonEnabled = false

@@ -78,6 +66,31 @@ class IntroActivity: AppIntro2() {
                goToPreviousSlide()
            }
        }

        val factories = EntryPointAccessors.fromActivity(this, IntroActivityEntryPoint::class.java).introFragmentFactories()

        lifecycleScope.launch {
            val factoriesWithOrder = withContext(Dispatchers.IO) {
                factories.associateWith { it.getOrder(this@IntroActivity) }
                    .filterValues { it != IntroFragmentFactory.DONT_SHOW }
            }

            for (factory in factories) {
                Logger.log.fine("Found intro fragment factory ${factory::class.java} with order ${factoriesWithOrder[factory]}")
            }

            if (!lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
                return@launch
            }

            val anyPositiveOrder = factoriesWithOrder.values.any { it > 0 }
            if (anyPositiveOrder) {
                factoriesWithOrder
                    .toList()
                    .sortedBy { (_, v) -> v }
                    .forEach { (factory, _) -> addSlide(factory.create()) }
            }
        }
    }

    override fun onPageSelected(position: Int) {
+2 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
package at.bitfire.davdroid.ui.intro

import android.content.Context
import androidx.annotation.WorkerThread
import androidx.fragment.app.Fragment

interface IntroFragmentFactory {
@@ -25,6 +26,7 @@ interface IntroFragmentFactory {
     *   * [DONT_SHOW] (0): don't show the fragment
     *   * ≥0: show the fragment (lower numbers are shown first)
     */
    @WorkerThread
    fun getOrder(context: Context): Int

    /**
Loading