forked from GitHub-Mirror/riotX-android
Dagger: merge develop compiling now.
This commit is contained in:
parent
b2d2582e0f
commit
1fa7b7367a
@ -18,6 +18,7 @@ package im.vector.matrix.rx
|
|||||||
|
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||||
|
import im.vector.matrix.android.api.session.pushers.Pusher
|
||||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||||
import im.vector.matrix.android.api.session.sync.SyncState
|
import im.vector.matrix.android.api.session.sync.SyncState
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
@ -36,6 +37,10 @@ class RxSession(private val session: Session) {
|
|||||||
return session.syncState().asObservable()
|
return session.syncState().asObservable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun livePushers(): Observable<List<Pusher>> {
|
||||||
|
return session.livePushers().asObservable()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Session.rx(): RxSession {
|
fun Session.rx(): RxSession {
|
||||||
|
@ -54,6 +54,10 @@ interface Session :
|
|||||||
*/
|
*/
|
||||||
val sessionParams: SessionParams
|
val sessionParams: SessionParams
|
||||||
|
|
||||||
|
val myUserId : String
|
||||||
|
get() = sessionParams.credentials.userId
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method allow to open a session. It does start some service on the background.
|
* This method allow to open a session. It does start some service on the background.
|
||||||
*/
|
*/
|
||||||
|
@ -22,6 +22,7 @@ import im.vector.matrix.android.api.auth.data.SessionParams
|
|||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.internal.crypto.CryptoModule
|
import im.vector.matrix.android.internal.crypto.CryptoModule
|
||||||
import im.vector.matrix.android.internal.di.MatrixComponent
|
import im.vector.matrix.android.internal.di.MatrixComponent
|
||||||
|
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
|
||||||
import im.vector.matrix.android.internal.session.cache.CacheModule
|
import im.vector.matrix.android.internal.session.cache.CacheModule
|
||||||
import im.vector.matrix.android.internal.session.content.ContentModule
|
import im.vector.matrix.android.internal.session.content.ContentModule
|
||||||
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
||||||
@ -37,8 +38,11 @@ import im.vector.matrix.android.internal.session.room.send.RedactEventWorker
|
|||||||
import im.vector.matrix.android.internal.session.room.send.SendEventWorker
|
import im.vector.matrix.android.internal.session.room.send.SendEventWorker
|
||||||
import im.vector.matrix.android.internal.session.signout.SignOutModule
|
import im.vector.matrix.android.internal.session.signout.SignOutModule
|
||||||
import im.vector.matrix.android.internal.session.sync.SyncModule
|
import im.vector.matrix.android.internal.session.sync.SyncModule
|
||||||
|
import im.vector.matrix.android.internal.session.sync.SyncTask
|
||||||
|
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
|
||||||
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
|
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
|
||||||
import im.vector.matrix.android.internal.session.user.UserModule
|
import im.vector.matrix.android.internal.session.user.UserModule
|
||||||
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
|
|
||||||
@Component(dependencies = [MatrixComponent::class],
|
@Component(dependencies = [MatrixComponent::class],
|
||||||
modules = [
|
modules = [
|
||||||
@ -61,6 +65,14 @@ internal interface SessionComponent {
|
|||||||
|
|
||||||
fun session(): Session
|
fun session(): Session
|
||||||
|
|
||||||
|
fun syncTask(): SyncTask
|
||||||
|
|
||||||
|
fun syncTokenStore(): SyncTokenStore
|
||||||
|
|
||||||
|
fun networkConnectivityChecker(): NetworkConnectivityChecker
|
||||||
|
|
||||||
|
fun taskExecutor(): TaskExecutor
|
||||||
|
|
||||||
fun inject(sendEventWorker: SendEventWorker)
|
fun inject(sendEventWorker: SendEventWorker)
|
||||||
|
|
||||||
fun inject(sendEventWorker: SendRelationWorker)
|
fun inject(sendEventWorker: SendRelationWorker)
|
||||||
@ -77,7 +89,6 @@ internal interface SessionComponent {
|
|||||||
|
|
||||||
fun inject(addHttpPusherWorker: AddHttpPusherWorker)
|
fun inject(addHttpPusherWorker: AddHttpPusherWorker)
|
||||||
|
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(
|
fun create(
|
||||||
@ -86,4 +97,6 @@ internal interface SessionComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
|
|||||||
import im.vector.matrix.android.internal.database.model.PushRulesEntity
|
import im.vector.matrix.android.internal.database.model.PushRulesEntity
|
||||||
import im.vector.matrix.android.internal.database.model.PusherEntityFields
|
import im.vector.matrix.android.internal.database.model.PusherEntityFields
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
|
import im.vector.matrix.android.internal.session.SessionScope
|
||||||
import im.vector.matrix.android.internal.session.pushers.GetPushRulesTask
|
import im.vector.matrix.android.internal.session.pushers.GetPushRulesTask
|
||||||
import im.vector.matrix.android.internal.session.pushers.UpdatePushRuleEnableStatusTask
|
import im.vector.matrix.android.internal.session.pushers.UpdatePushRuleEnableStatusTask
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
@ -34,7 +35,7 @@ import im.vector.matrix.android.internal.task.configureWith
|
|||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@SessionScope
|
||||||
internal class DefaultPushRuleService @Inject constructor(
|
internal class DefaultPushRuleService @Inject constructor(
|
||||||
private val sessionParams: SessionParams,
|
private val sessionParams: SessionParams,
|
||||||
private val pushRulesTask: GetPushRulesTask,
|
private val pushRulesTask: GetPushRulesTask,
|
||||||
@ -43,10 +44,8 @@ internal class DefaultPushRuleService @Inject constructor(
|
|||||||
private val monarchy: Monarchy
|
private val monarchy: Monarchy
|
||||||
) : PushRuleService {
|
) : PushRuleService {
|
||||||
|
|
||||||
|
|
||||||
private var listeners = ArrayList<PushRuleService.PushRuleListener>()
|
private var listeners = ArrayList<PushRuleService.PushRuleListener>()
|
||||||
|
|
||||||
|
|
||||||
override fun fetchPushRules(scope: String) {
|
override fun fetchPushRules(scope: String) {
|
||||||
pushRulesTask
|
pushRulesTask
|
||||||
.configureWith(Unit)
|
.configureWith(Unit)
|
||||||
|
@ -19,7 +19,9 @@ import android.app.Service
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Binder
|
import android.os.Binder
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import androidx.work.ListenableWorker
|
||||||
import com.squareup.moshi.JsonEncodingException
|
import com.squareup.moshi.JsonEncodingException
|
||||||
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.failure.Failure
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
import im.vector.matrix.android.api.failure.MatrixError
|
import im.vector.matrix.android.api.failure.MatrixError
|
||||||
@ -31,6 +33,7 @@ import im.vector.matrix.android.internal.session.sync.model.SyncResponse
|
|||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
import im.vector.matrix.android.internal.task.TaskThread
|
import im.vector.matrix.android.internal.task.TaskThread
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
import im.vector.matrix.android.internal.task.configureWith
|
||||||
|
import im.vector.matrix.android.internal.worker.getSessionComponent
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.net.SocketTimeoutException
|
import java.net.SocketTimeoutException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -46,15 +49,15 @@ private const val BACKGROUND_LONG_POOL_TIMEOUT = 0L
|
|||||||
* in order to be able to perform a sync even if the app is not running.
|
* in order to be able to perform a sync even if the app is not running.
|
||||||
* The <receiver> and <service> must be declared in the Manifest or the app using the SDK
|
* The <receiver> and <service> must be declared in the Manifest or the app using the SDK
|
||||||
*/
|
*/
|
||||||
internal open class SyncService : Service() {
|
open class SyncService : Service() {
|
||||||
|
|
||||||
private var mIsSelfDestroyed: Boolean = false
|
private var mIsSelfDestroyed: Boolean = false
|
||||||
private var cancelableTask: Cancelable? = null
|
private var cancelableTask: Cancelable? = null
|
||||||
|
|
||||||
@Inject lateinit var syncTokenStore: SyncTokenStore
|
private lateinit var syncTokenStore: SyncTokenStore
|
||||||
@Inject lateinit var syncTask: SyncTask
|
private lateinit var syncTask: SyncTask
|
||||||
@Inject lateinit var networkConnectivityChecker: NetworkConnectivityChecker
|
private lateinit var networkConnectivityChecker: NetworkConnectivityChecker
|
||||||
@Inject lateinit var taskExecutor: TaskExecutor
|
private lateinit var taskExecutor: TaskExecutor
|
||||||
|
|
||||||
private var localBinder = LocalBinder()
|
private var localBinder = LocalBinder()
|
||||||
|
|
||||||
@ -68,6 +71,12 @@ internal open class SyncService : Service() {
|
|||||||
nextBatchDelay = 60_000L
|
nextBatchDelay = 60_000L
|
||||||
timeout = 0
|
timeout = 0
|
||||||
intent?.let {
|
intent?.let {
|
||||||
|
val userId = it.getStringExtra(EXTRA_USER_ID)
|
||||||
|
val sessionComponent = Matrix.getInstance(applicationContext).sessionManager.getSessionComponent(userId) ?: return@let
|
||||||
|
syncTokenStore = sessionComponent.syncTokenStore()
|
||||||
|
syncTask = sessionComponent.syncTask()
|
||||||
|
networkConnectivityChecker = sessionComponent.networkConnectivityChecker()
|
||||||
|
taskExecutor = sessionComponent.taskExecutor()
|
||||||
if (cancelableTask == null) {
|
if (cancelableTask == null) {
|
||||||
timer.cancel()
|
timer.cancel()
|
||||||
timer = Timer()
|
timer = Timer()
|
||||||
@ -191,7 +200,6 @@ internal open class SyncService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun notifySyncFinish() {
|
internal fun notifySyncFinish() {
|
||||||
|
|
||||||
listeners.forEach {
|
listeners.forEach {
|
||||||
try {
|
try {
|
||||||
it.onSyncFinsh()
|
it.onSyncFinsh()
|
||||||
@ -235,6 +243,8 @@ internal open class SyncService : Service() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
const val EXTRA_USER_ID = "EXTRA_USER_ID"
|
||||||
|
|
||||||
fun startLongPool(delay: Long) {
|
fun startLongPool(delay: Long) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ package im.vector.riotredesign.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.di.HasVectorInjector
|
||||||
import im.vector.riotredesign.core.services.AlarmSyncBroadcastReceiver
|
import im.vector.riotredesign.core.services.AlarmSyncBroadcastReceiver
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@ -27,6 +28,11 @@ class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() {
|
|||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
Timber.v("## onReceive() ${intent.action}")
|
Timber.v("## onReceive() ${intent.action}")
|
||||||
AlarmSyncBroadcastReceiver.scheduleAlarm(context, 10)
|
if (context is HasVectorInjector) {
|
||||||
|
val activeSession = context.injector().activeSessionHolder().getSafeActiveSession()
|
||||||
|
if (activeSession != null) {
|
||||||
|
AlarmSyncBroadcastReceiver.scheduleAlarm(context, activeSession.myUserId, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
|
|||||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||||
fun entersForeground() {
|
fun entersForeground() {
|
||||||
AlarmSyncBroadcastReceiver.cancelAlarm(appContext)
|
AlarmSyncBroadcastReceiver.cancelAlarm(appContext)
|
||||||
activeSessionHolder.getActiveSession().also {
|
activeSessionHolder.getSafeActiveSession()?.also {
|
||||||
it.stopAnyBackgroundSync()
|
it.stopAnyBackgroundSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,8 +128,9 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
|
|||||||
} else {
|
} else {
|
||||||
//TODO check if notifications are enabled for this device
|
//TODO check if notifications are enabled for this device
|
||||||
//We need to use alarm in this mode
|
//We need to use alarm in this mode
|
||||||
if (PreferencesManager.areNotificationEnabledForDevice(applicationContext)) {
|
val activeSession = activeSessionHolder.getSafeActiveSession()
|
||||||
AlarmSyncBroadcastReceiver.scheduleAlarm(applicationContext, 4_000L)
|
if (activeSession != null && PreferencesManager.areNotificationEnabledForDevice(applicationContext)) {
|
||||||
|
AlarmSyncBroadcastReceiver.scheduleAlarm(applicationContext, activeSession.myUserId, 4_000L)
|
||||||
Timber.i("Alarm scheduled to restart service")
|
Timber.i("Alarm scheduled to restart service")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ import im.vector.riotredesign.features.roomdirectory.createroom.CreateRoomFragme
|
|||||||
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerFragment
|
import im.vector.riotredesign.features.roomdirectory.picker.RoomDirectoryPickerFragment
|
||||||
import im.vector.riotredesign.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment
|
import im.vector.riotredesign.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment
|
||||||
import im.vector.riotredesign.features.settings.VectorSettingsActivity
|
import im.vector.riotredesign.features.settings.VectorSettingsActivity
|
||||||
|
import im.vector.riotredesign.features.settings.VectorSettingsNotificationPreferenceFragment
|
||||||
import im.vector.riotredesign.features.settings.VectorSettingsPreferencesFragment
|
import im.vector.riotredesign.features.settings.VectorSettingsPreferencesFragment
|
||||||
|
|
||||||
@Component(dependencies = [VectorComponent::class], modules = [ViewModelModule::class, HomeModule::class])
|
@Component(dependencies = [VectorComponent::class], modules = [ViewModelModule::class, HomeModule::class])
|
||||||
@ -133,6 +134,8 @@ interface ScreenComponent {
|
|||||||
|
|
||||||
fun inject(videoMediaViewerActivity: VideoMediaViewerActivity)
|
fun inject(videoMediaViewerActivity: VideoMediaViewerActivity)
|
||||||
|
|
||||||
|
fun inject(vectorSettingsNotificationPreferenceFragment: VectorSettingsNotificationPreferenceFragment)
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(vectorComponent: VectorComponent,
|
fun create(vectorComponent: VectorComponent,
|
||||||
|
@ -33,7 +33,9 @@ import im.vector.riotredesign.features.home.HomeNavigator
|
|||||||
import im.vector.riotredesign.features.home.HomeRoomListObservableStore
|
import im.vector.riotredesign.features.home.HomeRoomListObservableStore
|
||||||
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||||
import im.vector.riotredesign.features.navigation.Navigator
|
import im.vector.riotredesign.features.navigation.Navigator
|
||||||
|
import im.vector.riotredesign.features.notifications.NotificationBroadcastReceiver
|
||||||
import im.vector.riotredesign.features.notifications.NotificationDrawerManager
|
import im.vector.riotredesign.features.notifications.NotificationDrawerManager
|
||||||
|
import im.vector.riotredesign.features.notifications.PushRuleTriggerListener
|
||||||
import im.vector.riotredesign.features.rageshake.BugReporter
|
import im.vector.riotredesign.features.rageshake.BugReporter
|
||||||
import im.vector.riotredesign.features.rageshake.RageShake
|
import im.vector.riotredesign.features.rageshake.RageShake
|
||||||
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
|
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
|
||||||
@ -43,6 +45,8 @@ import javax.inject.Singleton
|
|||||||
@Singleton
|
@Singleton
|
||||||
interface VectorComponent {
|
interface VectorComponent {
|
||||||
|
|
||||||
|
fun inject(vectorApplication: NotificationBroadcastReceiver)
|
||||||
|
|
||||||
fun inject(vectorApplication: VectorApplication)
|
fun inject(vectorApplication: VectorApplication)
|
||||||
|
|
||||||
fun matrix(): Matrix
|
fun matrix(): Matrix
|
||||||
@ -79,6 +83,8 @@ interface VectorComponent {
|
|||||||
|
|
||||||
fun vectorUncaughtExceptionHandler(): VectorUncaughtExceptionHandler
|
fun vectorUncaughtExceptionHandler(): VectorUncaughtExceptionHandler
|
||||||
|
|
||||||
|
fun pushRuleTriggerListener(): PushRuleTriggerListener
|
||||||
|
|
||||||
@Component.Factory
|
@Component.Factory
|
||||||
interface Factory {
|
interface Factory {
|
||||||
fun create(@BindsInstance context: Context): VectorComponent
|
fun create(@BindsInstance context: Context): VectorComponent
|
||||||
|
@ -57,6 +57,7 @@ import im.vector.riotredesign.features.workers.signout.SignOutViewModel
|
|||||||
|
|
||||||
@Module
|
@Module
|
||||||
interface ViewModelModule {
|
interface ViewModelModule {
|
||||||
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
fun bindViewModelFactory(factory: VectorViewModelFactory): ViewModelProvider.Factory
|
fun bindViewModelFactory(factory: VectorViewModelFactory): ViewModelProvider.Factory
|
||||||
|
@ -6,10 +6,11 @@ import im.vector.riotredesign.R
|
|||||||
import im.vector.riotredesign.core.resources.AppNameProvider
|
import im.vector.riotredesign.core.resources.AppNameProvider
|
||||||
import im.vector.riotredesign.core.resources.LocaleProvider
|
import im.vector.riotredesign.core.resources.LocaleProvider
|
||||||
import im.vector.riotredesign.core.resources.StringProvider
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
private const val DEFAULT_PUSHER_FILE_TAG = "mobile"
|
private const val DEFAULT_PUSHER_FILE_TAG = "mobile"
|
||||||
|
|
||||||
class PushersManager(
|
class PushersManager @Inject constructor(
|
||||||
private val currentSession: Session,
|
private val currentSession: Session,
|
||||||
private val localeProvider: LocaleProvider,
|
private val localeProvider: LocaleProvider,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
|
@ -2,9 +2,10 @@ package im.vector.riotredesign.core.resources
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
class AppNameProvider(private val context: Context) {
|
class AppNameProvider @Inject constructor(private val context: Context) {
|
||||||
|
|
||||||
fun getAppName(): String {
|
fun getAppName(): String {
|
||||||
try {
|
try {
|
||||||
|
@ -8,6 +8,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.matrix.android.internal.session.sync.job.SyncService
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
||||||
@ -22,11 +23,12 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val userId = intent.getStringExtra(SyncService.EXTRA_USER_ID)
|
||||||
// This method is called when the BroadcastReceiver is receiving an Intent broadcast.
|
// This method is called when the BroadcastReceiver is receiving an Intent broadcast.
|
||||||
Timber.d("RestartBroadcastReceiver received intent")
|
Timber.d("RestartBroadcastReceiver received intent")
|
||||||
Intent(context, VectorSyncService::class.java).also {
|
Intent(context, VectorSyncService::class.java).also {
|
||||||
it.action = "SLOW"
|
it.action = "SLOW"
|
||||||
|
it.putExtra(SyncService.EXTRA_USER_ID, userId)
|
||||||
context.startService(it)
|
context.startService(it)
|
||||||
try {
|
try {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
@ -40,7 +42,7 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleAlarm(context, 30_000L)
|
scheduleAlarm(context, userId, 30_000L)
|
||||||
|
|
||||||
Timber.i("Alarm scheduled to restart service")
|
Timber.i("Alarm scheduled to restart service")
|
||||||
}
|
}
|
||||||
@ -48,11 +50,13 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
|||||||
companion object {
|
companion object {
|
||||||
const val REQUEST_CODE = 0
|
const val REQUEST_CODE = 0
|
||||||
|
|
||||||
fun scheduleAlarm(context: Context, delay: Long) {
|
fun scheduleAlarm(context: Context, userId: String, delay: Long) {
|
||||||
//Reschedule
|
//Reschedule
|
||||||
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java)
|
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java).apply {
|
||||||
|
putExtra(SyncService.EXTRA_USER_ID, userId)
|
||||||
|
}
|
||||||
val pIntent = PendingIntent.getBroadcast(context, AlarmSyncBroadcastReceiver.REQUEST_CODE,
|
val pIntent = PendingIntent.getBroadcast(context, AlarmSyncBroadcastReceiver.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) {
|
||||||
@ -65,7 +69,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, AlarmSyncBroadcastReceiver.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)
|
||||||
}
|
}
|
||||||
|
@ -1,587 +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.riotredesign.core.services
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.work.Constraints
|
|
||||||
import androidx.work.NetworkType
|
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
|
||||||
import androidx.work.WorkManager
|
|
||||||
import im.vector.matrix.android.api.session.Session
|
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
|
||||||
import im.vector.riotredesign.R
|
|
||||||
import im.vector.riotredesign.features.notifications.NotifiableEventResolver
|
|
||||||
import im.vector.riotredesign.features.notifications.NotificationUtils
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A service in charge of controlling whether the event stream is running or not.
|
|
||||||
*
|
|
||||||
* It manages messages notifications displayed to the end user.
|
|
||||||
*/
|
|
||||||
class EventStreamServiceX : VectorService() {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Managed session (no multi session for Riot)
|
|
||||||
*/
|
|
||||||
@Inject lateinit var session: Session
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set to true to simulate a push immediately when service is destroyed
|
|
||||||
*/
|
|
||||||
private var mSimulatePushImmediate = false
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current state.
|
|
||||||
*/
|
|
||||||
private var serviceState = ServiceState.INIT
|
|
||||||
set(newServiceState) {
|
|
||||||
Timber.i("setServiceState from $field to $newServiceState")
|
|
||||||
field = newServiceState
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Push manager
|
|
||||||
*/
|
|
||||||
// TODO private var mPushManager: PushManager? = null
|
|
||||||
|
|
||||||
private var mNotifiableEventResolver: NotifiableEventResolver? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Live events listener
|
|
||||||
*/
|
|
||||||
/* TODO
|
|
||||||
private val mEventsListener = object : MXEventListener() {
|
|
||||||
override fun onBingEvent(event: Event, roomState: RoomState, bingRule: BingRule) {
|
|
||||||
if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) {
|
|
||||||
Timber.i("%%%%%%%% MXEventListener: the event $event")
|
|
||||||
}
|
|
||||||
|
|
||||||
Timber.i("prepareNotification : " + event.eventId + " in " + roomState.roomId)
|
|
||||||
val session = Matrix.getMXSession(applicationContext, event.matrixId)
|
|
||||||
|
|
||||||
// invalid session ?
|
|
||||||
// should never happen.
|
|
||||||
// But it could be triggered because of multi accounts management.
|
|
||||||
// The dedicated account is removing but some pushes are still received.
|
|
||||||
if (null == session || !session.isAlive) {
|
|
||||||
Timber.i("prepareNotification : don't bing - no session")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EventType.CALL_INVITE == event.getClearType()) {
|
|
||||||
handleCallInviteEvent(event)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val notifiableEvent = mNotifiableEventResolver!!.resolveEvent(event, roomState, bingRule, session)
|
|
||||||
if (notifiableEvent != null) {
|
|
||||||
VectorApp.getInstance().notificationDrawerManager.onNotifiableEventReceived(notifiableEvent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onLiveEventsChunkProcessed(fromToken: String, toToken: String) {
|
|
||||||
Timber.i("%%%%%%%% MXEventListener: onLiveEventsChunkProcessed[$fromToken->$toToken]")
|
|
||||||
|
|
||||||
VectorApp.getInstance().notificationDrawerManager.refreshNotificationDrawer(OutdatedEventDetector(this@EventStreamServiceX))
|
|
||||||
|
|
||||||
// do not suspend the application if there is some active calls
|
|
||||||
if (ServiceState.CATCHUP == serviceState) {
|
|
||||||
val hasActiveCalls = session?.mCallsManager?.hasActiveCalls() == true
|
|
||||||
|
|
||||||
// if there are some active calls, the catchup should not be stopped.
|
|
||||||
// because an user could answer to a call from another device.
|
|
||||||
// there will no push because it is his own message.
|
|
||||||
// so, the client has no choice to catchup until the ring is shutdown
|
|
||||||
if (hasActiveCalls) {
|
|
||||||
Timber.i("onLiveEventsChunkProcessed : Catchup again because there are active calls")
|
|
||||||
catchup(false)
|
|
||||||
} else if (ServiceState.CATCHUP == serviceState) {
|
|
||||||
Timber.i("onLiveEventsChunkProcessed : no Active call")
|
|
||||||
CallsManager.getSharedInstance().checkDeadCalls()
|
|
||||||
stop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service internal state
|
|
||||||
*/
|
|
||||||
private enum class ServiceState {
|
|
||||||
// Initial state
|
|
||||||
INIT,
|
|
||||||
// Service is started for a Catchup. Once the catchup is finished the service will be stopped
|
|
||||||
CATCHUP,
|
|
||||||
// Service is started, and session is monitored
|
|
||||||
STARTED
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {
|
|
||||||
//setup injector
|
|
||||||
super.onCreate()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
|
||||||
// Cancel any previous worker
|
|
||||||
cancelAnySimulatedPushSchedule()
|
|
||||||
|
|
||||||
// no intent : restarted by Android
|
|
||||||
if (null == intent) {
|
|
||||||
// Cannot happen anymore
|
|
||||||
Timber.e("onStartCommand : null intent")
|
|
||||||
myStopSelf()
|
|
||||||
return START_NOT_STICKY
|
|
||||||
}
|
|
||||||
|
|
||||||
val action = intent.action
|
|
||||||
|
|
||||||
Timber.i("onStartCommand with action : $action (current state $serviceState)")
|
|
||||||
|
|
||||||
// Manage foreground notification
|
|
||||||
when (action) {
|
|
||||||
ACTION_BOOT_COMPLETE,
|
|
||||||
ACTION_APPLICATION_UPGRADE,
|
|
||||||
ACTION_SIMULATED_PUSH_RECEIVED -> {
|
|
||||||
// Display foreground notification
|
|
||||||
Timber.i("startForeground")
|
|
||||||
val notification = NotificationUtils.buildForegroundServiceNotification(this, R.string.notification_sync_in_progress)
|
|
||||||
startForeground(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE, notification)
|
|
||||||
}
|
|
||||||
ACTION_GO_TO_FOREGROUND -> {
|
|
||||||
// Stop foreground notification display
|
|
||||||
Timber.i("stopForeground")
|
|
||||||
stopForeground(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null == session) {
|
|
||||||
Timber.e("onStartCommand : no sessions")
|
|
||||||
myStopSelf()
|
|
||||||
return START_NOT_STICKY
|
|
||||||
}
|
|
||||||
|
|
||||||
when (action) {
|
|
||||||
ACTION_START,
|
|
||||||
ACTION_GO_TO_FOREGROUND ->
|
|
||||||
when (serviceState) {
|
|
||||||
ServiceState.INIT ->
|
|
||||||
start(false)
|
|
||||||
ServiceState.CATCHUP ->
|
|
||||||
// A push has been received before, just change state, to avoid stopping the service when catchup is over
|
|
||||||
serviceState = ServiceState.STARTED
|
|
||||||
ServiceState.STARTED -> {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ACTION_STOP,
|
|
||||||
ACTION_GO_TO_BACKGROUND,
|
|
||||||
ACTION_LOGOUT ->
|
|
||||||
stop()
|
|
||||||
ACTION_PUSH_RECEIVED,
|
|
||||||
ACTION_SIMULATED_PUSH_RECEIVED ->
|
|
||||||
when (serviceState) {
|
|
||||||
ServiceState.INIT ->
|
|
||||||
start(true)
|
|
||||||
ServiceState.CATCHUP ->
|
|
||||||
catchup(true)
|
|
||||||
ServiceState.STARTED ->
|
|
||||||
// Nothing to do
|
|
||||||
Unit
|
|
||||||
}
|
|
||||||
ACTION_PUSH_UPDATE -> pushStatusUpdate()
|
|
||||||
ACTION_BOOT_COMPLETE -> {
|
|
||||||
// No FCM only
|
|
||||||
mSimulatePushImmediate = true
|
|
||||||
stop()
|
|
||||||
}
|
|
||||||
ACTION_APPLICATION_UPGRADE -> {
|
|
||||||
// FDroid only
|
|
||||||
catchup(true)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
// Should not happen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We don't want the service to be restarted automatically by the System
|
|
||||||
return START_NOT_STICKY
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
|
|
||||||
// Schedule worker?
|
|
||||||
scheduleSimulatedPushIfNeeded()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tell the WorkManager to cancel any schedule of push simulation
|
|
||||||
*/
|
|
||||||
private fun cancelAnySimulatedPushSchedule() {
|
|
||||||
WorkManager.getInstance().cancelAllWorkByTag(PUSH_SIMULATOR_REQUEST_TAG)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the WorkManager to schedule a simulated push, if necessary
|
|
||||||
*/
|
|
||||||
private fun scheduleSimulatedPushIfNeeded() {
|
|
||||||
if (shouldISimulatePush()) {
|
|
||||||
val delay = if (mSimulatePushImmediate) 0 else 60_000 // TODO mPushManager?.backgroundSyncDelay ?: let { 60_000 }
|
|
||||||
Timber.i("## service is schedule to restart in $delay millis, if network is connected")
|
|
||||||
|
|
||||||
val pushSimulatorRequest = OneTimeWorkRequestBuilder<PushSimulatorWorker>()
|
|
||||||
.setInitialDelay(delay.toLong(), TimeUnit.MILLISECONDS)
|
|
||||||
.setConstraints(Constraints.Builder()
|
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
|
||||||
.build())
|
|
||||||
.addTag(PUSH_SIMULATOR_REQUEST_TAG)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
WorkManager.getInstance().let {
|
|
||||||
// Cancel any previous worker
|
|
||||||
it.cancelAllWorkByTag(PUSH_SIMULATOR_REQUEST_TAG)
|
|
||||||
it.enqueue(pushSimulatorRequest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start the even stream.
|
|
||||||
*
|
|
||||||
* @param session the session
|
|
||||||
*/
|
|
||||||
private fun startEventStream(session: Session) {
|
|
||||||
/* TODO
|
|
||||||
// resume if it was only suspended
|
|
||||||
if (null != session.currentSyncToken) {
|
|
||||||
session.resumeEventStream()
|
|
||||||
} else {
|
|
||||||
session.startEventStream(store?.eventStreamToken)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Monitor the provided session.
|
|
||||||
*
|
|
||||||
* @param session the session
|
|
||||||
*/
|
|
||||||
private fun monitorSession(session: Session) {
|
|
||||||
/* TODO
|
|
||||||
session.dataHandler.addListener(mEventsListener)
|
|
||||||
CallsManager.getSharedInstance().addSession(session)
|
|
||||||
|
|
||||||
val store = session.dataHandler.store
|
|
||||||
|
|
||||||
// the store is ready (no data loading in progress...)
|
|
||||||
if (store!!.isReady) {
|
|
||||||
startEventStream(session, store)
|
|
||||||
} else {
|
|
||||||
// wait that the store is ready before starting the events stream
|
|
||||||
store.addMXStoreListener(object : MXStoreListener() {
|
|
||||||
override fun onStoreReady(accountId: String) {
|
|
||||||
startEventStream(session, store)
|
|
||||||
|
|
||||||
store.removeMXStoreListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStoreCorrupted(accountId: String, description: String) {
|
|
||||||
// start a new initial sync
|
|
||||||
if (null == store.eventStreamToken) {
|
|
||||||
startEventStream(session, store)
|
|
||||||
} else {
|
|
||||||
// the data are out of sync
|
|
||||||
Matrix.getInstance(applicationContext)!!.reloadSessions(applicationContext)
|
|
||||||
}
|
|
||||||
|
|
||||||
store.removeMXStoreListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStoreOOM(accountId: String, description: String) {
|
|
||||||
val uiHandler = Handler(mainLooper)
|
|
||||||
|
|
||||||
uiHandler.post {
|
|
||||||
Toast.makeText(applicationContext, "$accountId : $description", Toast.LENGTH_LONG).show()
|
|
||||||
Matrix.getInstance(applicationContext)!!.reloadSessions(applicationContext)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
store.open()
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* internal start.
|
|
||||||
*/
|
|
||||||
private fun start(forPush: Boolean) {
|
|
||||||
val applicationContext = applicationContext
|
|
||||||
// TODO mPushManager = Matrix.getInstance(applicationContext)!!.pushManager
|
|
||||||
mNotifiableEventResolver = NotifiableEventResolver(applicationContext)
|
|
||||||
|
|
||||||
monitorSession(session!!)
|
|
||||||
|
|
||||||
serviceState = if (forPush) {
|
|
||||||
ServiceState.CATCHUP
|
|
||||||
} else {
|
|
||||||
ServiceState.STARTED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* internal stop.
|
|
||||||
*/
|
|
||||||
private fun stop() {
|
|
||||||
Timber.i("## stop(): the service is stopped")
|
|
||||||
|
|
||||||
/* TODO
|
|
||||||
if (null != session && session!!.isAlive) {
|
|
||||||
session!!.stopEventStream()
|
|
||||||
session!!.dataHandler.removeListener(mEventsListener)
|
|
||||||
CallsManager.getSharedInstance().removeSession(session)
|
|
||||||
}
|
|
||||||
session = null
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Stop the service
|
|
||||||
myStopSelf()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* internal catchup method.
|
|
||||||
*
|
|
||||||
* @param checkState true to check if the current state allow to perform a catchup
|
|
||||||
*/
|
|
||||||
private fun catchup(checkState: Boolean) {
|
|
||||||
var canCatchup = true
|
|
||||||
|
|
||||||
if (!checkState) {
|
|
||||||
Timber.i("catchup without checking serviceState ")
|
|
||||||
} else {
|
|
||||||
Timber.i("catchup with serviceState " + serviceState + " CurrentActivity ") // TODO + VectorApp.getCurrentActivity())
|
|
||||||
|
|
||||||
/* TODO
|
|
||||||
// the catchup should only be done
|
|
||||||
// 1- the serviceState is in catchup : the event stream might have gone to sleep between two catchups
|
|
||||||
// 2- the thread is suspended
|
|
||||||
// 3- the application has been launched by a push so there is no displayed activity
|
|
||||||
canCatchup = (serviceState == ServiceState.CATCHUP
|
|
||||||
//|| (serviceState == ServiceState.PAUSE)
|
|
||||||
|| ServiceState.STARTED == serviceState && null == VectorApp.getCurrentActivity())
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canCatchup) {
|
|
||||||
if (session != null) {
|
|
||||||
// TODO session!!.catchupEventStream()
|
|
||||||
} else {
|
|
||||||
Timber.i("catchup no session")
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceState = ServiceState.CATCHUP
|
|
||||||
} else {
|
|
||||||
Timber.i("No catchup is triggered because there is already a running event thread")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The push status has been updated (i.e disabled or enabled).
|
|
||||||
* TODO Useless now?
|
|
||||||
*/
|
|
||||||
private fun pushStatusUpdate() {
|
|
||||||
Timber.i("## pushStatusUpdate")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================================
|
|
||||||
* Push simulator
|
|
||||||
* ========================================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if the FCM is disable or not setup, user allowed background sync, user wants notification
|
|
||||||
*/
|
|
||||||
private fun shouldISimulatePush(): Boolean {
|
|
||||||
return false
|
|
||||||
|
|
||||||
/* TODO
|
|
||||||
|
|
||||||
if (Matrix.getInstance(applicationContext)?.defaultSession == null) {
|
|
||||||
Timber.i("## shouldISimulatePush: NO: no session")
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
mPushManager?.let { pushManager ->
|
|
||||||
if (pushManager.useFcm()
|
|
||||||
&& !TextUtils.isEmpty(pushManager.currentRegistrationToken)
|
|
||||||
&& pushManager.isServerRegistered) {
|
|
||||||
// FCM is ok
|
|
||||||
Timber.i("## shouldISimulatePush: NO: FCM is up")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pushManager.isBackgroundSyncAllowed) {
|
|
||||||
// User has disabled background sync
|
|
||||||
Timber.i("## shouldISimulatePush: NO: background sync not allowed")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pushManager.areDeviceNotificationsAllowed()) {
|
|
||||||
// User does not want notifications
|
|
||||||
Timber.i("## shouldISimulatePush: NO: user does not want notification")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lets simulate push
|
|
||||||
Timber.i("## shouldISimulatePush: YES")
|
|
||||||
return true
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//================================================================================
|
|
||||||
// Call management
|
|
||||||
//================================================================================
|
|
||||||
|
|
||||||
private fun handleCallInviteEvent(event: Event) {
|
|
||||||
/*
|
|
||||||
TODO
|
|
||||||
val session = Matrix.getMXSession(applicationContext, event.matrixId)
|
|
||||||
|
|
||||||
// invalid session ?
|
|
||||||
// should never happen.
|
|
||||||
// But it could be triggered because of multi accounts management.
|
|
||||||
// The dedicated account is removing but some pushes are still received.
|
|
||||||
if (null == session || !session.isAlive) {
|
|
||||||
Timber.v("prepareCallNotification : don't bing - no session")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val room: Room? = session.dataHandler.getRoom(event.roomId)
|
|
||||||
|
|
||||||
// invalid room ?
|
|
||||||
if (null == room) {
|
|
||||||
Timber.i("prepareCallNotification : don't bing - the room does not exist")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var callId: String? = null
|
|
||||||
var isVideo = false
|
|
||||||
|
|
||||||
try {
|
|
||||||
callId = event.contentAsJsonObject?.get("call_id")?.asString
|
|
||||||
|
|
||||||
// Check if it is a video call
|
|
||||||
val offer = event.contentAsJsonObject?.get("offer")?.asJsonObject
|
|
||||||
val sdp = offer?.get("sdp")
|
|
||||||
val sdpValue = sdp?.asString
|
|
||||||
|
|
||||||
isVideo = sdpValue?.contains("m=video") == true
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.e(e, "prepareNotification : getContentAsJsonObject")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(callId)) {
|
|
||||||
CallService.onIncomingCall(this,
|
|
||||||
isVideo,
|
|
||||||
room.getRoomDisplayName(this),
|
|
||||||
room.roomId,
|
|
||||||
session.myUserId!!,
|
|
||||||
callId!!)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val PUSH_SIMULATOR_REQUEST_TAG = "PUSH_SIMULATOR_REQUEST_TAG"
|
|
||||||
|
|
||||||
private const val ACTION_START = "im.vector.riotredesign.core.services.EventStreamServiceX.START"
|
|
||||||
private const val ACTION_LOGOUT = "im.vector.riotredesign.core.services.EventStreamServiceX.LOGOUT"
|
|
||||||
private const val ACTION_GO_TO_FOREGROUND = "im.vector.riotredesign.core.services.EventStreamServiceX.GO_TO_FOREGROUND"
|
|
||||||
private const val ACTION_GO_TO_BACKGROUND = "im.vector.riotredesign.core.services.EventStreamServiceX.GO_TO_BACKGROUND"
|
|
||||||
private const val ACTION_PUSH_UPDATE = "im.vector.riotredesign.core.services.EventStreamServiceX.PUSH_UPDATE"
|
|
||||||
private const val ACTION_PUSH_RECEIVED = "im.vector.riotredesign.core.services.EventStreamServiceX.PUSH_RECEIVED"
|
|
||||||
private const val ACTION_SIMULATED_PUSH_RECEIVED = "im.vector.riotredesign.core.services.EventStreamServiceX.SIMULATED_PUSH_RECEIVED"
|
|
||||||
private const val ACTION_STOP = "im.vector.riotredesign.core.services.EventStreamServiceX.STOP"
|
|
||||||
private const val ACTION_BOOT_COMPLETE = "im.vector.riotredesign.core.services.EventStreamServiceX.BOOT_COMPLETE"
|
|
||||||
private const val ACTION_APPLICATION_UPGRADE = "im.vector.riotredesign.core.services.EventStreamServiceX.APPLICATION_UPGRADE"
|
|
||||||
|
|
||||||
/* ==========================================================================================
|
|
||||||
* Events sent to the service
|
|
||||||
* ========================================================================================== */
|
|
||||||
|
|
||||||
fun onApplicationStarted(context: Context) {
|
|
||||||
sendAction(context, ACTION_START)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onLogout(context: Context) {
|
|
||||||
sendAction(context, ACTION_LOGOUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onAppGoingToForeground(context: Context) {
|
|
||||||
sendAction(context, ACTION_GO_TO_FOREGROUND)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onAppGoingToBackground(context: Context) {
|
|
||||||
sendAction(context, ACTION_GO_TO_BACKGROUND)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onPushUpdate(context: Context) {
|
|
||||||
sendAction(context, ACTION_PUSH_UPDATE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onPushReceived(context: Context) {
|
|
||||||
sendAction(context, ACTION_PUSH_RECEIVED)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onSimulatedPushReceived(context: Context) {
|
|
||||||
sendAction(context, ACTION_SIMULATED_PUSH_RECEIVED, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onApplicationStopped(context: Context) {
|
|
||||||
sendAction(context, ACTION_STOP)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onBootComplete(context: Context) {
|
|
||||||
sendAction(context, ACTION_BOOT_COMPLETE, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onApplicationUpgrade(context: Context) {
|
|
||||||
sendAction(context, ACTION_APPLICATION_UPGRADE, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun sendAction(context: Context, action: String, foreground: Boolean = false) {
|
|
||||||
Timber.i("sendAction $action")
|
|
||||||
|
|
||||||
val intent = Intent(context, EventStreamServiceX::class.java)
|
|
||||||
intent.action = action
|
|
||||||
|
|
||||||
if (foreground) {
|
|
||||||
ContextCompat.startForegroundService(context, intent)
|
|
||||||
} else {
|
|
||||||
context.startService(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +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.riotredesign.features.home
|
|
||||||
|
|
||||||
import android.net.Uri
|
|
||||||
import im.vector.matrix.android.api.permalinks.PermalinkData
|
|
||||||
import im.vector.matrix.android.api.permalinks.PermalinkParser
|
|
||||||
import im.vector.riotredesign.features.navigation.Navigator
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class HomePermalinkHandler @Inject constructor(private val homeNavigator: HomeNavigator,
|
|
||||||
private val navigator: Navigator) {
|
|
||||||
|
|
||||||
fun launch(deepLink: String?) {
|
|
||||||
val uri = deepLink?.let { Uri.parse(it) }
|
|
||||||
launch(uri)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun launch(deepLink: Uri?) {
|
|
||||||
if (deepLink == null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val permalinkData = PermalinkParser.parse(deepLink)
|
|
||||||
when (permalinkData) {
|
|
||||||
is PermalinkData.EventLink -> {
|
|
||||||
homeNavigator.openRoomDetail(permalinkData.roomIdOrAlias, permalinkData.eventId, navigator)
|
|
||||||
}
|
|
||||||
is PermalinkData.RoomLink -> {
|
|
||||||
homeNavigator.openRoomDetail(permalinkData.roomIdOrAlias, null, navigator)
|
|
||||||
}
|
|
||||||
is PermalinkData.GroupLink -> {
|
|
||||||
homeNavigator.openGroupDetail(permalinkData.groupId)
|
|
||||||
}
|
|
||||||
is PermalinkData.UserLink -> {
|
|
||||||
homeNavigator.openUserDetail(permalinkData.userId)
|
|
||||||
}
|
|
||||||
is PermalinkData.FallbackLink -> {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -22,9 +22,10 @@ import im.vector.matrix.android.api.permalinks.PermalinkData
|
|||||||
import im.vector.matrix.android.api.permalinks.PermalinkParser
|
import im.vector.matrix.android.api.permalinks.PermalinkParser
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.riotredesign.features.navigation.Navigator
|
import im.vector.riotredesign.features.navigation.Navigator
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class PermalinkHandler(private val session: Session,
|
class PermalinkHandler @Inject constructor(private val session: Session,
|
||||||
private val navigator: Navigator) {
|
private val navigator: Navigator) {
|
||||||
|
|
||||||
fun launch(context: Context, deepLink: String?, navigateToRoomInterceptor: NavigateToRoomInterceptor? = null): Boolean {
|
fun launch(context: Context, deepLink: String?, navigateToRoomInterceptor: NavigateToRoomInterceptor? = null): Boolean {
|
||||||
val uri = deepLink?.let { Uri.parse(it) }
|
val uri = deepLink?.let { Uri.parse(it) }
|
||||||
|
@ -31,12 +31,13 @@ import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTex
|
|||||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_
|
import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
import im.vector.riotredesign.features.home.room.detail.timeline.util.MessageInformationDataFactory
|
||||||
import me.gujun.android.span.span
|
import me.gujun.android.span.span
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
// This class handles timeline events who haven't been successfully decrypted
|
// This class handles timeline events who haven't been successfully decrypted
|
||||||
class EncryptedItemFactory(private val messageInformationDataFactory: MessageInformationDataFactory,
|
class EncryptedItemFactory @Inject constructor(private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||||
private val colorProvider: ColorProvider,
|
private val colorProvider: ColorProvider,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val avatarRenderer: AvatarRenderer) {
|
private val avatarRenderer: AvatarRenderer) {
|
||||||
|
|
||||||
fun create(event: TimelineEvent,
|
fun create(event: TimelineEvent,
|
||||||
nextEvent: TimelineEvent?,
|
nextEvent: TimelineEvent?,
|
||||||
@ -79,7 +80,7 @@ class EncryptedItemFactory(private val messageInformationDataFactory: MessageInf
|
|||||||
}))
|
}))
|
||||||
.longClickListener { view ->
|
.longClickListener { view ->
|
||||||
return@longClickListener callback?.onEventLongClicked(informationData, null, view)
|
return@longClickListener callback?.onEventLongClicked(informationData, null, view)
|
||||||
?: false
|
?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
|
@ -30,6 +30,7 @@ import im.vector.riotredesign.R
|
|||||||
import im.vector.riotredesign.core.resources.StringProvider
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter
|
import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The notifiable event resolver is able to create a NotifiableEvent (view model for notifications) from an sdk Event.
|
* The notifiable event resolver is able to create a NotifiableEvent (view model for notifications) from an sdk Event.
|
||||||
@ -37,8 +38,8 @@ import timber.log.Timber
|
|||||||
* The NotifiableEventResolver is the only aware of session/store, the NotificationDrawerManager has no knowledge of that,
|
* The NotifiableEventResolver is the only aware of session/store, the NotificationDrawerManager has no knowledge of that,
|
||||||
* this pattern allow decoupling between the object responsible of displaying notifications and the matrix sdk.
|
* this pattern allow decoupling between the object responsible of displaying notifications and the matrix sdk.
|
||||||
*/
|
*/
|
||||||
class NotifiableEventResolver(private val stringProvider: StringProvider,
|
class NotifiableEventResolver @Inject constructor(private val stringProvider: StringProvider,
|
||||||
private val noticeEventFormatter: NoticeEventFormatter) {
|
private val noticeEventFormatter: NoticeEventFormatter) {
|
||||||
|
|
||||||
//private val eventDisplay = RiotEventDisplay(context)
|
//private val eventDisplay = RiotEventDisplay(context)
|
||||||
|
|
||||||
@ -95,8 +96,8 @@ class NotifiableEventResolver(private val stringProvider: StringProvider,
|
|||||||
// Ok room is not known in store, but we can still display something
|
// Ok room is not known in store, but we can still display something
|
||||||
val body =
|
val body =
|
||||||
event.annotations?.editSummary?.aggregatedContent?.toModel<MessageContent>()?.body
|
event.annotations?.editSummary?.aggregatedContent?.toModel<MessageContent>()?.body
|
||||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||||
val roomName = stringProvider.getString(R.string.notification_unknown_room_name)
|
val roomName = stringProvider.getString(R.string.notification_unknown_room_name)
|
||||||
val senderDisplayName = event.senderName
|
val senderDisplayName = event.senderName
|
||||||
|
|
||||||
@ -114,8 +115,8 @@ class NotifiableEventResolver(private val stringProvider: StringProvider,
|
|||||||
return notifiableEvent
|
return notifiableEvent
|
||||||
} else {
|
} else {
|
||||||
val body = event.annotations?.editSummary?.aggregatedContent?.toModel<MessageContent>()?.body
|
val body = event.annotations?.editSummary?.aggregatedContent?.toModel<MessageContent>()?.body
|
||||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||||
val roomName = room.roomSummary?.displayName ?: ""
|
val roomName = room.roomSummary?.displayName ?: ""
|
||||||
val senderDisplayName = event.senderName ?: ""
|
val senderDisplayName = event.senderName ?: ""
|
||||||
|
|
||||||
@ -137,15 +138,15 @@ class NotifiableEventResolver(private val stringProvider: StringProvider,
|
|||||||
// TODO They will be not displayed the first time (known limitation)
|
// TODO They will be not displayed the first time (known limitation)
|
||||||
notifiableEvent.roomAvatarPath = session.contentUrlResolver()
|
notifiableEvent.roomAvatarPath = session.contentUrlResolver()
|
||||||
.resolveThumbnail(room.roomSummary?.avatarUrl,
|
.resolveThumbnail(room.roomSummary?.avatarUrl,
|
||||||
250,
|
250,
|
||||||
250,
|
250,
|
||||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||||
|
|
||||||
notifiableEvent.senderAvatarPath = session.contentUrlResolver()
|
notifiableEvent.senderAvatarPath = session.contentUrlResolver()
|
||||||
.resolveThumbnail(event.senderAvatar,
|
.resolveThumbnail(event.senderAvatar,
|
||||||
250,
|
250,
|
||||||
250,
|
250,
|
||||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||||
|
|
||||||
return notifiableEvent
|
return notifiableEvent
|
||||||
}
|
}
|
||||||
@ -158,7 +159,7 @@ class NotifiableEventResolver(private val stringProvider: StringProvider,
|
|||||||
val dName = event.senderId?.let { session.getUser(it)?.displayName }
|
val dName = event.senderId?.let { session.getUser(it)?.displayName }
|
||||||
if (Membership.INVITE == content.membership) {
|
if (Membership.INVITE == content.membership) {
|
||||||
val body = noticeEventFormatter.format(event, dName)
|
val body = noticeEventFormatter.format(event, dName)
|
||||||
?: stringProvider.getString(R.string.notification_new_invitation)
|
?: stringProvider.getString(R.string.notification_new_invitation)
|
||||||
return InviteNotifiableEvent(
|
return InviteNotifiableEvent(
|
||||||
session.sessionParams.credentials.userId,
|
session.sessionParams.credentials.userId,
|
||||||
eventId = event.eventId!!,
|
eventId = event.eventId!!,
|
||||||
|
@ -20,12 +20,12 @@ import android.content.BroadcastReceiver
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.core.app.RemoteInput
|
import androidx.core.app.RemoteInput
|
||||||
import im.vector.matrix.android.api.Matrix
|
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.room.Room
|
import im.vector.matrix.android.api.session.room.Room
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.di.ActiveSessionHolder
|
import im.vector.riotredesign.core.di.ActiveSessionHolder
|
||||||
|
import im.vector.riotredesign.core.di.HasVectorInjector
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -38,10 +38,14 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
|||||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
|
|
||||||
|
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (intent == null || context == null) return
|
if (intent == null || context == null) return
|
||||||
Timber.v("NotificationBroadcastReceiver received : $intent")
|
Timber.v("NotificationBroadcastReceiver received : $intent")
|
||||||
|
val appContext = context.applicationContext
|
||||||
|
if (appContext is HasVectorInjector) {
|
||||||
|
appContext.injector().inject(this)
|
||||||
|
}
|
||||||
when (intent.action) {
|
when (intent.action) {
|
||||||
NotificationUtils.SMART_REPLY_ACTION ->
|
NotificationUtils.SMART_REPLY_ACTION ->
|
||||||
handleSmartReply(intent, context)
|
handleSmartReply(intent, context)
|
||||||
@ -60,7 +64,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleMarkAsRead(context: Context, roomId: String) {
|
private fun handleMarkAsRead(context: Context, roomId: String) {
|
||||||
activeSessionHolder.getActiveSession().let { session ->
|
activeSessionHolder.getActiveSession().let { session ->
|
||||||
session.getRoom(roomId)
|
session.getRoom(roomId)
|
||||||
?.markAllAsRead(object : MatrixCallback<Unit> {})
|
?.markAllAsRead(object : MatrixCallback<Unit> {})
|
||||||
}
|
}
|
||||||
@ -95,7 +99,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
|||||||
false,
|
false,
|
||||||
System.currentTimeMillis(),
|
System.currentTimeMillis(),
|
||||||
session.getUser(session.sessionParams.credentials.userId)?.displayName
|
session.getUser(session.sessionParams.credentials.userId)?.displayName
|
||||||
?: context?.getString(R.string.notification_sender_me),
|
?: context?.getString(R.string.notification_sender_me),
|
||||||
session.sessionParams.credentials.userId,
|
session.sessionParams.credentials.userId,
|
||||||
message,
|
message,
|
||||||
room.roomId,
|
room.roomId,
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.riotredesign.features.notifications
|
package im.vector.riotredesign.features.notifications
|
||||||
|
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.riotredesign.core.di.ActiveSessionHolder
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class OutdatedEventDetector @Inject constructor(private val session: Session) {
|
class OutdatedEventDetector @Inject constructor(private val activeSessionHolder: ActiveSessionHolder) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the given event is outdated.
|
* Returns true if the given event is outdated.
|
||||||
@ -29,7 +29,7 @@ class OutdatedEventDetector @Inject constructor(private val session: Session) {
|
|||||||
if (notifiableEvent is NotifiableMessageEvent) {
|
if (notifiableEvent is NotifiableMessageEvent) {
|
||||||
val eventID = notifiableEvent.eventId
|
val eventID = notifiableEvent.eventId
|
||||||
val roomID = notifiableEvent.roomId
|
val roomID = notifiableEvent.roomId
|
||||||
val room = session.getRoom(roomID) ?: return false
|
val room = activeSessionHolder.getSafeActiveSession()?.getRoom(roomID) ?: return false
|
||||||
return room.isEventRead(eventID)
|
return room.isEventRead(eventID)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -16,32 +16,43 @@
|
|||||||
|
|
||||||
package im.vector.riotredesign.features.settings
|
package im.vector.riotredesign.features.settings
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.di.ActiveSessionHolder
|
||||||
|
import im.vector.riotredesign.core.di.DaggerScreenComponent
|
||||||
import im.vector.riotredesign.core.platform.VectorPreferenceFragment
|
import im.vector.riotredesign.core.platform.VectorPreferenceFragment
|
||||||
import im.vector.riotredesign.core.pushers.PushersManager
|
import im.vector.riotredesign.core.pushers.PushersManager
|
||||||
import im.vector.riotredesign.push.fcm.FcmHelper
|
import im.vector.riotredesign.push.fcm.FcmHelper
|
||||||
import org.koin.android.ext.android.inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
// Referenced in vector_settings_preferences_root.xml
|
// Referenced in vector_settings_preferences_root.xml
|
||||||
class VectorSettingsNotificationPreferenceFragment : VectorPreferenceFragment() {
|
class VectorSettingsNotificationPreferenceFragment : VectorPreferenceFragment() {
|
||||||
|
|
||||||
|
|
||||||
override var titleRes: Int = R.string.settings_notifications
|
override var titleRes: Int = R.string.settings_notifications
|
||||||
|
|
||||||
val pushManager: PushersManager by inject()
|
@Inject lateinit var pushManager: PushersManager
|
||||||
|
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
addPreferencesFromResource(R.xml.vector_settings_notifications)
|
addPreferencesFromResource(R.xml.vector_settings_notifications)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
val screenComponent = DaggerScreenComponent.factory().create(vectorActivity.getVectorComponent(), vectorActivity)
|
||||||
|
super.onAttach(context)
|
||||||
|
screenComponent.inject(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
Matrix.getInstance().currentSession?.refreshPushers()
|
activeSessionHolder.getSafeActiveSession()?.refreshPushers()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
|
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
|
||||||
|
@ -35,12 +35,21 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.*
|
import android.widget.Button
|
||||||
|
import android.widget.CheckedTextView
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.preference.*
|
import androidx.preference.EditTextPreference
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceCategory
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import androidx.preference.SwitchPreference
|
||||||
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
@ -68,7 +77,19 @@ import im.vector.riotredesign.core.preference.BingRule
|
|||||||
import im.vector.riotredesign.core.preference.ProgressBarPreference
|
import im.vector.riotredesign.core.preference.ProgressBarPreference
|
||||||
import im.vector.riotredesign.core.preference.UserAvatarPreference
|
import im.vector.riotredesign.core.preference.UserAvatarPreference
|
||||||
import im.vector.riotredesign.core.preference.VectorPreference
|
import im.vector.riotredesign.core.preference.VectorPreference
|
||||||
import im.vector.riotredesign.core.utils.*
|
import im.vector.riotredesign.core.utils.PERMISSIONS_FOR_WRITING_FILES
|
||||||
|
import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_EXPORT_KEYS
|
||||||
|
import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||||
|
import im.vector.riotredesign.core.utils.allGranted
|
||||||
|
import im.vector.riotredesign.core.utils.checkPermissions
|
||||||
|
import im.vector.riotredesign.core.utils.copyToClipboard
|
||||||
|
import im.vector.riotredesign.core.utils.displayInWebView
|
||||||
|
import im.vector.riotredesign.core.utils.getCallRingtoneName
|
||||||
|
import im.vector.riotredesign.core.utils.getCallRingtoneUri
|
||||||
|
import im.vector.riotredesign.core.utils.openFileSelection
|
||||||
|
import im.vector.riotredesign.core.utils.setCallRingtoneUri
|
||||||
|
import im.vector.riotredesign.core.utils.setUseRiotDefaultRingtone
|
||||||
|
import im.vector.riotredesign.core.utils.toast
|
||||||
import im.vector.riotredesign.features.MainActivity
|
import im.vector.riotredesign.features.MainActivity
|
||||||
import im.vector.riotredesign.features.configuration.VectorConfiguration
|
import im.vector.riotredesign.features.configuration.VectorConfiguration
|
||||||
import im.vector.riotredesign.features.crypto.keys.KeysExporter
|
import im.vector.riotredesign.features.crypto.keys.KeysExporter
|
||||||
@ -76,7 +97,6 @@ import im.vector.riotredesign.features.crypto.keys.KeysImporter
|
|||||||
import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
||||||
import im.vector.riotredesign.features.themes.ThemeUtils
|
import im.vector.riotredesign.features.themes.ThemeUtils
|
||||||
import im.vector.riotredesign.features.version.getVersion
|
import im.vector.riotredesign.features.version.getVersion
|
||||||
import org.koin.android.ext.android.inject
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
@ -314,7 +334,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||||||
// It does not work on XML, do it here
|
// It does not work on XML, do it here
|
||||||
it.icon = activity?.let {
|
it.icon = activity?.let {
|
||||||
ThemeUtils.tintDrawable(it,
|
ThemeUtils.tintDrawable(it,
|
||||||
ContextCompat.getDrawable(it, R.drawable.ic_add_black)!!, R.attr.vctr_settings_icon_tint_color)
|
ContextCompat.getDrawable(it, R.drawable.ic_add_black)!!, R.attr.vctr_settings_icon_tint_color)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unfortunately, this is not supported in lib v7
|
// Unfortunately, this is not supported in lib v7
|
||||||
@ -331,7 +351,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||||||
// It does not work on XML, do it here
|
// It does not work on XML, do it here
|
||||||
it.icon = activity?.let {
|
it.icon = activity?.let {
|
||||||
ThemeUtils.tintDrawable(it,
|
ThemeUtils.tintDrawable(it,
|
||||||
ContextCompat.getDrawable(it, R.drawable.ic_add_black)!!, R.attr.vctr_settings_icon_tint_color)
|
ContextCompat.getDrawable(it, R.drawable.ic_add_black)!!, R.attr.vctr_settings_icon_tint_color)
|
||||||
}
|
}
|
||||||
|
|
||||||
it.setOnPreferenceClickListener {
|
it.setOnPreferenceClickListener {
|
||||||
@ -713,7 +733,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||||||
context?.let { context: Context ->
|
context?.let { context: Context ->
|
||||||
AlertDialog.Builder(context)
|
AlertDialog.Builder(context)
|
||||||
.setSingleChoiceItems(R.array.media_saving_choice,
|
.setSingleChoiceItems(R.array.media_saving_choice,
|
||||||
PreferencesManager.getSelectedMediasSavingPeriod(activity)) { d, n ->
|
PreferencesManager.getSelectedMediasSavingPeriod(activity)) { d, n ->
|
||||||
PreferencesManager.setSelectedMediasSavingPeriod(activity, n)
|
PreferencesManager.setSelectedMediasSavingPeriod(activity, n)
|
||||||
d.cancel()
|
d.cancel()
|
||||||
|
|
||||||
@ -1773,7 +1793,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||||||
mDisplayedEmails = newEmailsList
|
mDisplayedEmails = newEmailsList
|
||||||
|
|
||||||
val addEmailBtn = mUserSettingsCategory.findPreference(ADD_EMAIL_PREFERENCE_KEY)
|
val addEmailBtn = mUserSettingsCategory.findPreference(ADD_EMAIL_PREFERENCE_KEY)
|
||||||
?: return
|
?: return
|
||||||
|
|
||||||
var order = addEmailBtn.order
|
var order = addEmailBtn.order
|
||||||
|
|
||||||
@ -2449,7 +2469,9 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||||||
|
|
||||||
// disable the deletion for our own device
|
// disable the deletion for our own device
|
||||||
if (!TextUtils.equals(session.getMyDevice()?.deviceId, aDeviceInfo.deviceId)) {
|
if (!TextUtils.equals(session.getMyDevice()?.deviceId, aDeviceInfo.deviceId)) {
|
||||||
builder.setNegativeButton(R.string.delete) { _, _ -> displayDeviceDeletionDialog(aDeviceInfo) }
|
builder.setNegativeButton(R.string.delete) { _, _ ->
|
||||||
|
//displayDeviceDeletionDialog(aDeviceInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
builder.setNeutralButton(R.string.cancel, null)
|
builder.setNeutralButton(R.string.cancel, null)
|
||||||
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
|
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
|
||||||
@ -2746,8 +2768,8 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||||||
|
|
||||||
AlertDialog.Builder(thisActivity)
|
AlertDialog.Builder(thisActivity)
|
||||||
.setMessage(getString(R.string.encryption_import_room_keys_success,
|
.setMessage(getString(R.string.encryption_import_room_keys_success,
|
||||||
data.successfullyNumberOfImportedKeys,
|
data.successfullyNumberOfImportedKeys,
|
||||||
data.totalNumberOfKeys))
|
data.totalNumberOfKeys))
|
||||||
.setPositiveButton(R.string.ok) { dialog, _ -> dialog.dismiss() }
|
.setPositiveButton(R.string.ok) { dialog, _ -> dialog.dismiss() }
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,15 @@ import im.vector.riotredesign.core.platform.VectorBaseFragment
|
|||||||
import im.vector.riotredesign.core.resources.StringProvider
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
import im.vector.riotredesign.core.ui.list.genericFooterItem
|
import im.vector.riotredesign.core.ui.list.genericFooterItem
|
||||||
import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*
|
import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
// Referenced in vector_settings_notifications.xml
|
// Referenced in vector_settings_notifications.xml
|
||||||
class PushGatewaysFragment : VectorBaseFragment() {
|
class PushGatewaysFragment : VectorBaseFragment() {
|
||||||
|
|
||||||
override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy
|
override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy
|
||||||
|
|
||||||
|
@Inject lateinit var pushGatewaysViewModelFactory: PushGatewaysViewModel.Factory
|
||||||
private val viewModel: PushGatewaysViewModel by fragmentViewModel(PushGatewaysViewModel::class)
|
private val viewModel: PushGatewaysViewModel by fragmentViewModel(PushGatewaysViewModel::class)
|
||||||
|
|
||||||
private val epoxyController by lazy { PushGateWayController(StringProvider(requireContext().resources)) }
|
private val epoxyController by lazy { PushGateWayController(StringProvider(requireContext().resources)) }
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -16,38 +16,50 @@
|
|||||||
|
|
||||||
package im.vector.riotredesign.features.settings.push
|
package im.vector.riotredesign.features.settings.push
|
||||||
|
|
||||||
import androidx.lifecycle.Observer
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.*
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
|
import com.squareup.inject.assisted.Assisted
|
||||||
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.pushers.Pusher
|
import im.vector.matrix.android.api.session.pushers.Pusher
|
||||||
|
import im.vector.matrix.rx.RxSession
|
||||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||||
import org.koin.android.ext.android.get
|
|
||||||
|
|
||||||
|
|
||||||
data class PushGatewayViewState(
|
data class PushGatewayViewState(
|
||||||
val pushGateways: Async<List<Pusher>> = Uninitialized
|
val pushGateways: Async<List<Pusher>> = Uninitialized
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
|
||||||
class PushGatewaysViewModel(initialState: PushGatewayViewState) : VectorViewModel<PushGatewayViewState>(initialState) {
|
class PushGatewaysViewModel @AssistedInject constructor(@Assisted initialState: PushGatewayViewState,
|
||||||
|
private val session: Session) : VectorViewModel<PushGatewayViewState>(initialState) {
|
||||||
|
|
||||||
|
@AssistedInject.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: PushGatewayViewState): PushGatewaysViewModel
|
||||||
|
}
|
||||||
|
|
||||||
companion object : MvRxViewModelFactory<PushGatewaysViewModel, PushGatewayViewState> {
|
companion object : MvRxViewModelFactory<PushGatewaysViewModel, PushGatewayViewState> {
|
||||||
|
|
||||||
override fun create(viewModelContext: ViewModelContext, state: PushGatewayViewState): PushGatewaysViewModel? {
|
override fun create(viewModelContext: ViewModelContext, state: PushGatewayViewState): PushGatewaysViewModel? {
|
||||||
val session = viewModelContext.activity.get<Session>()
|
val fragment: PushGatewaysFragment = (viewModelContext as FragmentViewModelContext).fragment()
|
||||||
val fragment = (viewModelContext as FragmentViewModelContext).fragment
|
return fragment.pushGatewaysViewModelFactory.create(state)
|
||||||
|
|
||||||
val livePushers = session.livePushers()
|
|
||||||
|
|
||||||
val viewModel = PushGatewaysViewModel(state)
|
|
||||||
|
|
||||||
livePushers.observe(fragment, Observer {
|
|
||||||
viewModel.setState {
|
|
||||||
PushGatewayViewState(Success(it))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return viewModel
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
observePushers()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observePushers() {
|
||||||
|
RxSession(session)
|
||||||
|
.livePushers()
|
||||||
|
.execute {
|
||||||
|
copy(pushGateways = it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -19,23 +19,20 @@ import com.airbnb.mvrx.MvRxState
|
|||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.riotredesign.core.di.HasScreenInjector
|
||||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||||
import org.koin.android.ext.android.get
|
|
||||||
|
|
||||||
data class PushRulesViewState(
|
data class PushRulesViewState(
|
||||||
val rules: List<PushRule> = emptyList()
|
val rules: List<PushRule> = emptyList()
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
|
||||||
|
|
||||||
class PushRulesViewModel(initialState: PushRulesViewState) : VectorViewModel<PushRulesViewState>(initialState) {
|
class PushRulesViewModel(initialState: PushRulesViewState) : VectorViewModel<PushRulesViewState>(initialState) {
|
||||||
|
|
||||||
companion object : MvRxViewModelFactory<PushRulesViewModel, PushRulesViewState> {
|
companion object : MvRxViewModelFactory<PushRulesViewModel, PushRulesViewState> {
|
||||||
|
|
||||||
override fun initialState(viewModelContext: ViewModelContext): PushRulesViewState? {
|
override fun initialState(viewModelContext: ViewModelContext): PushRulesViewState? {
|
||||||
val session = viewModelContext.activity.get<Session>()
|
val session = (viewModelContext.activity as HasScreenInjector).injector().session()
|
||||||
val rules = session.getPushRules()
|
val rules = session.getPushRules()
|
||||||
|
|
||||||
return PushRulesViewState(rules)
|
return PushRulesViewState(rules)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user