Show a warning if notifications are not allowed or battery optimization is enabled

Open notification settings when click on warning

Also, still offer to enable notifications and disable battery optimization on first install

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2024-11-25 13:18:51 +01:00
parent 716dfa6577
commit b1e550b049
No known key found for this signature in database
GPG key ID: C793F8B59F43CE7B
8 changed files with 135 additions and 95 deletions

View file

@ -121,6 +121,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FORWARD_MSG_TEXT
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NEW_CONVERSATION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NEW_CONVERSATION
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SCROLL_TO_NOTIFICATION_CATEGORY
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARED_TEXT import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARED_TEXT
import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil
import com.nextcloud.talk.utils.power.PowerManagerUtils import com.nextcloud.talk.utils.power.PowerManagerUtils
@ -273,11 +274,7 @@ class ConversationsListActivity :
adapter!!.addListener(this) adapter!!.addListener(this)
prepareViews() prepareViews()
if (shouldShowIgnoreBatteryOptimizationHint()) { updateNotificationWarning()
showIgnoreBatteryOptimizationHint()
} else {
binding.chatListBatteryOptimizationIgnoredHint.visibility = View.GONE
}
showShareToScreen = hasActivityActionSendIntent() showShareToScreen = hasActivityActionSendIntent()
@ -309,6 +306,14 @@ class ConversationsListActivity :
showSearchOrToolbar() showSearchOrToolbar()
} }
private fun updateNotificationWarning() {
if (shouldShowNotificationWarning()) {
showNotificationWarning()
} else {
binding.chatListNotificationWarning.visibility = View.GONE
}
}
private fun initObservers() { private fun initObservers() {
this.lifecycleScope.launch { this.lifecycleScope.launch {
networkMonitor.isOnline.onEach { isOnline -> networkMonitor.isOnline.onEach { isOnline ->
@ -1461,21 +1466,10 @@ class ConversationsListActivity :
REQUEST_POST_NOTIFICATIONS_PERMISSION -> { REQUEST_POST_NOTIFICATIONS_PERMISSION -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Notification permission was granted") Log.d(TAG, "Notification permission was granted")
} else {
Log.d(
TAG,
"Notification permission is denied. Either because user denied it when being asked. " +
"Or permission is already denied and android decided to not offer the dialog."
)
}
}
}
}
@SuppressLint("StringFormatInvalid")
private fun showIgnoreBatteryOptimizationHint() {
binding.chatListBatteryOptimizationIgnoredHint.visibility = View.VISIBLE
if (!PowerManagerUtils().isIgnoringBatteryOptimizations() &&
ClosedInterfaceImpl().isGooglePlayServicesAvailable
) {
val dialogText = String.format( val dialogText = String.format(
context.resources.getString(R.string.nc_ignore_battery_optimization_dialog_text), context.resources.getString(R.string.nc_ignore_battery_optimization_dialog_text),
context.resources.getString(R.string.nc_app_name) context.resources.getString(R.string.nc_app_name)
@ -1491,20 +1485,45 @@ class ConversationsListActivity :
} }
.setNegativeButton(R.string.nc_common_dismiss, null) .setNegativeButton(R.string.nc_common_dismiss, null)
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, dialogBuilder) viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, dialogBuilder)
binding.chatListBatteryOptimizationIgnoredHint.setOnClickListener {
val dialog = dialogBuilder.show() val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons( viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE), dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE) dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
) )
} }
} else {
Log.d(
TAG,
"Notification permission is denied. Either because user denied it when being asked. " +
"Or permission is already denied and android decided to not offer the dialog."
)
}
}
}
} }
private fun shouldShowIgnoreBatteryOptimizationHint() : Boolean { private fun showNotificationWarning() {
return !PowerManagerUtils().isIgnoringBatteryOptimizations() && binding.chatListNotificationWarning.visibility = View.VISIBLE
ClosedInterfaceImpl().isGooglePlayServicesAvailable && binding.chatListNotificationWarning.setOnClickListener {
appPreferences.getShowIgnoreBatteryOptimizationHint() val bundle = Bundle()
bundle.putBoolean(KEY_SCROLL_TO_NOTIFICATION_CATEGORY, true)
val settingsIntent = Intent(context, SettingsActivity::class.java)
settingsIntent.putExtras(bundle)
startActivity(settingsIntent)
}
}
private fun shouldShowNotificationWarning() : Boolean {
val notificationPermissionNotGranted = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
!platformPermissionUtil.isPostNotificationsPermissionGranted()
val batteryOptimizationNotIgnored = !PowerManagerUtils().isIgnoringBatteryOptimizations()
val settingsOfUserAreWrong = notificationPermissionNotGranted || batteryOptimizationNotIgnored
val userWantsToBeNotifiedAboutWrongSettings = appPreferences.getShowNotificationWarning()
return settingsOfUserAreWrong &&
userWantsToBeNotifiedAboutWrongSettings &&
ClosedInterfaceImpl().isGooglePlayServicesAvailable
} }
private fun openConversation(textToPaste: String? = "") { private fun openConversation(textToPaste: String? = "") {

View file

@ -77,6 +77,7 @@ import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
import com.nextcloud.talk.utils.NotificationUtils.getMessageRingtoneUri import com.nextcloud.talk.utils.NotificationUtils.getMessageRingtoneUri
import com.nextcloud.talk.utils.SecurityUtils import com.nextcloud.talk.utils.SecurityUtils
import com.nextcloud.talk.utils.SpreedFeatures import com.nextcloud.talk.utils.SpreedFeatures
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SCROLL_TO_NOTIFICATION_CATEGORY
import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil
import com.nextcloud.talk.utils.power.PowerManagerUtils import com.nextcloud.talk.utils.power.PowerManagerUtils
import com.nextcloud.talk.utils.preferences.AppPreferencesImpl import com.nextcloud.talk.utils.preferences.AppPreferencesImpl
@ -129,6 +130,7 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
private lateinit var phoneBookIntegrationFlow: Flow<Boolean> private lateinit var phoneBookIntegrationFlow: Flow<Boolean>
private var profileQueryDisposable: Disposable? = null private var profileQueryDisposable: Disposable? = null
private var dbQueryDisposable: Disposable? = null private var dbQueryDisposable: Disposable? = null
private var scrollToNotificationCategory: Boolean? = false
@SuppressLint("StringFormatInvalid") @SuppressLint("StringFormatInvalid")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -143,6 +145,7 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
binding.avatarImage.let { ViewCompat.setTransitionName(it, "userAvatar.transitionTag") } binding.avatarImage.let { ViewCompat.setTransitionName(it, "userAvatar.transitionTag") }
getCurrentUser() getCurrentUser()
handleIntent(intent)
setupLicenceSetting() setupLicenceSetting()
@ -162,6 +165,11 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
setupClientCertView() setupClientCertView()
} }
private fun handleIntent(intent: Intent) {
val extras: Bundle? = intent.extras
scrollToNotificationCategory = extras?.getBoolean(KEY_SCROLL_TO_NOTIFICATION_CATEGORY)
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
supportActionBar?.show() supportActionBar?.show()
@ -210,6 +218,21 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
themeTitles() themeTitles()
themeSwitchPreferences() themeSwitchPreferences()
if (scrollToNotificationCategory == true) {
scrollToNotificationCategory()
}
}
private fun scrollToNotificationCategory() {
binding.scrollView.post {
val scrollViewLocation = IntArray(2)
val targetLocation = IntArray(2)
binding.scrollView.getLocationOnScreen(scrollViewLocation)
binding.settingsNotificationsCategory.getLocationOnScreen(targetLocation)
val offset = targetLocation[1] - scrollViewLocation[1]
binding.scrollView.smoothScrollBy(0, offset)
}
} }
private fun loadCapabilitiesAndUpdateSettings() { private fun loadCapabilitiesAndUpdateSettings() {
@ -255,9 +278,6 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
} }
private fun setupNotificationSettings() { private fun setupNotificationSettings() {
binding.settingsNotificationsTitle.text = resources!!.getString(
R.string.nc_settings_notification_sounds_post_oreo
)
setupNotificationSoundsSettings() setupNotificationSoundsSettings()
setupNotificationPermissionSettings() setupNotificationPermissionSettings()
} }
@ -662,7 +682,7 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
private fun themeSwitchPreferences() { private fun themeSwitchPreferences() {
binding.run { binding.run {
listOf( listOf(
settingsShowIgnoreBatteryOptimizationHintSwitch, settingsShowNotificationWarningSwitch,
settingsScreenLockSwitch, settingsScreenLockSwitch,
settingsScreenSecuritySwitch, settingsScreenSecuritySwitch,
settingsIncognitoKeyboardSwitch, settingsIncognitoKeyboardSwitch,
@ -858,17 +878,17 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
} }
private fun setupCheckables() { private fun setupCheckables() {
binding.settingsShowIgnoreBatteryOptimizationHintSwitch.isChecked = binding.settingsShowNotificationWarningSwitch.isChecked =
appPreferences.showIgnoreBatteryOptimizationHint appPreferences.showNotificationWarning
if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) { if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) {
binding.settingsShowIgnoreBatteryOptimizationHint.setOnClickListener { binding.settingsShowNotificationWarning.setOnClickListener {
val isChecked = binding.settingsShowIgnoreBatteryOptimizationHintSwitch.isChecked val isChecked = binding.settingsShowNotificationWarningSwitch.isChecked
binding.settingsShowIgnoreBatteryOptimizationHintSwitch.isChecked = !isChecked binding.settingsShowNotificationWarningSwitch.isChecked = !isChecked
appPreferences.setShowIgnoreBatteryOptimizationHint(!isChecked) appPreferences.setShowNotificationWarning(!isChecked)
} }
} else { } else {
binding.settingsShowIgnoreBatteryOptimizationHint.visibility = View.GONE binding.settingsShowNotificationWarning.visibility = View.GONE
} }
binding.settingsScreenSecuritySwitch.isChecked = appPreferences.isScreenSecured binding.settingsScreenSecuritySwitch.isChecked = appPreferences.isScreenSecured

View file

@ -80,4 +80,5 @@ object BundleKeys {
const val KEY_CREDENTIALS: String = "KEY_CREDENTIALS" const val KEY_CREDENTIALS: String = "KEY_CREDENTIALS"
const val KEY_FIELD_MAP: String = "KEY_FIELD_MAP" const val KEY_FIELD_MAP: String = "KEY_FIELD_MAP"
const val KEY_CHAT_URL: String = "KEY_CHAT_URL" const val KEY_CHAT_URL: String = "KEY_CHAT_URL"
const val KEY_SCROLL_TO_NOTIFICATION_CATEGORY: String = "KEY_SCROLL_TO_NOTIFICATION_CATEGORY"
} }

View file

@ -178,9 +178,9 @@ public interface AppPreferences {
void deleteAllMessageQueuesFor(String userId); void deleteAllMessageQueuesFor(String userId);
boolean getShowIgnoreBatteryOptimizationHint(); boolean getShowNotificationWarning();
void setShowIgnoreBatteryOptimizationHint(boolean showIgnoreBatteryOptimizationHint); void setShowNotificationWarning(boolean showNotificationWarning);
void clear(); void clear();
} }

View file

@ -544,16 +544,16 @@ class AppPreferencesImpl(val context: Context) : AppPreferences {
} }
} }
override fun getShowIgnoreBatteryOptimizationHint(): Boolean { override fun getShowNotificationWarning(): Boolean {
return runBlocking { async { return runBlocking { async {
readBoolean(SHOW_IGNORE_BATTERY_OPTIMIZATION_HINT, true).first() readBoolean(SHOW_NOTIFICATION_WARNING, true).first()
} }.getCompleted() } }.getCompleted()
} }
override fun setShowIgnoreBatteryOptimizationHint(showIgnoreBatteryOptimizationHint: Boolean) = override fun setShowNotificationWarning(showNotificationWarning: Boolean) =
runBlocking<Unit> { runBlocking<Unit> {
async { async {
writeBoolean(SHOW_IGNORE_BATTERY_OPTIMIZATION_HINT, showIgnoreBatteryOptimizationHint) writeBoolean(SHOW_NOTIFICATION_WARNING, showNotificationWarning)
} }
} }
@ -641,7 +641,7 @@ class AppPreferencesImpl(val context: Context) : AppPreferences {
const val PHONE_BOOK_INTEGRATION_LAST_RUN = "phone_book_integration_last_run" const val PHONE_BOOK_INTEGRATION_LAST_RUN = "phone_book_integration_last_run"
const val TYPING_STATUS = "typing_status" const val TYPING_STATUS = "typing_status"
const val MESSAGE_QUEUE = "@message_queue" const val MESSAGE_QUEUE = "@message_queue"
const val SHOW_IGNORE_BATTERY_OPTIMIZATION_HINT = "show_ignore_battery_optimization_hint" const val SHOW_NOTIFICATION_WARNING = "show_notification_warning"
private fun String.convertStringToArray(): Array<Float> { private fun String.convertStringToArray(): Array<Float> {
var varString = this var varString = this
val floatList = mutableListOf<Float>() val floatList = mutableListOf<Float>()

View file

@ -38,13 +38,13 @@
tools:visibility="visible" /> tools:visibility="visible" />
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
android:id="@+id/chat_list_battery_optimization_ignored_hint" android:id="@+id/chat_list_notification_warning"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/nc_warning" android:background="@color/nc_warning"
android:gravity="center" android:gravity="center"
android:minHeight="40dp" android:minHeight="40dp"
android:text="@string/nc_diagnose_battery_optimization_not_ignored" android:text="@string/nc_notification_warning"
android:textColor="@color/white" android:textColor="@color/white"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" /> tools:visibility="visible" />

View file

@ -201,7 +201,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/standard_margin" android:layout_margin="@dimen/standard_margin"
android:text="@string/nc_settings_notification_sounds" android:text="@string/nc_settings_notification_sounds_post_oreo"
android:textSize="@dimen/headline_text_size" android:textSize="@dimen/headline_text_size"
android:textStyle="bold"/> android:textStyle="bold"/>
@ -211,6 +211,42 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout
android:id="@+id/settings_show_notification_warning"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:padding="@dimen/standard_padding">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nc_show_notification_warning_title"
android:textSize="@dimen/headline_text_size"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/settings_show_notification_warning_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nc_show_notification_warning_description"/>
</LinearLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/settings_show_notification_warning_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:gravity="center_vertical"/>
</LinearLayout>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/settings_notifications_permission_wrapper" android:id="@+id/settings_notifications_permission_wrapper"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -252,42 +288,6 @@
tools:text="@string/nc_diagnose_battery_optimization_ignored"/> tools:text="@string/nc_diagnose_battery_optimization_ignored"/>
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/settings_show_ignore_battery_optimization_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:padding="@dimen/standard_padding">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nc_show_ignore_battery_optimization_hint_title"
android:textSize="@dimen/headline_text_size"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/settings_show_ignore_battery_optimization_hint_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nc_show_ignore_battery_optimization_hint_description"/>
</LinearLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/settings_show_ignore_battery_optimization_hint_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:gravity="center_vertical"/>
</LinearLayout>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/settings_gplay_not_available" android:id="@+id/settings_gplay_not_available"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -101,7 +101,6 @@ How to translate with transifex:
<string name="nc_settings_no_talk_installed">Talk app is not installed on the server you tried to authenticate against</string> <string name="nc_settings_no_talk_installed">Talk app is not installed on the server you tried to authenticate against</string>
<string name="nc_settings_account_updated">Your already existing account was updated, instead of adding a new one</string> <string name="nc_settings_account_updated">Your already existing account was updated, instead of adding a new one</string>
<string name="nc_account_scheduled_for_deletion">The account is scheduled for deletion, and cannot be changed</string> <string name="nc_account_scheduled_for_deletion">The account is scheduled for deletion, and cannot be changed</string>
<string name="nc_settings_notification_sounds">Notification sounds</string>
<string name="nc_settings_notification_sounds_post_oreo">Notifications</string> <string name="nc_settings_notification_sounds_post_oreo">Notifications</string>
<string name="nc_settings_call_ringtone">Calls</string> <string name="nc_settings_call_ringtone">Calls</string>
<string name="nc_settings_call_ringtone_key" translatable="false">call_ringtone</string> <string name="nc_settings_call_ringtone_key" translatable="false">call_ringtone</string>
@ -181,8 +180,9 @@ How to translate with transifex:
<string name="nc_ignore_battery_optimization_dialog_title">Ignore battery optimization</string> <string name="nc_ignore_battery_optimization_dialog_title">Ignore battery optimization</string>
<string name="nc_ignore_battery_optimization_dialog_text">Battery optimization is not ignored. This should be changed to make sure that notifications work in the background! Please click OK and select \"All apps\" -> %1$s -> Do not optimize</string> <string name="nc_ignore_battery_optimization_dialog_text">Battery optimization is not ignored. This should be changed to make sure that notifications work in the background! Please click OK and select \"All apps\" -> %1$s -> Do not optimize</string>
<string name="nc_show_ignore_battery_optimization_hint_title">Show battery optimization hint</string> <string name="nc_show_notification_warning_title">Show notification warning</string>
<string name="nc_show_ignore_battery_optimization_hint_description">When the battery optimization is not ignored, show a hint</string> <string name="nc_show_notification_warning_description">When notifications are not set up correctly, show a warning</string>
<string name="nc_notification_warning">Notifications are not set up correctly</string>
<string name="nc_diagnose_meta_category_title">Meta information</string> <string name="nc_diagnose_meta_category_title">Meta information</string>
<string name="nc_diagnose_meta_system_report_date">Generation of system report</string> <string name="nc_diagnose_meta_system_report_date">Generation of system report</string>