From 8915a3c10381aa130e529b9cc0b733977037c3f2 Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Tue, 1 Nov 2022 12:49:06 +0100 Subject: android 13 compatibility (bitfireAT/davx5#155) * check for notify permission before notifying * [WIP] add notification permission request * Revert "check for notify permission before notifying" This reverts commit ed8e046d73163bef5684622bd877f08b9ee781c6. * add notification permission request * [WIP] add notifications disabled card in accounts view * add notifications disabled card in accounts view * reorder permissions * use dp instead of mm for image max height in permissions view * stop using array to bundle notification permissions * Use new permissions contract for PermissionsFragment Co-authored-by: Ricki Hirner --- app/build.gradle | 2 +- .../java/at/bitfire/davdroid/PermissionUtils.kt | 8 +- .../at/bitfire/davdroid/ui/AccountListFragment.kt | 20 +++ .../at/bitfire/davdroid/ui/PermissionsFragment.kt | 38 ++++-- app/src/main/res/drawable/ic_notifications_off.xml | 5 + app/src/main/res/layout/account_list.xml | 35 ++++- app/src/main/res/layout/activity_permissions.xml | 149 +++++++++++++-------- app/src/main/res/values-h480dp/dimen.xml | 2 +- app/src/main/res/values/dimen.xml | 2 +- app/src/main/res/values/strings.xml | 6 + 10 files changed, 188 insertions(+), 79 deletions(-) create mode 100644 app/src/main/res/drawable/ic_notifications_off.xml diff --git a/app/build.gradle b/app/build.gradle index 887b45be..0a015992 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,7 +22,7 @@ android { setProperty "archivesBaseName", "davx5-ose-" + getVersionName() minSdkVersion 21 // Android 5 - targetSdkVersion 32 // Android 12v2 + targetSdkVersion 33 // Android 13 buildConfigField "String", "userAgent", "\"DAVx5\"" diff --git a/app/src/main/java/at/bitfire/davdroid/PermissionUtils.kt b/app/src/main/java/at/bitfire/davdroid/PermissionUtils.kt index 44529956..cc1df668 100644 --- a/app/src/main/java/at/bitfire/davdroid/PermissionUtils.kt +++ b/app/src/main/java/at/bitfire/davdroid/PermissionUtils.kt @@ -23,12 +23,12 @@ import at.bitfire.davdroid.ui.PermissionsActivity object PermissionUtils { val CONTACT_PERMISSIONS = arrayOf( - Manifest.permission.READ_CONTACTS, - Manifest.permission.WRITE_CONTACTS + Manifest.permission.READ_CONTACTS, + Manifest.permission.WRITE_CONTACTS ) val CALENDAR_PERMISSIONS = arrayOf( - Manifest.permission.READ_CALENDAR, - Manifest.permission.WRITE_CALENDAR + Manifest.permission.READ_CALENDAR, + Manifest.permission.WRITE_CALENDAR ) val WIFI_SSID_PERMISSIONS = diff --git a/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt index a1fe1f1a..c7e10564 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/AccountListFragment.kt @@ -4,12 +4,14 @@ package at.bitfire.davdroid.ui +import android.Manifest import android.accounts.Account import android.accounts.AccountManager import android.accounts.OnAccountsUpdateListener import android.app.Activity import android.app.Application import android.content.* +import android.content.pm.PackageManager import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities @@ -18,6 +20,8 @@ import android.os.Build import android.os.Bundle import android.provider.Settings import android.view.* +import androidx.core.content.ContextCompat +import androidx.core.content.PackageManagerCompat import androidx.core.content.getSystemService import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels @@ -29,6 +33,7 @@ import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import at.bitfire.davdroid.DavUtils import at.bitfire.davdroid.DavUtils.SyncStatus +import at.bitfire.davdroid.PermissionUtils import at.bitfire.davdroid.R import at.bitfire.davdroid.StorageLowReceiver import at.bitfire.davdroid.databinding.AccountListBinding @@ -57,6 +62,10 @@ class AccountListFragment: Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + binding.allowNotifications.setOnClickListener { + startActivity(Intent(requireActivity(), PermissionsActivity::class.java)) + } + model.networkAvailable.observe(viewLifecycleOwner) { networkAvailable -> binding.noNetworkInfo.visibility = if (networkAvailable) View.GONE else View.VISIBLE } @@ -103,11 +112,22 @@ class AccountListFragment: Fragment() { } } + override fun onResume() { + super.onResume() + checkPermissions() + } + override fun onDestroyView() { super.onDestroyView() _binding = null } + fun checkPermissions() { + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) + binding.noNotificationsInfo.visibility = View.GONE + else + binding.noNotificationsInfo.visibility = View.VISIBLE + } class AccountAdapter( val activity: Activity diff --git a/app/src/main/java/at/bitfire/davdroid/ui/PermissionsFragment.kt b/app/src/main/java/at/bitfire/davdroid/ui/PermissionsFragment.kt index 9a914b7e..77de939f 100644 --- a/app/src/main/java/at/bitfire/davdroid/ui/PermissionsFragment.kt +++ b/app/src/main/java/at/bitfire/davdroid/ui/PermissionsFragment.kt @@ -4,9 +4,11 @@ package at.bitfire.davdroid.ui +import android.Manifest import android.app.Application 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 @@ -14,7 +16,9 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.MainThread +import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.AndroidViewModel @@ -42,6 +46,10 @@ class PermissionsFragment: Fragment() { binding.text.text = getString(R.string.permissions_text, getString(R.string.app_name)) + val requestPermission = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { + model.checkPermissions() + } + model.needAutoResetPermission.observe(viewLifecycleOwner, { keepPermissions -> if (keepPermissions == true && model.haveAutoResetPermission.value == false) { Toast.makeText(requireActivity(), R.string.permissions_autoreset_instruction, Toast.LENGTH_LONG).show() @@ -50,34 +58,38 @@ class PermissionsFragment: Fragment() { }) model.needContactsPermissions.observe(viewLifecycleOwner, { needContacts -> if (needContacts && model.haveContactsPermissions.value == false) - requestPermissions(CONTACT_PERMISSIONS, 0) + requestPermission.launch(CONTACT_PERMISSIONS) }) model.needCalendarPermissions.observe(viewLifecycleOwner, { needCalendars -> if (needCalendars && model.haveCalendarPermissions.value == false) - requestPermissions(CALENDAR_PERMISSIONS, 0) + requestPermission.launch(CALENDAR_PERMISSIONS) + }) + model.needNotificationPermissions.observe(viewLifecycleOwner, { needNotifications -> + if (needNotifications && model.haveNotificationPermissions.value == false) + requestPermission.launch(arrayOf(Manifest.permission.POST_NOTIFICATIONS)) }) model.needOpenTasksPermissions.observe(viewLifecycleOwner, { needOpenTasks -> if (needOpenTasks == true && model.haveOpenTasksPermissions.value == false) - requestPermissions(TaskProvider.PERMISSIONS_OPENTASKS, 0) + requestPermission.launch(TaskProvider.PERMISSIONS_OPENTASKS) }) model.needTasksOrgPermissions.observe(viewLifecycleOwner, { needTasksOrg -> if (needTasksOrg == true && model.haveTasksOrgPermissions.value == false) - requestPermissions(TaskProvider.PERMISSIONS_TASKS_ORG, 0) + requestPermission.launch(TaskProvider.PERMISSIONS_TASKS_ORG) }) model.needJtxPermissions.observe(viewLifecycleOwner, { needJtx -> if (needJtx == true && model.haveJtxPermissions.value == false) - requestPermissions(TaskProvider.PERMISSIONS_JTX, 0) + requestPermission.launch(TaskProvider.PERMISSIONS_JTX) }) model.needAllPermissions.observe(viewLifecycleOwner, { needAll -> if (needAll && model.haveAllPermissions.value == false) { - val all = mutableSetOf(*CONTACT_PERMISSIONS, *CALENDAR_PERMISSIONS) + val all = mutableSetOf(*CONTACT_PERMISSIONS, *CALENDAR_PERMISSIONS, Manifest.permission.POST_NOTIFICATIONS) if (model.haveOpenTasksPermissions.value != null) all.addAll(TaskProvider.PERMISSIONS_OPENTASKS) if (model.haveTasksOrgPermissions.value != null) all.addAll(TaskProvider.PERMISSIONS_TASKS_ORG) if (model.haveJtxPermissions.value != null) all.addAll(TaskProvider.PERMISSIONS_JTX) - requestPermissions(all.toTypedArray(), 0) + requestPermission.launch(all.toTypedArray()) } }) @@ -93,11 +105,6 @@ class PermissionsFragment: Fragment() { model.checkPermissions() } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - model.checkPermissions() - } - class Model(app: Application): AndroidViewModel(app) { @@ -108,6 +115,8 @@ class PermissionsFragment: Fragment() { val needContactsPermissions = MutableLiveData() val haveCalendarPermissions = MutableLiveData() val needCalendarPermissions = MutableLiveData() + val haveNotificationPermissions = MutableLiveData() + val needNotificationPermissions = MutableLiveData() val haveOpenTasksPermissions = MutableLiveData() val needOpenTasksPermissions = MutableLiveData() @@ -153,6 +162,10 @@ class PermissionsFragment: Fragment() { haveCalendarPermissions.value = calendarPermissions needCalendarPermissions.value = calendarPermissions + val notificationPermissions = ContextCompat.checkSelfPermission(getApplication(), Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED + haveNotificationPermissions.value = notificationPermissions + needNotificationPermissions.value = notificationPermissions + // OpenTasks val openTasksAvailable = pm.resolveContentProvider(ProviderName.OpenTasks.authority, 0) != null var openTasksPermissions: Boolean? = null @@ -190,6 +203,7 @@ class PermissionsFragment: Fragment() { // "all permissions" switch val allPermissions = contactPermissions && calendarPermissions && + notificationPermissions && (!openTasksAvailable || openTasksPermissions == true) && (!tasksOrgAvailable || tasksOrgPermissions == true) && (!jtxAvailable || jtxPermissions == true) diff --git a/app/src/main/res/drawable/ic_notifications_off.xml b/app/src/main/res/drawable/ic_notifications_off.xml new file mode 100644 index 00000000..daa24d19 --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications_off.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/account_list.xml b/app/src/main/res/layout/account_list.xml index 18078361..dfc7d94e 100644 --- a/app/src/main/res/layout/account_list.xml +++ b/app/src/main/res/layout/account_list.xml @@ -5,6 +5,37 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical"> + + + + + +