Merge pull request #226 from vector-im/feature/notification_beta

Notification beta
This commit is contained in:
Benoit Marty 2019-06-27 10:46:27 +02:00 committed by GitHub
commit 9ec364b60e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 140 additions and 73 deletions

View File

@ -36,12 +36,15 @@ internal class BingRuleWatcher(monarchy: Monarchy,
override val query = Monarchy.Query<EventEntity> { override val query = Monarchy.Query<EventEntity> {


EventEntity.types(it, listOf( EventEntity.types(it, listOf(
EventType.REDACTION, EventType.MESSAGE, EventType.REDACTION, EventType.ENCRYPTED) EventType.MESSAGE,
EventType.REDACTION,
EventType.ENCRYPTED)
) )


} }


override fun processChanges(inserted: List<EventEntity>, updated: List<EventEntity>, deleted: List<EventEntity>) { override fun processChanges(inserted: List<EventEntity>, updated: List<EventEntity>, deleted: List<EventEntity>) {
// TODO Use const for "global"
val rules = defaultPushRuleService.getPushRules("global") val rules = defaultPushRuleService.getPushRules("global")
inserted.map { it.asDomain() } inserted.map { it.asDomain() }
.filter { it.senderId != sessionParams.credentials.userId } .filter { it.senderId != sessionParams.credentials.userId }

View File

@ -33,18 +33,19 @@ internal class DefaultProcessEventForPushTask(


private fun fulfilledBingRule(event: Event, rules: List<PushRule>): PushRule? { private fun fulfilledBingRule(event: Event, rules: List<PushRule>): PushRule? {
val conditionResolver = DefaultConditionResolver(event) val conditionResolver = DefaultConditionResolver(event)
rules.filter { it.enabled }.forEach { rule -> rules.filter { it.enabled }
val isFullfilled = rule.conditions?.map { .forEach { rule ->
it.asExecutableCondition()?.isSatisfied(conditionResolver) ?: false val isFullfilled = rule.conditions?.map {
}?.fold(true/*A rule with no conditions always matches*/, { acc, next -> it.asExecutableCondition()?.isSatisfied(conditionResolver) ?: false
//All conditions must hold true for an event in order to apply the action for the event. }?.fold(true/*A rule with no conditions always matches*/, { acc, next ->
acc && next //All conditions must hold true for an event in order to apply the action for the event.
}) ?: false acc && next
}) ?: false


if (isFullfilled) { if (isFullfilled) {
return rule return rule
} }
} }
return null return null
} }



View File

@ -8,7 +8,7 @@


<application> <application>


<receiver android:name=".receiver.OnApplicationUpgradeOrRebootReceiver"> <receiver android:name="im.vector.riotredesign.fdroid.receiver.OnApplicationUpgradeOrRebootReceiver">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" /> <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
@ -16,10 +16,14 @@
</receiver> </receiver>


<receiver <receiver
android:name=".core.services.AlarmSyncBroadcastReceiver" android:name="im.vector.riotredesign.fdroid.receiver.AlarmSyncBroadcastReceiver"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />


<service
android:name=".fdroid.receiver.service.VectorSyncService"
android:exported="false" />

</application> </application>


</manifest> </manifest>

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package im.vector.riotredesign.push.fcm.troubleshoot package im.vector.riotredesign.fdroid.features.settings.troubleshoot


import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import im.vector.riotredesign.R import im.vector.riotredesign.R

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package im.vector.riotredesign.push.fcm.troubleshoot package im.vector.riotredesign.fdroid.features.settings.troubleshoot


import android.content.Context import android.content.Context
import android.net.ConnectivityManager import android.net.ConnectivityManager

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package im.vector.riotredesign.push.fcm.troubleshoot package im.vector.riotredesign.fdroid.features.settings.troubleshoot


import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import im.vector.riotredesign.R import im.vector.riotredesign.R

View File

@ -0,0 +1,20 @@
/*
* 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.
*/

/**
* Code exclusively used by the FDroid build and not referenced on the main source code
*/
package im.vector.riotredesign.fdroid

View File

@ -1,4 +1,20 @@
package im.vector.riotredesign.core.services /*
* 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.riotredesign.fdroid.receiver


import android.app.AlarmManager import android.app.AlarmManager
import android.app.PendingIntent import android.app.PendingIntent
@ -8,6 +24,7 @@ import android.content.Intent
import android.os.Build import android.os.Build
import android.os.PowerManager import android.os.PowerManager
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import im.vector.riotredesign.fdroid.service.VectorSyncService
import timber.log.Timber import timber.log.Timber


class AlarmSyncBroadcastReceiver : BroadcastReceiver() { class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
@ -46,13 +63,12 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
} }


companion object { companion object {
const val REQUEST_CODE = 0 private const val REQUEST_CODE = 0


fun scheduleAlarm(context: Context, delay: Long) { fun scheduleAlarm(context: Context, delay: Long) {
//Reschedule //Reschedule
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java) val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java)
val pIntent = PendingIntent.getBroadcast(context, AlarmSyncBroadcastReceiver.REQUEST_CODE, val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
intent, PendingIntent.FLAG_UPDATE_CURRENT)
val firstMillis = System.currentTimeMillis() + delay val firstMillis = System.currentTimeMillis() + delay
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@ -64,8 +80,7 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {


fun cancelAlarm(context: Context) { fun cancelAlarm(context: Context) {
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java) val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java)
val pIntent = PendingIntent.getBroadcast(context, AlarmSyncBroadcastReceiver.REQUEST_CODE, val pIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
intent, PendingIntent.FLAG_UPDATE_CURRENT)
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmMgr.cancel(pIntent) alarmMgr.cancel(pIntent)
} }

View File

@ -15,12 +15,11 @@
* limitations under the License. * limitations under the License.
*/ */


package im.vector.riotredesign.receiver package im.vector.riotredesign.fdroid.receiver


import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import im.vector.riotredesign.core.services.AlarmSyncBroadcastReceiver
import timber.log.Timber import timber.log.Timber


class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() { class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() {

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package im.vector.riotredesign.core.services package im.vector.riotredesign.fdroid.service


import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
@ -28,12 +28,12 @@ import timber.log.Timber
class VectorSyncService : SyncService() { class VectorSyncService : SyncService() {


override fun onCreate() { override fun onCreate() {
Timber.v("VectorSyncService - onCreate ") Timber.v("VectorSyncService - onCreate")
super.onCreate() super.onCreate()
} }


override fun onDestroy() { override fun onDestroy() {
Timber.v("VectorSyncService - onDestroy ") Timber.v("VectorSyncService - onDestroy")
removeForegroundNotif() removeForegroundNotif()
super.onDestroy() super.onDestroy()
} }
@ -57,7 +57,7 @@ class VectorSyncService : SyncService() {
} }


/** /**
* If the service is bounded and the service was previously started we can remove foreground notif * If the service is bounded and the service was previously started we can remove foreground notification
*/ */
override fun onBind(intent: Intent?): IBinder { override fun onBind(intent: Intent?): IBinder {
Timber.v("VectorSyncService - onBind ") Timber.v("VectorSyncService - onBind ")

View File

@ -18,9 +18,14 @@ package im.vector.riotredesign.push.fcm


import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context

import im.vector.riotredesign.core.pushers.PushersManager import im.vector.riotredesign.core.pushers.PushersManager
import im.vector.riotredesign.fdroid.receiver.AlarmSyncBroadcastReceiver
import im.vector.riotredesign.features.settings.PreferencesManager
import timber.log.Timber


/**
* This class has an alter ego in the gplay variant.
*/
object FcmHelper { object FcmHelper {


fun isPushSupported(): Boolean = false fun isPushSupported(): Boolean = false
@ -52,4 +57,17 @@ object FcmHelper {
fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager) { fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager) {
// No op // No op
} }

fun onEnterForeground(context: Context) {
AlarmSyncBroadcastReceiver.cancelAlarm(context)
}

fun onEnterBackground(context: Context, hasSession: Boolean) {
//We need to use alarm in this mode
if (PreferencesManager.areNotificationEnabledForDevice(context)
&& hasSession) {
AlarmSyncBroadcastReceiver.scheduleAlarm(context, 4_000L)
Timber.i("Alarm scheduled to restart service")
}
}
} }

View File

@ -17,9 +17,9 @@ package im.vector.riotredesign.push.fcm


import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.riotredesign.fdroid.features.settings.troubleshoot.TestAutoStartBoot
import im.vector.riotredesign.fdroid.features.settings.troubleshoot.TestBackgroundRestrictions
import im.vector.riotredesign.features.settings.troubleshoot.* import im.vector.riotredesign.features.settings.troubleshoot.*
import im.vector.riotredesign.push.fcm.troubleshoot.TestAutoStartBoot
import im.vector.riotredesign.push.fcm.troubleshoot.TestBackgroundRestrictions


class NotificationTroubleshootTestManagerFactory { class NotificationTroubleshootTestManagerFactory {



View File

@ -9,7 +9,7 @@
android:name="firebase_analytics_collection_deactivated" android:name="firebase_analytics_collection_deactivated"
android:value="true" /> android:value="true" />


<service android:name=".push.fcm.VectorFirebaseMessagingService"> <service android:name=".gplay.push.fcm.VectorFirebaseMessagingService">
<intent-filter> <intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" /> <action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter> </intent-filter>

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package im.vector.riotredesign.push.fcm.troubleshoot package im.vector.riotredesign.gplay.features.settings.troubleshoot


import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.firebase.iid.FirebaseInstanceId import com.google.firebase.iid.FirebaseInstanceId

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package im.vector.riotredesign.push.fcm.troubleshoot package im.vector.riotredesign.gplay.features.settings.troubleshoot


import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.google.android.gms.common.ConnectionResult import com.google.android.gms.common.ConnectionResult

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package im.vector.riotredesign.push.fcm.troubleshoot package im.vector.riotredesign.gplay.features.settings.troubleshoot


import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import im.vector.riotredesign.R import im.vector.riotredesign.R

View File

@ -0,0 +1,21 @@
/*
* 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.
*/

/**
* Code exclusively used by the GPlay build and not referenced on the main source code
*/
package im.vector.riotredesign.gplay

View File

@ -17,7 +17,7 @@
* limitations under the License. * limitations under the License.
*/ */


package im.vector.riotredesign.push.fcm package im.vector.riotredesign.gplay.push.fcm


import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@ -39,6 +39,7 @@ import im.vector.riotredesign.features.notifications.NotifiableMessageEvent
import im.vector.riotredesign.features.notifications.NotificationDrawerManager import im.vector.riotredesign.features.notifications.NotificationDrawerManager
import im.vector.riotredesign.features.notifications.SimpleNotifiableEvent import im.vector.riotredesign.features.notifications.SimpleNotifiableEvent
import im.vector.riotredesign.features.settings.PreferencesManager import im.vector.riotredesign.features.settings.PreferencesManager
import im.vector.riotredesign.push.fcm.FcmHelper
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import timber.log.Timber import timber.log.Timber


View File

@ -99,4 +99,12 @@ object FcmHelper {
val resultCode = apiAvailability.isGooglePlayServicesAvailable(activity) val resultCode = apiAvailability.isGooglePlayServicesAvailable(activity)
return resultCode == ConnectionResult.SUCCESS return resultCode == ConnectionResult.SUCCESS
} }

fun onEnterForeground(context: Context) {
// No op
}

fun onEnterBackground(context: Context, hasSession: Boolean) {
// TODO FCM fallback
}
} }

View File

@ -18,9 +18,9 @@ package im.vector.riotredesign.push.fcm
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.riotredesign.features.settings.troubleshoot.* import im.vector.riotredesign.features.settings.troubleshoot.*
import im.vector.riotredesign.push.fcm.troubleshoot.TestFirebaseToken import im.vector.riotredesign.gplay.features.settings.troubleshoot.TestFirebaseToken
import im.vector.riotredesign.push.fcm.troubleshoot.TestPlayServices import im.vector.riotredesign.gplay.features.settings.troubleshoot.TestPlayServices
import im.vector.riotredesign.push.fcm.troubleshoot.TestTokenRegistration import im.vector.riotredesign.gplay.features.settings.troubleshoot.TestTokenRegistration


class NotificationTroubleshootTestManagerFactory { class NotificationTroubleshootTestManagerFactory {



View File

@ -68,15 +68,6 @@
<service <service
android:name=".core.services.CallService" android:name=".core.services.CallService"
android:exported="false" /> android:exported="false" />
<!--<service-->
<!--android:name="im.vector.matrix.android.internal.session.sync.job.SyncService"-->
<!--android:exported="false" />-->

<service
android:name=".core.services.VectorSyncService"
android:exported="false">

</service>


<!-- Receivers --> <!-- Receivers -->



View File

@ -36,7 +36,6 @@ import com.github.piasy.biv.loader.glide.GlideImageLoader
import com.jakewharton.threetenabp.AndroidThreeTen import com.jakewharton.threetenabp.AndroidThreeTen
import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.Matrix
import im.vector.riotredesign.core.di.AppModule import im.vector.riotredesign.core.di.AppModule
import im.vector.riotredesign.core.services.AlarmSyncBroadcastReceiver
import im.vector.riotredesign.features.configuration.VectorConfiguration import im.vector.riotredesign.features.configuration.VectorConfiguration
import im.vector.riotredesign.features.crypto.keysbackup.KeysBackupModule import im.vector.riotredesign.features.crypto.keysbackup.KeysBackupModule
import im.vector.riotredesign.features.home.HomeModule import im.vector.riotredesign.features.home.HomeModule
@ -47,7 +46,6 @@ import im.vector.riotredesign.features.notifications.PushRuleTriggerListener
import im.vector.riotredesign.features.rageshake.VectorFileLogger import im.vector.riotredesign.features.rageshake.VectorFileLogger
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule import im.vector.riotredesign.features.roomdirectory.RoomDirectoryModule
import im.vector.riotredesign.features.settings.PreferencesManager
import im.vector.riotredesign.features.version.getVersion import im.vector.riotredesign.features.version.getVersion
import im.vector.riotredesign.push.fcm.FcmHelper import im.vector.riotredesign.push.fcm.FcmHelper
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
@ -117,7 +115,7 @@ class VectorApplication : Application() {


@OnLifecycleEvent(Lifecycle.Event.ON_RESUME) @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun entersForeground() { fun entersForeground() {
AlarmSyncBroadcastReceiver.cancelAlarm(appContext) FcmHelper.onEnterForeground(appContext)
Matrix.getInstance().currentSession?.also { Matrix.getInstance().currentSession?.also {
it.stopAnyBackgroundSync() it.stopAnyBackgroundSync()
} }
@ -129,20 +127,8 @@ class VectorApplication : Application() {


notificationDrawerManager.persistInfo() notificationDrawerManager.persistInfo()


if (FcmHelper.isPushSupported()) { FcmHelper.onEnterBackground(appContext, Matrix.getInstance().currentSession != null)
//TODO FCM fallback
} else {
//TODO check if notifications are enabled for this device
//We need to use alarm in this mode
if (PreferencesManager.areNotificationEnabledForDevice(applicationContext)) {
if (Matrix.getInstance().currentSession != null) {
AlarmSyncBroadcastReceiver.scheduleAlarm(applicationContext, 4_000L)
Timber.i("Alarm scheduled to restart service")
}
}
}
} }

}) })





View File

@ -25,7 +25,7 @@ import timber.log.Timber


class PushRuleTriggerListener( class PushRuleTriggerListener(
private val resolver: NotifiableEventResolver, private val resolver: NotifiableEventResolver,
private val drawerManager: NotificationDrawerManager private val notificationDrawerManager: NotificationDrawerManager
) : PushRuleService.PushRuleListener { ) : PushRuleService.PushRuleListener {




@ -39,14 +39,14 @@ class PushRuleTriggerListener(
} }
val notificationAction = NotificationAction.extractFrom(actions) val notificationAction = NotificationAction.extractFrom(actions)
if (notificationAction.shouldNotify) { if (notificationAction.shouldNotify) {
val resolveEvent = resolver.resolveEvent(event, session!!) val notifiableEvent = resolver.resolveEvent(event, session!!)
if (resolveEvent == null) { if (notifiableEvent == null) {
Timber.v("## Failed to resolve event") Timber.v("## Failed to resolve event")
//TODO //TODO
} else { } else {
resolveEvent.noisy = !notificationAction.soundName.isNullOrBlank() notifiableEvent.noisy = !notificationAction.soundName.isNullOrBlank()
Timber.v("New event to notify $resolveEvent tweaks:$notificationAction") Timber.v("New event to notify $notifiableEvent tweaks:$notificationAction")
drawerManager.onNotifiableEventReceived(resolveEvent) notificationDrawerManager.onNotifiableEventReceived(notifiableEvent)
} }
} else { } else {
Timber.v("Matched push rule is set to not notify") Timber.v("Matched push rule is set to not notify")
@ -54,7 +54,7 @@ class PushRuleTriggerListener(
} }


override fun batchFinish() { override fun batchFinish() {
drawerManager.refreshNotificationDrawer() notificationDrawerManager.refreshNotificationDrawer()
} }


fun startWithSession(session: Session) { fun startWithSession(session: Session) {
@ -68,7 +68,7 @@ class PushRuleTriggerListener(
fun stop() { fun stop() {
session?.removePushRuleListener(this) session?.removePushRuleListener(this)
session = null session = null
drawerManager.clearAllEvents() notificationDrawerManager.clearAllEvents()
} }


} }