mirror of
https://github.com/element-hq/element-android
synced 2024-11-23 18:05:36 +03:00
Dagger: merge develop compiling now.
This commit is contained in:
parent
b2d2582e0f
commit
1fa7b7367a
25 changed files with 192 additions and 732 deletions
|
@ -18,6 +18,7 @@ package im.vector.matrix.rx
|
|||
|
||||
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.pushers.Pusher
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.sync.SyncState
|
||||
import io.reactivex.Observable
|
||||
|
@ -36,6 +37,10 @@ class RxSession(private val session: Session) {
|
|||
return session.syncState().asObservable()
|
||||
}
|
||||
|
||||
fun livePushers(): Observable<List<Pusher>> {
|
||||
return session.livePushers().asObservable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Session.rx(): RxSession {
|
||||
|
|
|
@ -54,6 +54,10 @@ interface Session :
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
|
|
@ -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.internal.crypto.CryptoModule
|
||||
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.content.ContentModule
|
||||
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.signout.SignOutModule
|
||||
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.user.UserModule
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
|
||||
@Component(dependencies = [MatrixComponent::class],
|
||||
modules = [
|
||||
|
@ -61,6 +65,14 @@ internal interface SessionComponent {
|
|||
|
||||
fun session(): Session
|
||||
|
||||
fun syncTask(): SyncTask
|
||||
|
||||
fun syncTokenStore(): SyncTokenStore
|
||||
|
||||
fun networkConnectivityChecker(): NetworkConnectivityChecker
|
||||
|
||||
fun taskExecutor(): TaskExecutor
|
||||
|
||||
fun inject(sendEventWorker: SendEventWorker)
|
||||
|
||||
fun inject(sendEventWorker: SendRelationWorker)
|
||||
|
@ -77,7 +89,6 @@ internal interface SessionComponent {
|
|||
|
||||
fun inject(addHttpPusherWorker: AddHttpPusherWorker)
|
||||
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
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.PusherEntityFields
|
||||
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.UpdatePushRuleEnableStatusTask
|
||||
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 javax.inject.Inject
|
||||
|
||||
|
||||
@SessionScope
|
||||
internal class DefaultPushRuleService @Inject constructor(
|
||||
private val sessionParams: SessionParams,
|
||||
private val pushRulesTask: GetPushRulesTask,
|
||||
|
@ -43,10 +44,8 @@ internal class DefaultPushRuleService @Inject constructor(
|
|||
private val monarchy: Monarchy
|
||||
) : PushRuleService {
|
||||
|
||||
|
||||
private var listeners = ArrayList<PushRuleService.PushRuleListener>()
|
||||
|
||||
|
||||
override fun fetchPushRules(scope: String) {
|
||||
pushRulesTask
|
||||
.configureWith(Unit)
|
||||
|
|
|
@ -19,7 +19,9 @@ import android.app.Service
|
|||
import android.content.Intent
|
||||
import android.os.Binder
|
||||
import android.os.IBinder
|
||||
import androidx.work.ListenableWorker
|
||||
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.failure.Failure
|
||||
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.TaskThread
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.worker.getSessionComponent
|
||||
import timber.log.Timber
|
||||
import java.net.SocketTimeoutException
|
||||
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.
|
||||
* 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 cancelableTask: Cancelable? = null
|
||||
|
||||
@Inject lateinit var syncTokenStore: SyncTokenStore
|
||||
@Inject lateinit var syncTask: SyncTask
|
||||
@Inject lateinit var networkConnectivityChecker: NetworkConnectivityChecker
|
||||
@Inject lateinit var taskExecutor: TaskExecutor
|
||||
private lateinit var syncTokenStore: SyncTokenStore
|
||||
private lateinit var syncTask: SyncTask
|
||||
private lateinit var networkConnectivityChecker: NetworkConnectivityChecker
|
||||
private lateinit var taskExecutor: TaskExecutor
|
||||
|
||||
private var localBinder = LocalBinder()
|
||||
|
||||
|
@ -68,6 +71,12 @@ internal open class SyncService : Service() {
|
|||
nextBatchDelay = 60_000L
|
||||
timeout = 0
|
||||
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) {
|
||||
timer.cancel()
|
||||
timer = Timer()
|
||||
|
@ -191,7 +200,6 @@ internal open class SyncService : Service() {
|
|||
}
|
||||
|
||||
internal fun notifySyncFinish() {
|
||||
|
||||
listeners.forEach {
|
||||
try {
|
||||
it.onSyncFinsh()
|
||||
|
@ -235,6 +243,8 @@ internal open class SyncService : Service() {
|
|||
|
||||
companion object {
|
||||
|
||||
const val EXTRA_USER_ID = "EXTRA_USER_ID"
|
||||
|
||||
fun startLongPool(delay: Long) {
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package im.vector.riotredesign.receiver
|
|||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import im.vector.riotredesign.core.di.HasVectorInjector
|
||||
import im.vector.riotredesign.core.services.AlarmSyncBroadcastReceiver
|
||||
import timber.log.Timber
|
||||
|
||||
|
@ -27,6 +28,11 @@ class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() {
|
|||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
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)
|
||||
fun entersForeground() {
|
||||
AlarmSyncBroadcastReceiver.cancelAlarm(appContext)
|
||||
activeSessionHolder.getActiveSession().also {
|
||||
activeSessionHolder.getSafeActiveSession()?.also {
|
||||
it.stopAnyBackgroundSync()
|
||||
}
|
||||
}
|
||||
|
@ -128,8 +128,9 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
|
|||
} else {
|
||||
//TODO check if notifications are enabled for this device
|
||||
//We need to use alarm in this mode
|
||||
if (PreferencesManager.areNotificationEnabledForDevice(applicationContext)) {
|
||||
AlarmSyncBroadcastReceiver.scheduleAlarm(applicationContext, 4_000L)
|
||||
val activeSession = activeSessionHolder.getSafeActiveSession()
|
||||
if (activeSession != null && PreferencesManager.areNotificationEnabledForDevice(applicationContext)) {
|
||||
AlarmSyncBroadcastReceiver.scheduleAlarm(applicationContext, activeSession.myUserId, 4_000L)
|
||||
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.roompreview.RoomPreviewNoPreviewFragment
|
||||
import im.vector.riotredesign.features.settings.VectorSettingsActivity
|
||||
import im.vector.riotredesign.features.settings.VectorSettingsNotificationPreferenceFragment
|
||||
import im.vector.riotredesign.features.settings.VectorSettingsPreferencesFragment
|
||||
|
||||
@Component(dependencies = [VectorComponent::class], modules = [ViewModelModule::class, HomeModule::class])
|
||||
|
@ -133,6 +134,8 @@ interface ScreenComponent {
|
|||
|
||||
fun inject(videoMediaViewerActivity: VideoMediaViewerActivity)
|
||||
|
||||
fun inject(vectorSettingsNotificationPreferenceFragment: VectorSettingsNotificationPreferenceFragment)
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
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.group.SelectedGroupStore
|
||||
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.PushRuleTriggerListener
|
||||
import im.vector.riotredesign.features.rageshake.BugReporter
|
||||
import im.vector.riotredesign.features.rageshake.RageShake
|
||||
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
|
||||
|
@ -43,6 +45,8 @@ import javax.inject.Singleton
|
|||
@Singleton
|
||||
interface VectorComponent {
|
||||
|
||||
fun inject(vectorApplication: NotificationBroadcastReceiver)
|
||||
|
||||
fun inject(vectorApplication: VectorApplication)
|
||||
|
||||
fun matrix(): Matrix
|
||||
|
@ -79,6 +83,8 @@ interface VectorComponent {
|
|||
|
||||
fun vectorUncaughtExceptionHandler(): VectorUncaughtExceptionHandler
|
||||
|
||||
fun pushRuleTriggerListener(): PushRuleTriggerListener
|
||||
|
||||
@Component.Factory
|
||||
interface Factory {
|
||||
fun create(@BindsInstance context: Context): VectorComponent
|
||||
|
|
|
@ -57,6 +57,7 @@ import im.vector.riotredesign.features.workers.signout.SignOutViewModel
|
|||
|
||||
@Module
|
||||
interface ViewModelModule {
|
||||
|
||||
|
||||
@Binds
|
||||
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.LocaleProvider
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val DEFAULT_PUSHER_FILE_TAG = "mobile"
|
||||
|
||||
class PushersManager(
|
||||
class PushersManager @Inject constructor(
|
||||
private val currentSession: Session,
|
||||
private val localeProvider: LocaleProvider,
|
||||
private val stringProvider: StringProvider,
|
||||
|
|
|
@ -2,9 +2,10 @@ package im.vector.riotredesign.core.resources
|
|||
|
||||
import android.content.Context
|
||||
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 {
|
||||
try {
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.content.Intent
|
|||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import androidx.core.content.ContextCompat
|
||||
import im.vector.matrix.android.internal.session.sync.job.SyncService
|
||||
import timber.log.Timber
|
||||
|
||||
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.
|
||||
Timber.d("RestartBroadcastReceiver received intent")
|
||||
Intent(context, VectorSyncService::class.java).also {
|
||||
it.action = "SLOW"
|
||||
it.putExtra(SyncService.EXTRA_USER_ID, userId)
|
||||
context.startService(it)
|
||||
try {
|
||||
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")
|
||||
}
|
||||
|
@ -48,11 +50,13 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
|||
companion object {
|
||||
const val REQUEST_CODE = 0
|
||||
|
||||
fun scheduleAlarm(context: Context, delay: Long) {
|
||||
fun scheduleAlarm(context: Context, userId: String, delay: Long) {
|
||||
//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,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val firstMillis = System.currentTimeMillis() + delay
|
||||
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
|
@ -65,7 +69,7 @@ class AlarmSyncBroadcastReceiver : BroadcastReceiver() {
|
|||
fun cancelAlarm(context: Context) {
|
||||
val intent = Intent(context, AlarmSyncBroadcastReceiver::class.java)
|
||||
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
|
||||
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.session.Session
|
||||
import im.vector.riotredesign.features.navigation.Navigator
|
||||
import javax.inject.Inject
|
||||
|
||||
class PermalinkHandler(private val session: Session,
|
||||
private val navigator: Navigator) {
|
||||
class PermalinkHandler @Inject constructor(private val session: Session,
|
||||
private val navigator: Navigator) {
|
||||
|
||||
fun launch(context: Context, deepLink: String?, navigateToRoomInterceptor: NavigateToRoomInterceptor? = null): Boolean {
|
||||
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.util.MessageInformationDataFactory
|
||||
import me.gujun.android.span.span
|
||||
import javax.inject.Inject
|
||||
|
||||
// This class handles timeline events who haven't been successfully decrypted
|
||||
class EncryptedItemFactory(private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val stringProvider: StringProvider,
|
||||
private val avatarRenderer: AvatarRenderer) {
|
||||
class EncryptedItemFactory @Inject constructor(private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val stringProvider: StringProvider,
|
||||
private val avatarRenderer: AvatarRenderer) {
|
||||
|
||||
fun create(event: TimelineEvent,
|
||||
nextEvent: TimelineEvent?,
|
||||
|
@ -79,7 +80,7 @@ class EncryptedItemFactory(private val messageInformationDataFactory: MessageInf
|
|||
}))
|
||||
.longClickListener { view ->
|
||||
return@longClickListener callback?.onEventLongClicked(informationData, null, view)
|
||||
?: false
|
||||
?: false
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
|
|
|
@ -30,6 +30,7 @@ import im.vector.riotredesign.R
|
|||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter
|
||||
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.
|
||||
|
@ -37,8 +38,8 @@ import timber.log.Timber
|
|||
* 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.
|
||||
*/
|
||||
class NotifiableEventResolver(private val stringProvider: StringProvider,
|
||||
private val noticeEventFormatter: NoticeEventFormatter) {
|
||||
class NotifiableEventResolver @Inject constructor(private val stringProvider: StringProvider,
|
||||
private val noticeEventFormatter: NoticeEventFormatter) {
|
||||
|
||||
//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
|
||||
val body =
|
||||
event.annotations?.editSummary?.aggregatedContent?.toModel<MessageContent>()?.body
|
||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||
val roomName = stringProvider.getString(R.string.notification_unknown_room_name)
|
||||
val senderDisplayName = event.senderName
|
||||
|
||||
|
@ -114,8 +115,8 @@ class NotifiableEventResolver(private val stringProvider: StringProvider,
|
|||
return notifiableEvent
|
||||
} else {
|
||||
val body = event.annotations?.editSummary?.aggregatedContent?.toModel<MessageContent>()?.body
|
||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||
?: event.root.getClearContent().toModel<MessageContent>()?.body
|
||||
?: stringProvider.getString(R.string.notification_unknown_new_event)
|
||||
val roomName = room.roomSummary?.displayName ?: ""
|
||||
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)
|
||||
notifiableEvent.roomAvatarPath = session.contentUrlResolver()
|
||||
.resolveThumbnail(room.roomSummary?.avatarUrl,
|
||||
250,
|
||||
250,
|
||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
250,
|
||||
250,
|
||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
|
||||
notifiableEvent.senderAvatarPath = session.contentUrlResolver()
|
||||
.resolveThumbnail(event.senderAvatar,
|
||||
250,
|
||||
250,
|
||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
250,
|
||||
250,
|
||||
ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
|
||||
return notifiableEvent
|
||||
}
|
||||
|
@ -158,7 +159,7 @@ class NotifiableEventResolver(private val stringProvider: StringProvider,
|
|||
val dName = event.senderId?.let { session.getUser(it)?.displayName }
|
||||
if (Membership.INVITE == content.membership) {
|
||||
val body = noticeEventFormatter.format(event, dName)
|
||||
?: stringProvider.getString(R.string.notification_new_invitation)
|
||||
?: stringProvider.getString(R.string.notification_new_invitation)
|
||||
return InviteNotifiableEvent(
|
||||
session.sessionParams.credentials.userId,
|
||||
eventId = event.eventId!!,
|
||||
|
|
|
@ -20,12 +20,12 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
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.session.Session
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.di.ActiveSessionHolder
|
||||
import im.vector.riotredesign.core.di.HasVectorInjector
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -38,10 +38,14 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
|||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||
|
||||
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (intent == null || context == null) return
|
||||
Timber.v("NotificationBroadcastReceiver received : $intent")
|
||||
|
||||
val appContext = context.applicationContext
|
||||
if (appContext is HasVectorInjector) {
|
||||
appContext.injector().inject(this)
|
||||
}
|
||||
when (intent.action) {
|
||||
NotificationUtils.SMART_REPLY_ACTION ->
|
||||
handleSmartReply(intent, context)
|
||||
|
@ -60,7 +64,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
|||
}
|
||||
|
||||
private fun handleMarkAsRead(context: Context, roomId: String) {
|
||||
activeSessionHolder.getActiveSession().let { session ->
|
||||
activeSessionHolder.getActiveSession().let { session ->
|
||||
session.getRoom(roomId)
|
||||
?.markAllAsRead(object : MatrixCallback<Unit> {})
|
||||
}
|
||||
|
@ -95,7 +99,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
|
|||
false,
|
||||
System.currentTimeMillis(),
|
||||
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,
|
||||
message,
|
||||
room.roomId,
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
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
|
||||
|
||||
class OutdatedEventDetector @Inject constructor(private val session: Session) {
|
||||
class OutdatedEventDetector @Inject constructor(private val activeSessionHolder: ActiveSessionHolder) {
|
||||
|
||||
/**
|
||||
* Returns true if the given event is outdated.
|
||||
|
@ -29,7 +29,7 @@ class OutdatedEventDetector @Inject constructor(private val session: Session) {
|
|||
if (notifiableEvent is NotifiableMessageEvent) {
|
||||
val eventID = notifiableEvent.eventId
|
||||
val roomID = notifiableEvent.roomId
|
||||
val room = session.getRoom(roomID) ?: return false
|
||||
val room = activeSessionHolder.getSafeActiveSession()?.getRoom(roomID) ?: return false
|
||||
return room.isEventRead(eventID)
|
||||
}
|
||||
return false
|
||||
|
|
|
@ -16,32 +16,43 @@
|
|||
|
||||
package im.vector.riotredesign.features.settings
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.SwitchPreference
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
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.pushers.PushersManager
|
||||
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
|
||||
class VectorSettingsNotificationPreferenceFragment : VectorPreferenceFragment() {
|
||||
|
||||
|
||||
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?) {
|
||||
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() {
|
||||
super.onResume()
|
||||
Matrix.getInstance().currentSession?.refreshPushers()
|
||||
activeSessionHolder.getSafeActiveSession()?.refreshPushers()
|
||||
}
|
||||
|
||||
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
|
||||
|
|
|
@ -35,12 +35,21 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
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.core.content.ContextCompat
|
||||
import androidx.core.content.edit
|
||||
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.material.textfield.TextInputEditText
|
||||
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.UserAvatarPreference
|
||||
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.configuration.VectorConfiguration
|
||||
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.themes.ThemeUtils
|
||||
import im.vector.riotredesign.features.version.getVersion
|
||||
import org.koin.android.ext.android.inject
|
||||
import timber.log.Timber
|
||||
import java.lang.ref.WeakReference
|
||||
import java.text.DateFormat
|
||||
|
@ -314,7 +334,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||
// It does not work on XML, do it here
|
||||
it.icon = activity?.let {
|
||||
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
|
||||
|
@ -331,7 +351,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||
// It does not work on XML, do it here
|
||||
it.icon = activity?.let {
|
||||
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 {
|
||||
|
@ -713,7 +733,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||
context?.let { context: Context ->
|
||||
AlertDialog.Builder(context)
|
||||
.setSingleChoiceItems(R.array.media_saving_choice,
|
||||
PreferencesManager.getSelectedMediasSavingPeriod(activity)) { d, n ->
|
||||
PreferencesManager.getSelectedMediasSavingPeriod(activity)) { d, n ->
|
||||
PreferencesManager.setSelectedMediasSavingPeriod(activity, n)
|
||||
d.cancel()
|
||||
|
||||
|
@ -1773,7 +1793,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||
mDisplayedEmails = newEmailsList
|
||||
|
||||
val addEmailBtn = mUserSettingsCategory.findPreference(ADD_EMAIL_PREFERENCE_KEY)
|
||||
?: return
|
||||
?: return
|
||||
|
||||
var order = addEmailBtn.order
|
||||
|
||||
|
@ -2449,7 +2469,9 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||
|
||||
// disable the deletion for our own device
|
||||
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)
|
||||
.setOnKeyListener(DialogInterface.OnKeyListener { dialog, keyCode, event ->
|
||||
|
@ -2746,8 +2768,8 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||
|
||||
AlertDialog.Builder(thisActivity)
|
||||
.setMessage(getString(R.string.encryption_import_room_keys_success,
|
||||
data.successfullyNumberOfImportedKeys,
|
||||
data.totalNumberOfKeys))
|
||||
data.successfullyNumberOfImportedKeys,
|
||||
data.totalNumberOfKeys))
|
||||
.setPositiveButton(R.string.ok) { dialog, _ -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
|
|
|
@ -29,14 +29,15 @@ import im.vector.riotredesign.core.platform.VectorBaseFragment
|
|||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.core.ui.list.genericFooterItem
|
||||
import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*
|
||||
import javax.inject.Inject
|
||||
|
||||
// Referenced in vector_settings_notifications.xml
|
||||
class PushGatewaysFragment : VectorBaseFragment() {
|
||||
|
||||
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 epoxyController by lazy { PushGateWayController(StringProvider(requireContext().resources)) }
|
||||
|
||||
override fun onResume() {
|
||||
|
|
|
@ -16,38 +16,50 @@
|
|||
|
||||
package im.vector.riotredesign.features.settings.push
|
||||
|
||||
import androidx.lifecycle.Observer
|
||||
import com.airbnb.mvrx.*
|
||||
import com.airbnb.mvrx.Async
|
||||
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.pushers.Pusher
|
||||
import im.vector.matrix.rx.RxSession
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import org.koin.android.ext.android.get
|
||||
|
||||
|
||||
data class PushGatewayViewState(
|
||||
val pushGateways: Async<List<Pusher>> = Uninitialized
|
||||
) : 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> {
|
||||
|
||||
override fun create(viewModelContext: ViewModelContext, state: PushGatewayViewState): PushGatewaysViewModel? {
|
||||
val session = viewModelContext.activity.get<Session>()
|
||||
val fragment = (viewModelContext as FragmentViewModelContext).fragment
|
||||
|
||||
val livePushers = session.livePushers()
|
||||
|
||||
val viewModel = PushGatewaysViewModel(state)
|
||||
|
||||
livePushers.observe(fragment, Observer {
|
||||
viewModel.setState {
|
||||
PushGatewayViewState(Success(it))
|
||||
}
|
||||
})
|
||||
return viewModel
|
||||
val fragment: PushGatewaysFragment = (viewModelContext as FragmentViewModelContext).fragment()
|
||||
return fragment.pushGatewaysViewModelFactory.create(state)
|
||||
}
|
||||
}
|
||||
|
||||
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.ViewModelContext
|
||||
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 org.koin.android.ext.android.get
|
||||
|
||||
data class PushRulesViewState(
|
||||
val rules: List<PushRule> = emptyList()
|
||||
) : MvRxState
|
||||
|
||||
|
||||
class PushRulesViewModel(initialState: PushRulesViewState) : VectorViewModel<PushRulesViewState>(initialState) {
|
||||
|
||||
companion object : MvRxViewModelFactory<PushRulesViewModel, 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()
|
||||
|
||||
return PushRulesViewState(rules)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue