Skip to content

Commit

Permalink
Merge pull request #4476 from nextcloud/featue/noid/addIgnoreBatteryO…
Browse files Browse the repository at this point in the history
…ptimizationHint

Add permanent warning when notifications are not set up correctly
  • Loading branch information
mahibi authored Nov 26, 2024
2 parents 996720b + 6dc52fe commit f048dc9
Show file tree
Hide file tree
Showing 10 changed files with 288 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ import com.nextcloud.talk.utils.ClosedInterfaceImpl
import com.nextcloud.talk.utils.ConversationUtils
import com.nextcloud.talk.utils.FileUtils
import com.nextcloud.talk.utils.Mimetype
import com.nextcloud.talk.utils.NotificationUtils
import com.nextcloud.talk.utils.ParticipantPermissions
import com.nextcloud.talk.utils.SpreedFeatures
import com.nextcloud.talk.utils.UserIdUtils
Expand All @@ -121,6 +122,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_NEW_CONVERSATION
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.permissions.PlatformPermissionUtil
import com.nextcloud.talk.utils.power.PowerManagerUtils
Expand Down Expand Up @@ -273,6 +275,8 @@ class ConversationsListActivity :
adapter!!.addListener(this)
prepareViews()

updateNotificationWarning()

showShareToScreen = hasActivityActionSendIntent()

if (!eventBus.isRegistered(this)) {
Expand Down Expand Up @@ -303,6 +307,14 @@ class ConversationsListActivity :
showSearchOrToolbar()
}

private fun updateNotificationWarning() {
if (shouldShowNotificationWarning()) {
showNotificationWarning()
} else {
binding.chatListNotificationWarning.visibility = View.GONE
}
}

private fun initObservers() {
this.lifecycleScope.launch {
networkMonitor.isOnline.onEach { isOnline ->
Expand Down Expand Up @@ -763,9 +775,8 @@ class ConversationsListActivity :
)
}

private fun hasActivityActionSendIntent(): Boolean {
return Intent.ACTION_SEND == intent.action || Intent.ACTION_SEND_MULTIPLE == intent.action
}
private fun hasActivityActionSendIntent(): Boolean =
Intent.ACTION_SEND == intent.action || Intent.ACTION_SEND_MULTIPLE == intent.action

private fun showSearchView(searchView: SearchView?, searchItem: MenuItem?) {
binding.conversationListAppbar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
Expand Down Expand Up @@ -1274,10 +1285,9 @@ class ConversationsListActivity :
!participantPermissions.canIgnoreLobby()
}

private fun isReadOnlyConversation(conversation: ConversationModel): Boolean {
return conversation.conversationReadOnlyState ===
private fun isReadOnlyConversation(conversation: ConversationModel): Boolean =
conversation.conversationReadOnlyState ===
ConversationEnums.ConversationReadOnlyState.CONVERSATION_READ_ONLY
}

private fun handleSharedData() {
collectDataFromIntent()
Expand Down Expand Up @@ -1453,8 +1463,9 @@ class ConversationsListActivity :
}

REQUEST_POST_NOTIFICATIONS_PERMISSION -> {
// whenever user allowed notifications, also check to ignore battery optimization
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Notification permission was granted")

if (!PowerManagerUtils().isIgnoringBatteryOptimizations() &&
ClosedInterfaceImpl().isGooglePlayServicesAvailable
) {
Expand Down Expand Up @@ -1490,6 +1501,41 @@ class ConversationsListActivity :
}
}

private fun showNotificationWarning() {
binding.chatListNotificationWarning.visibility = View.VISIBLE
binding.chatListNotificationWarning.setOnClickListener {
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 messagesChannelNotEnabled = !NotificationUtils.isMessagesNotificationChannelEnabled(this)
val callsChannelNotEnabled = !NotificationUtils.isCallsNotificationChannelEnabled(this)

val serverNotificationAppInstalled =
userManager.currentUser.blockingGet().capabilities?.notificationsCapability?.features?.isNotEmpty() ?: false

val settingsOfUserAreWrong = notificationPermissionNotGranted ||
batteryOptimizationNotIgnored ||
messagesChannelNotEnabled ||
callsChannelNotEnabled ||
!serverNotificationAppInstalled

val userWantsToBeNotifiedAboutWrongSettings = appPreferences.getShowNotificationWarning()

return settingsOfUserAreWrong &&
userWantsToBeNotifiedAboutWrongSettings &&
ClosedInterfaceImpl().isGooglePlayServicesAvailable
}

private fun openConversation(textToPaste: String? = "") {
if (CallActivity.active &&
selectedConversation!!.token != ApplicationWideCurrentRoomHolder.getInstance().currentRoomToken
Expand Down
115 changes: 98 additions & 17 deletions app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,14 @@ import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.CapabilitiesUtil
import com.nextcloud.talk.utils.ClosedInterfaceImpl
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.DrawableUtils
import com.nextcloud.talk.utils.LoggingUtils.sendMailWithAttachment
import com.nextcloud.talk.utils.NotificationUtils
import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri
import com.nextcloud.talk.utils.NotificationUtils.getMessageRingtoneUri
import com.nextcloud.talk.utils.SecurityUtils
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.power.PowerManagerUtils
import com.nextcloud.talk.utils.preferences.AppPreferencesImpl
Expand All @@ -101,7 +103,9 @@ import javax.inject.Inject

@Suppress("LargeClass", "TooManyFunctions")
@AutoInjector(NextcloudTalkApplication::class)
class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNumberDialogClickListener {
class SettingsActivity :
BaseActivity(),
SetPhoneNumberDialogFragment.SetPhoneNumberDialogClickListener {
private lateinit var binding: ActivitySettingsBinding

@Inject
Expand Down Expand Up @@ -129,6 +133,7 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
private lateinit var phoneBookIntegrationFlow: Flow<Boolean>
private var profileQueryDisposable: Disposable? = null
private var dbQueryDisposable: Disposable? = null
private var openedByNotificationWarning: Boolean = false

@SuppressLint("StringFormatInvalid")
override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -143,6 +148,7 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
binding.avatarImage.let { ViewCompat.setTransitionName(it, "userAvatar.transitionTag") }

getCurrentUser()
handleIntent(intent)

setupLicenceSetting()

Expand All @@ -162,6 +168,11 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
setupClientCertView()
}

private fun handleIntent(intent: Intent) {
val extras: Bundle? = intent.extras
openedByNotificationWarning = extras?.getBoolean(KEY_SCROLL_TO_NOTIFICATION_CATEGORY) ?: false
}

override fun onResume() {
super.onResume()
supportActionBar?.show()
Expand Down Expand Up @@ -210,6 +221,22 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu

themeTitles()
themeSwitchPreferences()

if (openedByNotificationWarning) {
scrollToNotificationCategory()
}
}

@Suppress("MagicNumber")
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.scrollBy(0, offset)
}
}

private fun loadCapabilitiesAndUpdateSettings() {
Expand Down Expand Up @@ -255,11 +282,9 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
}

private fun setupNotificationSettings() {
binding.settingsNotificationsTitle.text = resources!!.getString(
R.string.nc_settings_notification_sounds_post_oreo
)
setupNotificationSoundsSettings()
setupNotificationPermissionSettings()
setupServerNotificationAppCheck()
}

@SuppressLint("StringFormatInvalid")
Expand All @@ -281,6 +306,10 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
resources!!.getString(R.string.nc_diagnose_battery_optimization_not_ignored)
binding.batteryOptimizationIgnored.setTextColor(resources.getColor(R.color.nc_darkRed, null))

if (openedByNotificationWarning) {
DrawableUtils.blinkDrawable(binding.settingsBatteryOptimizationWrapper.background)
}

binding.settingsBatteryOptimizationWrapper.setOnClickListener {
val dialogText = String.format(
context.resources.getString(R.string.nc_ignore_battery_optimization_dialog_text),
Expand Down Expand Up @@ -313,12 +342,26 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
binding.ncDiagnoseNotificationPermissionSubtitle.setTextColor(
resources.getColor(R.color.high_emphasis_text, null)
)
binding.settingsCallSound.isEnabled = true
binding.settingsCallSound.alpha = ENABLED_ALPHA
binding.settingsMessageSound.isEnabled = true
binding.settingsMessageSound.alpha = ENABLED_ALPHA
} else {
binding.ncDiagnoseNotificationPermissionSubtitle.text =
resources.getString(R.string.nc_settings_notifications_declined)
binding.ncDiagnoseNotificationPermissionSubtitle.setTextColor(
resources.getColor(R.color.nc_darkRed, null)
)

if (openedByNotificationWarning) {
DrawableUtils.blinkDrawable(binding.settingsNotificationsPermissionWrapper.background)
}

binding.settingsCallSound.isEnabled = false
binding.settingsCallSound.alpha = DISABLED_ALPHA
binding.settingsMessageSound.isEnabled = false
binding.settingsMessageSound.alpha = DISABLED_ALPHA

binding.settingsNotificationsPermissionWrapper.setOnClickListener {
requestPermissions(
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
Expand Down Expand Up @@ -346,6 +389,10 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
ResourcesCompat.getColor(context.resources, R.color.nc_darkRed, null)
)
binding.callsRingtone.text = resources!!.getString(R.string.nc_common_disabled)

if (openedByNotificationWarning) {
DrawableUtils.blinkDrawable(binding.settingsCallSound.background)
}
}

if (NotificationUtils.isMessagesNotificationChannelEnabled(this)) {
Expand All @@ -357,6 +404,10 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
ResourcesCompat.getColor(context.resources, R.color.nc_darkRed, null)
)
binding.messagesRingtone.text = resources!!.getString(R.string.nc_common_disabled)

if (openedByNotificationWarning) {
DrawableUtils.blinkDrawable(binding.settingsMessageSound.background)
}
}

binding.settingsCallSound.setOnClickListener {
Expand Down Expand Up @@ -426,6 +477,24 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
}
}

private fun setupServerNotificationAppCheck() {
val serverNotificationAppInstalled =
userManager.currentUser.blockingGet().capabilities?.notificationsCapability?.features?.isNotEmpty() ?: false
if (!serverNotificationAppInstalled) {
binding.settingsServerNotificationAppWrapper.visibility = View.VISIBLE

val description = context.getString(R.string.nc_settings_contact_admin_of) + LINEBREAK +
userManager.currentUser.blockingGet().baseUrl!!

binding.settingsServerNotificationAppDescription.text = description
if (openedByNotificationWarning) {
DrawableUtils.blinkDrawable(binding.settingsServerNotificationAppWrapper.background)
}
} else {
binding.settingsServerNotificationAppWrapper.visibility = View.GONE
}
}

private fun setupSourceCodeUrl() {
if (!TextUtils.isEmpty(resources!!.getString(R.string.nc_source_code_url))) {
binding.settingsSourceCode.setOnClickListener {
Expand Down Expand Up @@ -646,8 +715,8 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
startActivity(intent)
}

private fun getRingtoneName(context: Context, ringtoneUri: Uri?): String {
return if (ringtoneUri == null) {
private fun getRingtoneName(context: Context, ringtoneUri: Uri?): String =
if (ringtoneUri == null) {
resources!!.getString(R.string.nc_settings_no_ringtone)
} else if ((NotificationUtils.DEFAULT_CALL_RINGTONE_URI == ringtoneUri.toString()) ||
(NotificationUtils.DEFAULT_MESSAGE_RINGTONE_URI == ringtoneUri.toString())
Expand All @@ -657,11 +726,11 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
val r = RingtoneManager.getRingtone(context, ringtoneUri)
r.getTitle(context)
}
}

private fun themeSwitchPreferences() {
binding.run {
listOf(
settingsShowNotificationWarningSwitch,
settingsScreenLockSwitch,
settingsScreenSecuritySwitch,
settingsIncognitoKeyboardSwitch,
Expand Down Expand Up @@ -857,6 +926,19 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
}

private fun setupCheckables() {
binding.settingsShowNotificationWarningSwitch.isChecked =
appPreferences.showNotificationWarning

if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) {
binding.settingsShowNotificationWarning.setOnClickListener {
val isChecked = binding.settingsShowNotificationWarningSwitch.isChecked
binding.settingsShowNotificationWarningSwitch.isChecked = !isChecked
appPreferences.setShowNotificationWarning(!isChecked)
}
} else {
binding.settingsShowNotificationWarning.visibility = View.GONE
}

binding.settingsScreenSecuritySwitch.isChecked = appPreferences.isScreenSecured

binding.settingsIncognitoKeyboardSwitch.isChecked = appPreferences.isKeyboardIncognito
Expand Down Expand Up @@ -1067,16 +1149,14 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu

ConversationsListActivity.REQUEST_POST_NOTIFICATIONS_PERMISSION -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_DENIED) {
Snackbar.make(
binding.root,
context.resources.getString(R.string.nc_settings_notifications_declined_hint),
Snackbar.LENGTH_LONG
).show()
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."
)
try {
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
startActivity(intent)
} catch (e: Exception) {
Log.e(TAG, "Failed to open notification settings as fallback", e)
}
}
}
}
Expand Down Expand Up @@ -1344,6 +1424,7 @@ class SettingsActivity : BaseActivity(), SetPhoneNumberDialogFragment.SetPhoneNu
private const val START_DELAY: Long = 5000
private const val DISABLED_ALPHA: Float = 0.38f
private const val ENABLED_ALPHA: Float = 1.0f
private const val LINEBREAK = "\n"
const val HTTP_CODE_OK: Int = 200
const val HTTP_ERROR_CODE_BAD_REQUEST: Int = 400
}
Expand Down
Loading

0 comments on commit f048dc9

Please sign in to comment.