diff --git a/.idea/dictionaries/bmarty.xml b/.idea/dictionaries/bmarty.xml index f351ec8bfd..7e9a9e1b03 100644 --- a/.idea/dictionaries/bmarty.xml +++ b/.idea/dictionaries/bmarty.xml @@ -19,6 +19,7 @@ msisdn pbkdf pkcs + riotx signin signout signup diff --git a/CHANGES.md b/CHANGES.md index 7c31f37b0d..9efbbbf5e5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ Improvements 🙌: - Detect spaces in password if user fail to login (#1038) - FTUE: do not display a different color when encrypting message when not in developer mode. - Open room member profile from avatar of the room member state event (#935) + - Restore the push rules configuration in the settings Bugfix 🐛: - Fix crash on attachment preview screen (#1088) @@ -20,7 +21,7 @@ Translations 🗣: - SDK API changes ⚠️: - - + - PushRuleService.getPushRules() now returns a RuleSet. Use getAllRules() on this object to get all the rules. Build 🧱: - Upgrade ktlint to version 0.36.0 diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt index 0ef70eb99b..1c1c2f266c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/PushRuleService.kt @@ -17,25 +17,24 @@ package im.vector.matrix.android.api.pushrules import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.pushrules.rest.PushRule +import im.vector.matrix.android.api.pushrules.rest.RuleSet import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.util.Cancelable interface PushRuleService { - /** * Fetch the push rules from the server */ fun fetchPushRules(scope: String = RuleScope.GLOBAL) - // TODO get push rule set - fun getPushRules(scope: String = RuleScope.GLOBAL): List - - // TODO update rule + fun getPushRules(scope: String = RuleScope.GLOBAL): RuleSet fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback): Cancelable fun addPushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback): Cancelable + fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule, callback: MatrixCallback): Cancelable + fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback): Cancelable fun addPushRuleListener(listener: PushRuleListener) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/GetPushRulesResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/GetPushRulesResponse.kt index c5f03aed41..2ce6c8364a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/GetPushRulesResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/GetPushRulesResponse.kt @@ -20,6 +20,7 @@ import com.squareup.moshi.JsonClass /** * All push rulesets for a user. + * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules */ @JsonClass(generateAdapter = true) internal data class GetPushRulesResponse( @@ -27,11 +28,11 @@ internal data class GetPushRulesResponse( * Global rules, account level applying to all devices */ @Json(name = "global") - val global: Ruleset, + val global: RuleSet, /** * Device specific rules, apply only to current device */ @Json(name = "device") - val device: Ruleset? = null + val device: RuleSet? = null ) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt index cc19e6a7d1..edfb56e019 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushCondition.kt @@ -24,21 +24,27 @@ import im.vector.matrix.android.api.pushrules.RoomMemberCountCondition import im.vector.matrix.android.api.pushrules.SenderNotificationPermissionCondition import timber.log.Timber +/** + * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules + */ @JsonClass(generateAdapter = true) data class PushCondition( /** * Required. The kind of condition to apply. */ + @Json(name = "kind") val kind: String, /** * Required for event_match conditions. The dot- separated field of the event to match. */ + @Json(name = "key") val key: String? = null, /** * Required for event_match conditions. */ + @Json(name = "pattern") val pattern: String? = null, /** @@ -47,7 +53,8 @@ data class PushCondition( * A prefix of < matches rooms where the member count is strictly less than the given number and so forth. * If no prefix is present, this parameter defaults to ==. */ - @Json(name = "is") val iz: String? = null + @Json(name = "is") + val iz: String? = null ) { fun asExecutableCondition(): Condition? { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushRule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushRule.kt index e9423d7c40..8611f124e8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushRule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/PushRule.kt @@ -18,31 +18,158 @@ package im.vector.matrix.android.api.pushrules.rest import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import im.vector.matrix.android.api.pushrules.Action +import im.vector.matrix.android.api.pushrules.getActions +import im.vector.matrix.android.api.pushrules.toJson +/** + * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules + */ @JsonClass(generateAdapter = true) data class PushRule( /** * Required. The actions to perform when this rule is matched. */ + @Json(name = "actions") val actions: List, /** * Required. Whether this is a default rule, or has been set explicitly. */ + @Json(name = "default") val default: Boolean? = false, /** * Required. Whether the push rule is enabled or not. */ + @Json(name = "enabled") val enabled: Boolean, /** * Required. The ID of this rule. */ - @Json(name = "rule_id") val ruleId: String, + @Json(name = "rule_id") + val ruleId: String, /** * The conditions that must hold true for an event in order for a rule to be applied to an event */ + @Json(name = "conditions") val conditions: List? = null, /** * The glob-style pattern to match against. Only applicable to content rules. */ + @Json(name = "pattern") val pattern: String? = null -) +) { + /** + * Add the default notification sound. + */ + fun setNotificationSound(): PushRule { + return setNotificationSound(ACTION_VALUE_DEFAULT) + } + + fun getNotificationSound(): String? { + return (getActions().firstOrNull { it is Action.Sound } as? Action.Sound)?.sound + } + + /** + * Set the notification sound + * + * @param sound notification sound + */ + fun setNotificationSound(sound: String): PushRule { + return copy( + actions = (getActions().filter { it !is Action.Sound } + Action.Sound(sound)).toJson() + ) + } + + /** + * Remove the notification sound + */ + fun removeNotificationSound(): PushRule { + return copy( + actions = getActions().filter { it !is Action.Sound }.toJson() + ) + } + + /** + * Set the highlight status. + * + * @param highlight the highlight status + */ + fun setHighlight(highlight: Boolean): PushRule { + return copy( + actions = (getActions().filter { it !is Action.Highlight } + Action.Highlight(highlight)).toJson() + ) + } + + /** + * Set the notification status. + * + * @param notify true to notify + */ + fun setNotify(notify: Boolean): PushRule { + val mutableActions = actions.toMutableList() + + mutableActions.remove(ACTION_DONT_NOTIFY) + mutableActions.remove(ACTION_NOTIFY) + + if (notify) { + mutableActions.add(ACTION_NOTIFY) + } else { + mutableActions.add(ACTION_DONT_NOTIFY) + } + + return copy(actions = mutableActions) + } + + /** + * Return true if the rule should highlight the event. + * + * @return true if the rule should play sound + */ + fun shouldNotify() = actions.contains(ACTION_NOTIFY) + + /** + * Return true if the rule should not highlight the event. + * + * @return true if the rule should not play sound + */ + fun shouldNotNotify() = actions.contains(ACTION_DONT_NOTIFY) + + companion object { + /* ========================================================================================== + * Rule id + * ========================================================================================== */ + + const val RULE_ID_DISABLE_ALL = ".m.rule.master" + const val RULE_ID_CONTAIN_USER_NAME = ".m.rule.contains_user_name" + const val RULE_ID_CONTAIN_DISPLAY_NAME = ".m.rule.contains_display_name" + const val RULE_ID_ONE_TO_ONE_ROOM = ".m.rule.room_one_to_one" + const val RULE_ID_INVITE_ME = ".m.rule.invite_for_me" + const val RULE_ID_PEOPLE_JOIN_LEAVE = ".m.rule.member_event" + const val RULE_ID_CALL = ".m.rule.call" + const val RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS = ".m.rule.suppress_notices" + const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message" + const val RULE_ID_AT_ROOMS = ".m.rule.roomnotif" + const val RULE_ID_TOMBSTONE = ".m.rule.tombstone" + const val RULE_ID_E2E_ONE_TO_ONE_ROOM = ".m.rule.encrypted_room_one_to_one" + const val RULE_ID_E2E_GROUP = ".m.rule.encrypted" + const val RULE_ID_REACTION = ".m.rule.reaction" + const val RULE_ID_FALLBACK = ".m.rule.fallback" + + /* ========================================================================================== + * Actions + * ========================================================================================== */ + + const val ACTION_NOTIFY = "notify" + const val ACTION_DONT_NOTIFY = "dont_notify" + const val ACTION_COALESCE = "coalesce" + + const val ACTION_SET_TWEAK_SOUND_VALUE = "sound" + const val ACTION_SET_TWEAK_HIGHLIGHT_VALUE = "highlight" + + const val ACTION_PARAMETER_SET_TWEAK = "set_tweak" + const val ACTION_PARAMETER_VALUE = "value" + + const val ACTION_VALUE_DEFAULT = "default" + const val ACTION_VALUE_RING = "ring" + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/RuleSet.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/RuleSet.kt new file mode 100644 index 0000000000..28f680b12b --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/RuleSet.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.matrix.android.api.pushrules.rest + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import im.vector.matrix.android.api.pushrules.RuleSetKey + +/** + * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules + */ +@JsonClass(generateAdapter = true) +data class RuleSet( + @Json(name = "content") + val content: List? = null, + @Json(name = "override") + val override: List? = null, + @Json(name = "room") + val room: List? = null, + @Json(name = "sender") + val sender: List? = null, + @Json(name = "underride") + val underride: List? = null +) { + fun getAllRules(): List { + // Ref. for the order: https://matrix.org/docs/spec/client_server/latest#push-rules + return override.orEmpty() + content.orEmpty() + room.orEmpty() + sender.orEmpty() + underride.orEmpty() + } + + /** + * Find a rule from its ruleID. + * + * @param ruleId a RULE_ID_XX value + * @return the matched bing rule or null it doesn't exist. + */ + fun findDefaultRule(ruleId: String?): PushRuleAndKind? { + var result: PushRuleAndKind? = null + // sanity check + if (null != ruleId) { + if (PushRule.RULE_ID_CONTAIN_USER_NAME == ruleId) { + result = findRule(content, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.CONTENT) } + } else { + // assume that the ruleId is unique. + result = findRule(override, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.OVERRIDE) } + if (null == result) { + result = findRule(underride, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.UNDERRIDE) } + } + } + } + return result + } + + /** + * Find a rule from its rule Id. + * + * @param rules the rules list. + * @param ruleId the rule Id. + * @return the bing rule if it exists, else null. + */ + private fun findRule(rules: List?, ruleId: String): PushRule? { + return rules?.firstOrNull { it.ruleId == ruleId } + } +} + +data class PushRuleAndKind( + val pushRule: PushRule, + val kind: RuleSetKey +) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt deleted file mode 100644 index a7093731b5..0000000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/pushrules/rest/Ruleset.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2019 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package im.vector.matrix.android.api.pushrules.rest - -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -internal data class Ruleset( - val content: List? = null, - val override: List? = null, - val room: List? = null, - val sender: List? = null, - val underride: List? = null -) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt index 7e8dc1eb30..f01b86fbdd 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/notification/DefaultPushRuleService.kt @@ -22,6 +22,7 @@ import im.vector.matrix.android.api.pushrules.RuleKind import im.vector.matrix.android.api.pushrules.RuleSetKey import im.vector.matrix.android.api.pushrules.getActions import im.vector.matrix.android.api.pushrules.rest.PushRule +import im.vector.matrix.android.api.pushrules.rest.RuleSet import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.internal.database.mapper.PushRulesMapper @@ -31,6 +32,7 @@ import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.pushers.AddPushRuleTask import im.vector.matrix.android.internal.session.pushers.GetPushRulesTask import im.vector.matrix.android.internal.session.pushers.RemovePushRuleTask +import im.vector.matrix.android.internal.session.pushers.UpdatePushRuleActionsTask import im.vector.matrix.android.internal.session.pushers.UpdatePushRuleEnableStatusTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith @@ -42,6 +44,7 @@ internal class DefaultPushRuleService @Inject constructor( private val getPushRulesTask: GetPushRulesTask, private val updatePushRuleEnableStatusTask: UpdatePushRuleEnableStatusTask, private val addPushRuleTask: AddPushRuleTask, + private val updatePushRuleActionsTask: UpdatePushRuleActionsTask, private val removePushRuleTask: RemovePushRuleTask, private val taskExecutor: TaskExecutor, private val monarchy: Monarchy @@ -55,7 +58,7 @@ internal class DefaultPushRuleService @Inject constructor( .executeBy(taskExecutor) } - override fun getPushRules(scope: String): List { + override fun getPushRules(scope: String): RuleSet { var contentRules: List = emptyList() var overrideRules: List = emptyList() var roomRules: List = emptyList() @@ -90,8 +93,13 @@ internal class DefaultPushRuleService @Inject constructor( } } - // Ref. for the order: https://matrix.org/docs/spec/client_server/latest#push-rules - return overrideRules + contentRules + roomRules + senderRules + underrideRules + return RuleSet( + content = contentRules, + override = overrideRules, + room = roomRules, + sender = senderRules, + underride = underrideRules + ) } override fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback): Cancelable { @@ -111,6 +119,14 @@ internal class DefaultPushRuleService @Inject constructor( .executeBy(taskExecutor) } + override fun updatePushRuleActions(kind: RuleKind, oldPushRule: PushRule, newPushRule: PushRule, callback: MatrixCallback): Cancelable { + return updatePushRuleActionsTask + .configureWith(UpdatePushRuleActionsTask.Params(kind, oldPushRule, newPushRule)) { + this.callback = callback + } + .executeBy(taskExecutor) + } + override fun removePushRule(kind: RuleKind, pushRule: PushRule, callback: MatrixCallback): Cancelable { return removePushRuleTask .configureWith(RemovePushRuleTask.Params(kind, pushRule)) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushRulesApi.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushRulesApi.kt index db7d2a15ed..6dc7c1cd5a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushRulesApi.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushRulesApi.kt @@ -47,6 +47,7 @@ internal interface PushRulesApi { /** * Update the ruleID action + * Ref: https://matrix.org/docs/spec/client_server/latest#put-matrix-client-r0-pushrules-scope-kind-ruleid-actions * * @param kind the notification kind (sender, room...) * @param ruleId the ruleId diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt index 35ee90bf42..e80fca09e7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/PushersModule.kt @@ -72,6 +72,9 @@ internal abstract class PushersModule { @Binds abstract fun bindAddPushRuleTask(task: DefaultAddPushRuleTask): AddPushRuleTask + @Binds + abstract fun bindUpdatePushRuleActionTask(task: DefaultUpdatePushRuleActionsTask): UpdatePushRuleActionsTask + @Binds abstract fun bindRemovePushRuleTask(task: DefaultRemovePushRuleTask): RemovePushRuleTask diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleActionsTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleActionsTask.kt new file mode 100644 index 0000000000..d8025be14d --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/pushers/UpdatePushRuleActionsTask.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.matrix.android.internal.session.pushers + +import im.vector.matrix.android.api.pushrules.RuleKind +import im.vector.matrix.android.api.pushrules.rest.PushRule +import im.vector.matrix.android.internal.network.executeRequest +import im.vector.matrix.android.internal.task.Task +import org.greenrobot.eventbus.EventBus +import javax.inject.Inject + +internal interface UpdatePushRuleActionsTask : Task { + data class Params( + val kind: RuleKind, + val oldPushRule: PushRule, + val newPushRule: PushRule + ) +} + +internal class DefaultUpdatePushRuleActionsTask @Inject constructor( + private val pushRulesApi: PushRulesApi, + private val eventBus: EventBus +) : UpdatePushRuleActionsTask { + + override suspend fun execute(params: UpdatePushRuleActionsTask.Params) { + if (params.oldPushRule.enabled != params.newPushRule.enabled) { + // First change enabled state + executeRequest(eventBus) { + apiCall = pushRulesApi.updateEnableRuleStatus(params.kind.value, params.newPushRule.ruleId, params.newPushRule.enabled) + } + } + + if (params.newPushRule.enabled) { + // Also ensure the actions are up to date + val body = mapOf("actions" to params.newPushRule.actions) + + executeRequest(eventBus) { + apiCall = pushRulesApi.updateRuleActions(params.kind.value, params.newPushRule.ruleId, body) + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt index 1454fdae7d..4ae42b273d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt @@ -120,7 +120,7 @@ internal class SyncResponseHandler @Inject constructor(private val monarchy: Mon return } // nothing on initial sync - val rules = pushRuleService.getPushRules(RuleScope.GLOBAL) + val rules = pushRuleService.getPushRules(RuleScope.GLOBAL).getAllRules() processEventForPushTask.execute(ProcessEventForPushTask.Params(roomsSyncResponse, rules)) Timber.v("[PushRules] <-- Push task scheduled") } diff --git a/vector/src/fdroid/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/fdroid/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt index 723a0b9327..b88a379450 100644 --- a/vector/src/fdroid/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/fdroid/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -20,7 +20,7 @@ import im.vector.riotx.fdroid.features.settings.troubleshoot.TestAutoStartBoot import im.vector.riotx.fdroid.features.settings.troubleshoot.TestBackgroundRestrictions import im.vector.riotx.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.riotx.features.settings.troubleshoot.TestAccountSettings -import im.vector.riotx.features.settings.troubleshoot.TestBingRulesSettings +import im.vector.riotx.features.settings.troubleshoot.TestPushRulesSettings import im.vector.riotx.features.settings.troubleshoot.TestDeviceSettings import im.vector.riotx.features.settings.troubleshoot.TestSystemSettings import javax.inject.Inject @@ -28,7 +28,7 @@ import javax.inject.Inject class NotificationTroubleshootTestManagerFactory @Inject constructor(private val testSystemSettings: TestSystemSettings, private val testAccountSettings: TestAccountSettings, private val testDeviceSettings: TestDeviceSettings, - private val testBingRulesSettings: TestBingRulesSettings, + private val testPushRulesSettings: TestPushRulesSettings, private val testAutoStartBoot: TestAutoStartBoot, private val testBackgroundRestrictions: TestBackgroundRestrictions) { @@ -37,7 +37,7 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(private val mgr.addTest(testSystemSettings) mgr.addTest(testAccountSettings) mgr.addTest(testDeviceSettings) - mgr.addTest(testBingRulesSettings) + mgr.addTest(testPushRulesSettings) mgr.addTest(testAutoStartBoot) mgr.addTest(testBackgroundRestrictions) return mgr diff --git a/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt index 7feb89879e..9fadbcafb6 100755 --- a/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/riotx/gplay/push/fcm/VectorFirebaseMessagingService.kt @@ -25,13 +25,13 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.ProcessLifecycleOwner import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage +import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.events.model.Event import im.vector.riotx.BuildConfig import im.vector.riotx.R import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.extensions.vectorComponent -import im.vector.riotx.core.preference.BingRule import im.vector.riotx.core.pushers.PushersManager import im.vector.riotx.features.badge.BadgeProxy import im.vector.riotx.features.notifications.NotifiableEventResolver @@ -196,7 +196,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { description = "", type = null, timestamp = System.currentTimeMillis(), - soundName = BingRule.ACTION_VALUE_DEFAULT, + soundName = PushRule.ACTION_VALUE_DEFAULT, isPushGatewayEvent = true ) notificationDrawerManager.onNotifiableEventReceived(simpleNotifiableEvent) diff --git a/vector/src/gplay/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/gplay/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt index 6f980197dd..2830822918 100644 --- a/vector/src/gplay/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/gplay/java/im/vector/riotx/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -18,8 +18,8 @@ package im.vector.riotx.push.fcm import androidx.fragment.app.Fragment import im.vector.riotx.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.riotx.features.settings.troubleshoot.TestAccountSettings -import im.vector.riotx.features.settings.troubleshoot.TestBingRulesSettings import im.vector.riotx.features.settings.troubleshoot.TestDeviceSettings +import im.vector.riotx.features.settings.troubleshoot.TestPushRulesSettings import im.vector.riotx.features.settings.troubleshoot.TestSystemSettings import im.vector.riotx.gplay.features.settings.troubleshoot.TestFirebaseToken import im.vector.riotx.gplay.features.settings.troubleshoot.TestPlayServices @@ -29,7 +29,7 @@ import javax.inject.Inject class NotificationTroubleshootTestManagerFactory @Inject constructor(private val testSystemSettings: TestSystemSettings, private val testAccountSettings: TestAccountSettings, private val testDeviceSettings: TestDeviceSettings, - private val testBingRulesSettings: TestBingRulesSettings, + private val testBingRulesSettings: TestPushRulesSettings, private val testPlayServices: TestPlayServices, private val testFirebaseToken: TestFirebaseToken, private val testTokenRegistration: TestTokenRegistration) { diff --git a/vector/src/main/java/im/vector/riotx/core/preference/BingRulePreference.kt b/vector/src/main/java/im/vector/riotx/core/preference/PushRulePreference.kt similarity index 52% rename from vector/src/main/java/im/vector/riotx/core/preference/BingRulePreference.kt rename to vector/src/main/java/im/vector/riotx/core/preference/PushRulePreference.kt index 76df61dd33..16dd1bb486 100755 --- a/vector/src/main/java/im/vector/riotx/core/preference/BingRulePreference.kt +++ b/vector/src/main/java/im/vector/riotx/core/preference/PushRulePreference.kt @@ -22,49 +22,17 @@ import android.view.View import android.widget.RadioGroup import android.widget.TextView import androidx.preference.PreferenceViewHolder +import im.vector.matrix.android.api.pushrules.RuleSetKey +import im.vector.matrix.android.api.pushrules.rest.PushRule +import im.vector.matrix.android.api.pushrules.rest.PushRuleAndKind import im.vector.riotx.R -// TODO Replace by real Bingrule class, then delete -@Suppress("UNUSED_PARAMETER") -class BingRule(rule: BingRule) { - fun shouldNotNotify() = false - fun shouldNotify() = false - fun setNotify(b: Boolean) { - } - - fun setHighlight(b: Boolean) { - } - - fun removeNotificationSound() { - } - - val ruleId: CharSequence? = null - var isEnabled = false - var notificationSound: String? = null - val kind: CharSequence? = null - - companion object { - const val RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS = "TODO" - const val ACTION_VALUE_DEFAULT = "TODO" - const val KIND_UNDERRIDE = "TODO" - const val RULE_ID_INVITE_ME = "TODO" - const val RULE_ID_CALL = "TODO" - const val ACTION_VALUE_RING = "TODO" - const val RULE_ID_DISABLE_ALL = "TODO" - const val ACTION_DONT_NOTIFY = "TODO" - const val RULE_ID_CONTAIN_DISPLAY_NAME = "TODO" - const val RULE_ID_CONTAIN_USER_NAME = "TODO" - const val RULE_ID_ONE_TO_ONE_ROOM = "TODO" - const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = "TODO" - } -} - -class BingRulePreference : VectorPreference { +class PushRulePreference : VectorPreference { /** - * @return the selected bing rule + * @return the selected push rule and its kind */ - var rule: BingRule? = null + var ruleAndKind: PushRuleAndKind? = null private set constructor(context: Context) : super(context) @@ -74,35 +42,35 @@ class BingRulePreference : VectorPreference { constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) init { - layoutResource = R.layout.vector_preference_bing_rule + layoutResource = R.layout.vector_preference_push_rule } /** * @return the bing rule status index */ - val ruleStatusIndex: Int + private val ruleStatusIndex: Int get() { - if (null != rule) { - if (rule!!.ruleId == BingRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) { - if (rule!!.shouldNotNotify()) { - return if (rule!!.isEnabled) { - NOTIFICATION_OFF_INDEX - } else { - NOTIFICATION_SILENT_INDEX - } - } else if (rule!!.shouldNotify()) { - return NOTIFICATION_NOISY_INDEX - } - } + val safeRule = ruleAndKind?.pushRule ?: return NOTIFICATION_OFF_INDEX - if (rule!!.isEnabled) { - return if (rule!!.shouldNotNotify()) { + if (safeRule.ruleId == PushRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) { + if (safeRule.shouldNotNotify()) { + return if (safeRule.enabled) { NOTIFICATION_OFF_INDEX - } else if (null != rule!!.notificationSound) { - NOTIFICATION_NOISY_INDEX } else { NOTIFICATION_SILENT_INDEX } + } else if (safeRule.shouldNotify()) { + return NOTIFICATION_NOISY_INDEX + } + } + + if (safeRule.enabled) { + return if (safeRule.shouldNotNotify()) { + NOTIFICATION_OFF_INDEX + } else if (safeRule.getNotificationSound() != null) { + NOTIFICATION_NOISY_INDEX + } else { + NOTIFICATION_SILENT_INDEX } } @@ -110,12 +78,12 @@ class BingRulePreference : VectorPreference { } /** - * Update the bing rule. + * Update the push rule. * - * @param aBingRule + * @param pushRule */ - fun setBingRule(aBingRule: BingRule) { - rule = aBingRule + fun setPushRule(pushRuleAndKind: PushRuleAndKind?) { + ruleAndKind = pushRuleAndKind refreshSummary() } @@ -131,63 +99,64 @@ class BingRulePreference : VectorPreference { } /** - * Create a bing rule with the updated required at index. + * Create a push rule with the updated required at index. * * @param index index - * @return a bing rule with the updated flags / null if there is no update + * @return a push rule with the updated flags / null if there is no update */ - fun createRule(index: Int): BingRule? { - var rule: BingRule? = null + fun createNewRule(index: Int): PushRule? { + val safeRule = ruleAndKind?.pushRule ?: return null + val safeKind = ruleAndKind?.kind ?: return null - if (null != this.rule && index != ruleStatusIndex) { - rule = BingRule(this.rule!!) - - if (rule.ruleId == BingRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) { + return if (index != ruleStatusIndex) { + if (safeRule.ruleId == PushRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) { when (index) { NOTIFICATION_OFF_INDEX -> { - rule.isEnabled = true - rule.setNotify(false) + safeRule.copy(enabled = true) + .setNotify(false) + .removeNotificationSound() } NOTIFICATION_SILENT_INDEX -> { - rule.isEnabled = false - rule.setNotify(false) + safeRule.copy(enabled = false) + .setNotify(false) } NOTIFICATION_NOISY_INDEX -> { - rule.isEnabled = true - rule.setNotify(true) - rule.notificationSound = BingRule.ACTION_VALUE_DEFAULT + safeRule.copy(enabled = true) + .setNotify(true) + .setNotificationSound() } - } - - return rule - } - - if (NOTIFICATION_OFF_INDEX == index) { - if (this.rule!!.kind == BingRule.KIND_UNDERRIDE - || rule.ruleId == BingRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) { - rule.setNotify(false) - } else { - rule.isEnabled = false + else -> safeRule } } else { - rule.isEnabled = true - rule.setNotify(true) - rule.setHighlight(this.rule!!.kind != BingRule.KIND_UNDERRIDE - && rule.ruleId != BingRule.RULE_ID_INVITE_ME - && NOTIFICATION_NOISY_INDEX == index) - if (NOTIFICATION_NOISY_INDEX == index) { - rule.notificationSound = if (rule.ruleId == BingRule.RULE_ID_CALL) { - BingRule.ACTION_VALUE_RING + if (NOTIFICATION_OFF_INDEX == index) { + if (safeKind == RuleSetKey.UNDERRIDE || safeRule.ruleId == PushRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS) { + safeRule.setNotify(false) } else { - BingRule.ACTION_VALUE_DEFAULT + safeRule.copy(enabled = false) } } else { - rule.removeNotificationSound() + val newRule = safeRule.copy(enabled = true) + .setNotify(true) + .setHighlight(safeKind != RuleSetKey.UNDERRIDE + && safeRule.ruleId != PushRule.RULE_ID_INVITE_ME + && NOTIFICATION_NOISY_INDEX == index) + + if (NOTIFICATION_NOISY_INDEX == index) { + newRule.setNotificationSound( + if (safeRule.ruleId == PushRule.RULE_ID_CALL) { + PushRule.ACTION_VALUE_RING + } else { + PushRule.ACTION_VALUE_DEFAULT + } + ) + } else { + newRule.removeNotificationSound() + } } } + } else { + safeRule } - - return rule } override fun onBindViewHolder(holder: PreferenceViewHolder) { diff --git a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt index ff0947598f..50fb5b70de 100755 --- a/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/riotx/features/notifications/NotificationUtils.kt @@ -423,9 +423,9 @@ class NotificationUtils @Inject constructor(private val context: Context, // 'importance' which is set in the NotificationChannel. The integers representing // 'priority' are different from 'importance', so make sure you don't mix them. .apply { - priority = NotificationCompat.PRIORITY_DEFAULT if (roomInfo.shouldBing) { // Compat + priority = NotificationCompat.PRIORITY_DEFAULT vectorPreferences.getNotificationRingTone()?.let { setSound(it) } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt index 28f78743e4..68f92ff15e 100755 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt @@ -35,7 +35,6 @@ import javax.inject.Inject class VectorPreferences @Inject constructor(private val context: Context) { companion object { - const val SETTINGS_MESSAGES_SENT_BY_BOT_PREFERENCE_KEY = "SETTINGS_MESSAGES_SENT_BY_BOT_PREFERENCE_KEY_2" const val SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY = "SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY" const val SETTINGS_VERSION_PREFERENCE_KEY = "SETTINGS_VERSION_PREFERENCE_KEY" const val SETTINGS_SDK_VERSION_PREFERENCE_KEY = "SETTINGS_SDK_VERSION_PREFERENCE_KEY" @@ -46,7 +45,6 @@ class VectorPreferences @Inject constructor(private val context: Context) { const val SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY = "SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY" const val SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY = "SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY" - const val SETTINGS_NOTIFICATION_TROUBLESHOOT_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_TROUBLESHOOT_PREFERENCE_KEY" const val SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY" const val SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY" const val SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY" @@ -106,7 +104,6 @@ class VectorPreferences @Inject constructor(private val context: Context) { const val SETTINGS_GROUPS_FLAIR_KEY = "SETTINGS_GROUPS_FLAIR_KEY" // notifications - const val SETTINGS_NOTIFICATIONS_KEY = "SETTINGS_NOTIFICATIONS_KEY" const val SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY = "SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY" const val SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY = "SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY" // public static final String SETTINGS_TURN_SCREEN_ON_PREFERENCE_KEY = "SETTINGS_TURN_SCREEN_ON_PREFERENCE_KEY"; @@ -115,12 +112,6 @@ class VectorPreferences @Inject constructor(private val context: Context) { const val SETTINGS_SYSTEM_SILENT_NOTIFICATION_PREFERENCE_KEY = "SETTINGS_SYSTEM_SILENT_NOTIFICATION_PREFERENCE_KEY" const val SETTINGS_NOTIFICATION_RINGTONE_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_RINGTONE_PREFERENCE_KEY" const val SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY" - const val SETTINGS_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY = "SETTINGS_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY_2" - const val SETTINGS_CONTAINING_MY_USER_NAME_PREFERENCE_KEY = "SETTINGS_CONTAINING_MY_USER_NAME_PREFERENCE_KEY_2" - const val SETTINGS_MESSAGES_IN_ONE_TO_ONE_PREFERENCE_KEY = "SETTINGS_MESSAGES_IN_ONE_TO_ONE_PREFERENCE_KEY_2" - const val SETTINGS_MESSAGES_IN_GROUP_CHAT_PREFERENCE_KEY = "SETTINGS_MESSAGES_IN_GROUP_CHAT_PREFERENCE_KEY_2" - const val SETTINGS_INVITED_TO_ROOM_PREFERENCE_KEY = "SETTINGS_INVITED_TO_ROOM_PREFERENCE_KEY_2" - const val SETTINGS_CALL_INVITATIONS_PREFERENCE_KEY = "SETTINGS_CALL_INVITATIONS_PREFERENCE_KEY_2" // media private const val SETTINGS_DEFAULT_MEDIA_COMPRESSION_KEY = "SETTINGS_DEFAULT_MEDIA_COMPRESSION_KEY" diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt index 490805ea3c..909d40a74c 100755 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt @@ -77,21 +77,14 @@ class VectorSettingsActivity : VectorBaseActivity(), } override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean { - val oFragment = when { - VectorPreferences.SETTINGS_NOTIFICATION_TROUBLESHOOT_PREFERENCE_KEY == pref.key -> - supportFragmentManager.fragmentFactory.instantiate(classLoader, VectorSettingsNotificationsTroubleshootFragment::class.java.name) - VectorPreferences.SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY == pref.key -> - supportFragmentManager.fragmentFactory.instantiate(classLoader, VectorSettingsAdvancedNotificationPreferenceFragment::class.java.name) - else -> - try { - pref.fragment?.let { - supportFragmentManager.fragmentFactory.instantiate(classLoader, it) - } - } catch (e: Throwable) { - showSnackbar(getString(R.string.not_implemented)) - Timber.e(e) - null - } + val oFragment = try { + pref.fragment?.let { + supportFragmentManager.fragmentFactory.instantiate(classLoader, it) + } + } catch (e: Throwable) { + showSnackbar(getString(R.string.not_implemented)) + Timber.e(e) + null } if (oFragment != null) { diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsAdvancedNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsAdvancedNotificationPreferenceFragment.kt index a8328fae52..95901de471 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsAdvancedNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsAdvancedNotificationPreferenceFragment.kt @@ -15,125 +15,64 @@ */ package im.vector.riotx.features.settings -import android.app.Activity -import android.content.Intent -import android.media.RingtoneManager -import android.net.Uri -import android.os.Parcelable -import androidx.core.content.edit import androidx.preference.Preference -import androidx.preference.PreferenceManager +import im.vector.matrix.android.api.MatrixCallback +import im.vector.matrix.android.api.pushrules.rest.PushRule +import im.vector.matrix.android.api.pushrules.rest.PushRuleAndKind import im.vector.riotx.R -import im.vector.riotx.core.preference.BingRule -import im.vector.riotx.core.preference.BingRulePreference +import im.vector.riotx.core.preference.PushRulePreference import im.vector.riotx.core.preference.VectorPreference -import im.vector.riotx.features.notifications.NotificationUtils +import im.vector.riotx.core.utils.toast import javax.inject.Inject -class VectorSettingsAdvancedNotificationPreferenceFragment @Inject constructor( - private val vectorPreferences: VectorPreferences -) : VectorSettingsBaseFragment() { - - // events listener - /* TODO - private val mEventsListener = object : MXEventListener() { - override fun onBingRulesUpdate() { - refreshPreferences() - refreshDisplay() - } - } */ +class VectorSettingsAdvancedNotificationPreferenceFragment @Inject constructor() + : VectorSettingsBaseFragment() { override var titleRes: Int = R.string.settings_notification_advanced override val preferenceXmlRes = R.xml.vector_settings_notification_advanced_preferences override fun bindPref() { - val callNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_CALL_NOTIFICATION_PREFERENCE_KEY)!! - if (NotificationUtils.supportNotificationChannels()) { - callNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener { - NotificationUtils.openSystemSettingsForCallCategory(this) - false - } - } else { - callNotificationsSystemOptions.isVisible = false - } - - val noisyNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_NOISY_NOTIFICATION_PREFERENCE_KEY)!! - if (NotificationUtils.supportNotificationChannels()) { - noisyNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener { - NotificationUtils.openSystemSettingsForNoisyCategory(this) - false - } - } else { - noisyNotificationsSystemOptions.isVisible = false - } - - val silentNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_SILENT_NOTIFICATION_PREFERENCE_KEY)!! - if (NotificationUtils.supportNotificationChannels()) { - silentNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener { - NotificationUtils.openSystemSettingsForSilentCategory(this) - false - } - } else { - silentNotificationsSystemOptions.isVisible = false - } - - // Ringtone - val ringtonePreference = findPreference(VectorPreferences.SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY)!! - - if (NotificationUtils.supportNotificationChannels()) { - ringtonePreference.isVisible = false - } else { - ringtonePreference.summary = vectorPreferences.getNotificationRingToneName() - ringtonePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener { - val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER) - intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION) - - if (null != vectorPreferences.getNotificationRingTone()) { - intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, vectorPreferences.getNotificationRingTone()) - } - - startActivityForResult(intent, REQUEST_NOTIFICATION_RINGTONE) - false - } - } - - for (preferenceKey in mPrefKeyToBingRuleId.keys) { + for (preferenceKey in prefKeyToPushRuleId.keys) { val preference = findPreference(preferenceKey) - if (preference is BingRulePreference) { + if (preference is PushRulePreference) { // preference.isEnabled = null != rules && isConnected && pushManager.areDeviceNotificationsAllowed() - val rule: BingRule? = null // TODO session.dataHandler.pushRules()?.findDefaultRule(mPrefKeyToBingRuleId[preferenceKey]) + val ruleAndKind: PushRuleAndKind? = session.getPushRules().findDefaultRule(prefKeyToPushRuleId[preferenceKey]) - if (rule == null) { + if (ruleAndKind == null) { // The rule is not defined, hide the preference preference.isVisible = false } else { preference.isVisible = true - preference.setBingRule(rule) + preference.setPushRule(ruleAndKind) preference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - val rule2 = preference.createRule(newValue as Int) - if (null != rule2) { - /* - TODO - displayLoadingView() - session.dataHandler.bingRulesManager.updateRule(preference.rule, - rule, - object : BingRulesManager.onBingRuleUpdateListener { - private fun onDone() { - refreshDisplay() + val newRule = preference.createNewRule(newValue as Int) + if (newRule != null) { + displayLoadingView() + + session.updatePushRuleActions( + ruleAndKind.kind, + preference.ruleAndKind?.pushRule ?: ruleAndKind.pushRule, + newRule, + object : MatrixCallback { + override fun onSuccess(data: Unit) { + if (!isAdded) { + return + } + preference.setPushRule(ruleAndKind.copy(pushRule = newRule)) hideLoadingView() } - override fun onBingRuleUpdateSuccess() { - onDone() - } - - override fun onBingRuleUpdateFailure(errorMessage: String) { - activity?.toast(errorMessage) - onDone() + override fun onFailure(failure: Throwable) { + if (!isAdded) { + return + } + hideLoadingView() + // Restore the previous value + refreshDisplay() + activity?.toast(errorFormatter.toHumanReadable(failure)) } }) - */ } false } @@ -146,83 +85,24 @@ class VectorSettingsAdvancedNotificationPreferenceFragment @Inject constructor( listView?.adapter?.notifyDataSetChanged() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (resultCode == Activity.RESULT_OK) { - when (requestCode) { - REQUEST_NOTIFICATION_RINGTONE -> { - vectorPreferences.setNotificationRingTone(data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) as Uri?) - - // test if the selected ring tone can be played - val notificationRingToneName = vectorPreferences.getNotificationRingToneName() - if (null != notificationRingToneName) { - vectorPreferences.setNotificationRingTone(vectorPreferences.getNotificationRingTone()) - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY)!! - .summary = notificationRingToneName - } - } - } - } - } - - /** - * Refresh the known information about the account - */ - private fun refreshPreferences() { - PreferenceManager.getDefaultSharedPreferences(activity).edit { - /* TODO - session.dataHandler.pushRules()?.let { - for (prefKey in mPrefKeyToBingRuleId.keys) { - val preference = findPreference(prefKey) - - if (null != preference && preference is SwitchPreference) { - val ruleId = mPrefKeyToBingRuleId[prefKey] - - val rule = it.findDefaultRule(ruleId) - var isEnabled = null != rule && rule.isEnabled - - if (TextUtils.equals(ruleId, BingRule.RULE_ID_DISABLE_ALL) || TextUtils.equals(ruleId, BingRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS)) { - isEnabled = !isEnabled - } else if (isEnabled) { - val domainActions = rule!!.domainActions - - // no action -> noting will be done - if (null == domainActions || domainActions.isEmpty()) { - isEnabled = false - } else if (1 == domainActions.size) { - try { - isEnabled = !TextUtils.equals(domainActions[0] as String, BingRule.ACTION_DONT_NOTIFY) - } catch (e: Exception) { - Timber.e(e, "## refreshPreferences failed") - } - - } - }// check if the rule is only defined by don't notify - - putBoolean(prefKey, isEnabled) - } - } - } - */ - } - } - /* ========================================================================================== * Companion * ========================================================================================== */ companion object { - private const val REQUEST_NOTIFICATION_RINGTONE = 888 - // preference name <-> rule Id - private var mPrefKeyToBingRuleId = mapOf( - VectorPreferences.SETTINGS_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY to BingRule.RULE_ID_CONTAIN_DISPLAY_NAME, - VectorPreferences.SETTINGS_CONTAINING_MY_USER_NAME_PREFERENCE_KEY to BingRule.RULE_ID_CONTAIN_USER_NAME, - VectorPreferences.SETTINGS_MESSAGES_IN_ONE_TO_ONE_PREFERENCE_KEY to BingRule.RULE_ID_ONE_TO_ONE_ROOM, - VectorPreferences.SETTINGS_MESSAGES_IN_GROUP_CHAT_PREFERENCE_KEY to BingRule.RULE_ID_ALL_OTHER_MESSAGES_ROOMS, - VectorPreferences.SETTINGS_INVITED_TO_ROOM_PREFERENCE_KEY to BingRule.RULE_ID_INVITE_ME, - VectorPreferences.SETTINGS_CALL_INVITATIONS_PREFERENCE_KEY to BingRule.RULE_ID_CALL, - VectorPreferences.SETTINGS_MESSAGES_SENT_BY_BOT_PREFERENCE_KEY to BingRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS + private val prefKeyToPushRuleId = mapOf( + "SETTINGS_PUSH_RULE_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY" to PushRule.RULE_ID_CONTAIN_DISPLAY_NAME, + "SETTINGS_PUSH_RULE_CONTAINING_MY_USER_NAME_PREFERENCE_KEY" to PushRule.RULE_ID_CONTAIN_USER_NAME, + "SETTINGS_PUSH_RULE_MESSAGES_IN_ONE_TO_ONE_PREFERENCE_KEY" to PushRule.RULE_ID_ONE_TO_ONE_ROOM, + "SETTINGS_PUSH_RULE_MESSAGES_IN_GROUP_CHAT_PREFERENCE_KEY" to PushRule.RULE_ID_ALL_OTHER_MESSAGES_ROOMS, + "SETTINGS_PUSH_RULE_INVITED_TO_ROOM_PREFERENCE_KEY" to PushRule.RULE_ID_INVITE_ME, + "SETTINGS_PUSH_RULE_CALL_INVITATIONS_PREFERENCE_KEY" to PushRule.RULE_ID_CALL, + "SETTINGS_PUSH_RULE_MESSAGES_SENT_BY_BOT_PREFERENCE_KEY" to PushRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS, + "SETTINGS_PUSH_RULE_MESSAGES_CONTAINING_AT_ROOM_PREFERENCE_KEY" to PushRule.RULE_ID_AT_ROOMS, + "SETTINGS_PUSH_RULE_MESSAGES_IN_E2E_ONE_ONE_CHAT_PREFERENCE_KEY" to PushRule.RULE_ID_E2E_ONE_TO_ONE_ROOM, + "SETTINGS_PUSH_RULE_MESSAGES_IN_E2E_GROUP_CHAT_PREFERENCE_KEY" to PushRule.RULE_ID_E2E_GROUP, + "SETTINGS_PUSH_RULE_ROOMS_UPGRADED_KEY" to PushRule.RULE_ID_TOMBSTONE ) } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsBaseFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsBaseFragment.kt index e32cc98123..85d32251b6 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsBaseFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsBaseFragment.kt @@ -26,6 +26,7 @@ import im.vector.riotx.R import im.vector.riotx.core.di.DaggerScreenComponent import im.vector.riotx.core.di.HasScreenInjector import im.vector.riotx.core.di.ScreenComponent +import im.vector.riotx.core.error.ErrorFormatter import im.vector.riotx.core.platform.VectorBaseActivity import im.vector.riotx.core.utils.toast import timber.log.Timber @@ -40,6 +41,7 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), HasScree // members protected lateinit var session: Session + protected lateinit var errorFormatter: ErrorFormatter private lateinit var screenComponent: ScreenComponent abstract val preferenceXmlRes: Int @@ -54,6 +56,7 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), HasScree screenComponent = DaggerScreenComponent.factory().create(vectorActivity.getVectorComponent(), vectorActivity) super.onAttach(context) session = screenComponent.activeSessionHolder().getActiveSession() + errorFormatter = screenComponent.errorFormatter() injectWith(injector()) } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationPreferenceFragment.kt index 5e7bc9d95b..a1e67e6cd0 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationPreferenceFragment.kt @@ -16,6 +16,11 @@ package im.vector.riotx.features.settings +import android.app.Activity +import android.content.Intent +import android.media.RingtoneManager +import android.net.Uri +import android.os.Parcelable import android.widget.Toast import androidx.preference.Preference import androidx.preference.SwitchPreference @@ -24,8 +29,10 @@ import im.vector.matrix.android.api.pushrules.RuleIds import im.vector.matrix.android.api.pushrules.RuleKind import im.vector.riotx.R import im.vector.riotx.core.di.ActiveSessionHolder +import im.vector.riotx.core.preference.VectorPreference import im.vector.riotx.core.preference.VectorSwitchPreference import im.vector.riotx.core.pushers.PushersManager +import im.vector.riotx.features.notifications.NotificationUtils import im.vector.riotx.push.fcm.FcmHelper import javax.inject.Inject @@ -42,7 +49,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( override fun bindPref() { findPreference(VectorPreferences.SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY)!!.let { pref -> val pushRuleService = session - val mRuleMaster = pushRuleService.getPushRules() + val mRuleMaster = pushRuleService.getPushRules().getAllRules() .find { it.ruleId == RuleIds.RULE_ID_DISABLE_ALL } if (mRuleMaster == null) { @@ -54,6 +61,79 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( val areNotifEnabledAtAccountLevel = !mRuleMaster.enabled (pref as SwitchPreference).isChecked = areNotifEnabledAtAccountLevel } + + handleSystemPreference() + } + + private fun handleSystemPreference() { + val callNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_CALL_NOTIFICATION_PREFERENCE_KEY)!! + if (NotificationUtils.supportNotificationChannels()) { + callNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener { + NotificationUtils.openSystemSettingsForCallCategory(this) + false + } + } else { + callNotificationsSystemOptions.isVisible = false + } + + val noisyNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_NOISY_NOTIFICATION_PREFERENCE_KEY)!! + if (NotificationUtils.supportNotificationChannels()) { + noisyNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener { + NotificationUtils.openSystemSettingsForNoisyCategory(this) + false + } + } else { + noisyNotificationsSystemOptions.isVisible = false + } + + val silentNotificationsSystemOptions = findPreference(VectorPreferences.SETTINGS_SYSTEM_SILENT_NOTIFICATION_PREFERENCE_KEY)!! + if (NotificationUtils.supportNotificationChannels()) { + silentNotificationsSystemOptions.onPreferenceClickListener = Preference.OnPreferenceClickListener { + NotificationUtils.openSystemSettingsForSilentCategory(this) + false + } + } else { + silentNotificationsSystemOptions.isVisible = false + } + + // Ringtone + val ringtonePreference = findPreference(VectorPreferences.SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY)!! + + if (NotificationUtils.supportNotificationChannels()) { + ringtonePreference.isVisible = false + } else { + ringtonePreference.summary = vectorPreferences.getNotificationRingToneName() + ringtonePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener { + val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER) + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_NOTIFICATION) + + if (null != vectorPreferences.getNotificationRingTone()) { + intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, vectorPreferences.getNotificationRingTone()) + } + + startActivityForResult(intent, REQUEST_NOTIFICATION_RINGTONE) + false + } + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + if (resultCode == Activity.RESULT_OK) { + when (requestCode) { + REQUEST_NOTIFICATION_RINGTONE -> { + vectorPreferences.setNotificationRingTone(data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) as Uri?) + + // test if the selected ring tone can be played + val notificationRingToneName = vectorPreferences.getNotificationRingToneName() + if (null != notificationRingToneName) { + vectorPreferences.setNotificationRingTone(vectorPreferences.getNotificationRingTone()) + findPreference(VectorPreferences.SETTINGS_NOTIFICATION_RINGTONE_SELECTION_PREFERENCE_KEY)!! + .summary = notificationRingToneName + } + } + } + } } override fun onResume() { @@ -105,7 +185,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( private fun updateEnabledForAccount(preference: Preference?) { val pushRuleService = session val switchPref = preference as SwitchPreference - pushRuleService.getPushRules() + pushRuleService.getPushRules().getAllRules() .find { it.ruleId == RuleIds.RULE_ID_DISABLE_ALL } ?.let { // Trick, we must enable this room to disable notifications @@ -114,7 +194,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( !switchPref.isChecked, object : MatrixCallback { override fun onSuccess(data: Unit) { - // Push rules will be updated form the sync + // Push rules will be updated from the sync } override fun onFailure(failure: Throwable) { @@ -129,4 +209,8 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( }) } } + + companion object { + private const val REQUEST_NOTIFICATION_RINGTONE = 888 + } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/push/PushRulesViewModel.kt b/vector/src/main/java/im/vector/riotx/features/settings/push/PushRulesViewModel.kt index 3c71238b33..43854af666 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/push/PushRulesViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/push/PushRulesViewModel.kt @@ -35,7 +35,7 @@ class PushRulesViewModel(initialState: PushRulesViewState) override fun initialState(viewModelContext: ViewModelContext): PushRulesViewState? { val session = (viewModelContext.activity as HasScreenInjector).injector().activeSessionHolder().getActiveSession() - val rules = session.getPushRules() + val rules = session.getPushRules().getAllRules() return PushRulesViewState(rules) } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestAccountSettings.kt b/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestAccountSettings.kt index feea3e40d0..d89bd15e14 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestAccountSettings.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestAccountSettings.kt @@ -32,7 +32,7 @@ class TestAccountSettings @Inject constructor(private val stringProvider: String override fun perform() { val session = activeSessionHolder.getSafeActiveSession() ?: return - val defaultRule = session.getPushRules() + val defaultRule = session.getPushRules().getAllRules() .find { it.ruleId == RuleIds.RULE_ID_DISABLE_ALL } if (defaultRule != null) { diff --git a/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestBingRulesSettings.kt b/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestPushRulesSettings.kt similarity index 96% rename from vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestBingRulesSettings.kt rename to vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestPushRulesSettings.kt index 4847587d56..bbdf8fa62c 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestBingRulesSettings.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/troubleshoot/TestPushRulesSettings.kt @@ -23,7 +23,7 @@ import im.vector.riotx.core.resources.StringProvider import im.vector.riotx.features.notifications.toNotificationAction import javax.inject.Inject -class TestBingRulesSettings @Inject constructor(private val activeSessionHolder: ActiveSessionHolder, +class TestPushRulesSettings @Inject constructor(private val activeSessionHolder: ActiveSessionHolder, private val stringProvider: StringProvider) : TroubleshootTest(R.string.settings_troubleshoot_test_bing_settings_title) { @@ -40,7 +40,7 @@ class TestBingRulesSettings @Inject constructor(private val activeSessionHolder: override fun perform() { val session = activeSessionHolder.getSafeActiveSession() ?: return - val pushRules = session.getPushRules() + val pushRules = session.getPushRules().getAllRules() var oneOrMoreRuleIsOff = false var oneOrMoreRuleAreSilent = false testedRules.forEach { ruleId -> diff --git a/vector/src/main/res/layout/vector_preference_bing_rule.xml b/vector/src/main/res/layout/vector_preference_push_rule.xml similarity index 100% rename from vector/src/main/res/layout/vector_preference_bing_rule.xml rename to vector/src/main/res/layout/vector_preference_push_rule.xml diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index 579fdae874..e842550dd1 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -11,6 +11,13 @@ + Notifications configuration + Messages containing @room + Encrypted messages in one-to-one chats + Encrypted messages in group chats + When rooms are upgraded + Troubleshoot + Set notification importance by event diff --git a/vector/src/main/res/xml/vector_settings_notification_advanced_preferences.xml b/vector/src/main/res/xml/vector_settings_notification_advanced_preferences.xml index b5f01d98f6..6e0fb71671 100644 --- a/vector/src/main/res/xml/vector_settings_notification_advanced_preferences.xml +++ b/vector/src/main/res/xml/vector_settings_notification_advanced_preferences.xml @@ -3,62 +3,65 @@ - - - + + + + - + + - + + - - + + - - - - - - - - - - diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index 2114dba373..5ecf693b44 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -2,9 +2,7 @@ - + + app:fragment="im.vector.riotx.features.settings.VectorSettingsAdvancedNotificationPreferenceFragment" /> + + + + + + + + + + + + + + + + + + -