Notification: open room and clear drawer - Smart reply - Mark as read - dismiss all

This commit is contained in:
Benoit Marty 2019-06-25 15:39:51 +02:00 committed by Benoit Marty
parent 328f090723
commit 785f33177d
6 changed files with 97 additions and 59 deletions

View File

@ -63,6 +63,8 @@
<activity android:name=".features.home.room.detail.RoomDetailActivity" /> <activity android:name=".features.home.room.detail.RoomDetailActivity" />
<activity android:name=".features.debug.DebugMenuActivity" /> <activity android:name=".features.debug.DebugMenuActivity" />


<!-- Services -->

<service <service
android:name=".core.services.CallService" android:name=".core.services.CallService"
android:exported="false" /> android:exported="false" />
@ -76,6 +78,16 @@


</service> </service>


<!-- Receivers -->

<!-- Exported false, should only be accessible from this app!! -->
<receiver
android:name=".features.notifications.NotificationBroadcastReceiver"
android:enabled="true"
android:exported="false" />

<!-- Providers -->

<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider" android:authorities="${applicationId}.fileProvider"

View File

@ -37,19 +37,19 @@ import im.vector.riotredesign.core.extensions.replaceFragment
import im.vector.riotredesign.core.platform.OnBackPressed import im.vector.riotredesign.core.platform.OnBackPressed
import im.vector.riotredesign.core.platform.ToolbarConfigurable import im.vector.riotredesign.core.platform.ToolbarConfigurable
import im.vector.riotredesign.core.platform.VectorBaseActivity import im.vector.riotredesign.core.platform.VectorBaseActivity
import im.vector.riotredesign.core.pushers.PushersManager
import im.vector.riotredesign.features.crypto.keysrequest.KeyRequestHandler import im.vector.riotredesign.features.crypto.keysrequest.KeyRequestHandler
import im.vector.riotredesign.features.crypto.verification.IncomingVerificationRequestHandler import im.vector.riotredesign.features.crypto.verification.IncomingVerificationRequestHandler
import im.vector.riotredesign.core.pushers.PushersManager import im.vector.riotredesign.features.notifications.NotificationDrawerManager
import im.vector.riotredesign.features.rageshake.BugReporter import im.vector.riotredesign.features.rageshake.BugReporter
import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.riotredesign.features.workers.signout.SignOutUiWorker import im.vector.riotredesign.features.workers.signout.SignOutUiWorker
import im.vector.riotredesign.features.workers.signout.SignOutViewModel
import im.vector.riotredesign.push.fcm.FcmHelper import im.vector.riotredesign.push.fcm.FcmHelper
import kotlinx.android.synthetic.main.activity_home.* import kotlinx.android.synthetic.main.activity_home.*
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import org.koin.android.scope.ext.android.bindScope import org.koin.android.scope.ext.android.bindScope
import org.koin.android.scope.ext.android.getOrCreateScope import org.koin.android.scope.ext.android.getOrCreateScope
import im.vector.riotredesign.features.workers.signout.SignOutViewModel





class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
@ -64,6 +64,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
private val homeNavigator by inject<HomeNavigator>() private val homeNavigator by inject<HomeNavigator>()
private val pushManager by inject<PushersManager>() private val pushManager by inject<PushersManager>()


private val notificationDrawerManager by inject<NotificationDrawerManager>()

// TODO Move this elsewhere // TODO Move this elsewhere
private val incomingVerificationRequestHandler by inject<IncomingVerificationRequestHandler>() private val incomingVerificationRequestHandler by inject<IncomingVerificationRequestHandler>()
// TODO Move this elsewhere // TODO Move this elsewhere
@ -115,6 +117,20 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {


incomingVerificationRequestHandler.ensureStarted() incomingVerificationRequestHandler.ensureStarted()
keyRequestHandler.ensureStarted() keyRequestHandler.ensureStarted()

if (intent.hasExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION)) {
notificationDrawerManager.clearAllEvents()
intent.removeExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION)
}
}

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)

if (intent?.hasExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION) == true) {
notificationDrawerManager.clearAllEvents()
intent.removeExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION)
}
} }


override fun onDestroy() { override fun onDestroy() {
@ -189,10 +205,14 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {




companion object { companion object {
fun newIntent(context: Context): Intent { private const val EXTRA_CLEAR_EXISTING_NOTIFICATION = "EXTRA_CLEAR_EXISTING_NOTIFICATION"
return Intent(context, HomeActivity::class.java)
}


fun newIntent(context: Context, clearNotification: Boolean = false): Intent {
return Intent(context, HomeActivity::class.java)
.apply {
putExtra(EXTRA_CLEAR_EXISTING_NOTIFICATION, clearNotification)
}
}
} }


} }

View File

@ -43,7 +43,6 @@ import butterknife.BindView
import com.airbnb.epoxy.EpoxyVisibilityTracker import com.airbnb.epoxy.EpoxyVisibilityTracker
import com.airbnb.mvrx.args import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import com.github.piasy.biv.BigImageViewer import com.github.piasy.biv.BigImageViewer
import com.github.piasy.biv.loader.ImageLoader import com.github.piasy.biv.loader.ImageLoader
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@ -92,6 +91,7 @@ import im.vector.riotredesign.features.media.ImageContentRenderer
import im.vector.riotredesign.features.media.ImageMediaViewerActivity import im.vector.riotredesign.features.media.ImageMediaViewerActivity
import im.vector.riotredesign.features.media.VideoContentRenderer import im.vector.riotredesign.features.media.VideoContentRenderer
import im.vector.riotredesign.features.media.VideoMediaViewerActivity import im.vector.riotredesign.features.media.VideoMediaViewerActivity
import im.vector.riotredesign.features.notifications.NotificationDrawerManager
import im.vector.riotredesign.features.reactions.EmojiReactionPickerActivity import im.vector.riotredesign.features.reactions.EmojiReactionPickerActivity
import im.vector.riotredesign.features.settings.PreferencesManager import im.vector.riotredesign.features.settings.PreferencesManager
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
@ -168,6 +168,8 @@ class RoomDetailFragment :
private val autocompleteUserPresenter: AutocompleteUserPresenter by inject { parametersOf(this) } private val autocompleteUserPresenter: AutocompleteUserPresenter by inject { parametersOf(this) }
private val permalinkHandler: PermalinkHandler by inject() private val permalinkHandler: PermalinkHandler by inject()


private val notificationDrawerManager by inject<NotificationDrawerManager>()

private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
private lateinit var scrollOnHighlightedEventCallback: ScrollOnHighlightedEventCallback private lateinit var scrollOnHighlightedEventCallback: ScrollOnHighlightedEventCallback


@ -277,6 +279,18 @@ class RoomDetailFragment :
} }
} }


override fun onResume() {
super.onResume()

notificationDrawerManager.setCurrentRoom(roomDetailArgs.roomId)
}

override fun onPause() {
super.onPause()

notificationDrawerManager.setCurrentRoom(null)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && data != null) { if (resultCode == RESULT_OK && data != null) {

View File

@ -20,11 +20,15 @@ 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.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 org.koin.standalone.KoinComponent import org.koin.standalone.KoinComponent
import org.koin.standalone.inject import org.koin.standalone.inject
import timber.log.Timber import timber.log.Timber
import java.util.*


/** /**
* Receives actions broadcast by notification (on click, on dismiss, inline replies, etc.) * Receives actions broadcast by notification (on click, on dismiss, inline replies, etc.)
@ -39,15 +43,15 @@ class NotificationBroadcastReceiver : BroadcastReceiver(), KoinComponent {
Timber.v("ReplyNotificationBroadcastReceiver received : $intent") Timber.v("ReplyNotificationBroadcastReceiver received : $intent")


when (intent.action) { when (intent.action) {
NotificationUtils.SMART_REPLY_ACTION -> NotificationUtils.SMART_REPLY_ACTION ->
handleSmartReply(intent, context) handleSmartReply(intent, context)
NotificationUtils.DISMISS_ROOM_NOTIF_ACTION -> NotificationUtils.DISMISS_ROOM_NOTIF_ACTION ->
intent.getStringExtra(KEY_ROOM_ID)?.let { intent.getStringExtra(KEY_ROOM_ID)?.let {
notificationDrawerManager.clearMessageEventOfRoom(it) notificationDrawerManager.clearMessageEventOfRoom(it)
} }
NotificationUtils.DISMISS_SUMMARY_ACTION -> NotificationUtils.DISMISS_SUMMARY_ACTION ->
notificationDrawerManager.clearAllEvents() notificationDrawerManager.clearAllEvents()
NotificationUtils.MARK_ROOM_READ_ACTION -> NotificationUtils.MARK_ROOM_READ_ACTION ->
intent.getStringExtra(KEY_ROOM_ID)?.let { intent.getStringExtra(KEY_ROOM_ID)?.let {
notificationDrawerManager.clearMessageEventOfRoom(it) notificationDrawerManager.clearMessageEventOfRoom(it)
handleMarkAsRead(context, it) handleMarkAsRead(context, it)
@ -56,67 +60,59 @@ class NotificationBroadcastReceiver : BroadcastReceiver(), KoinComponent {
} }


private fun handleMarkAsRead(context: Context, roomId: String) { private fun handleMarkAsRead(context: Context, roomId: String) {
/* Matrix.getInstance().currentSession?.let { session ->
TODO session.getRoom(roomId)
Matrix.getInstance(context)?.defaultSession?.let { session -> ?.markAllAsRead(object : MatrixCallback<Unit> {})
session.dataHandler
?.getRoom(roomId)
?.markAllAsRead(object : SimpleApiCallback<Unit>() {
override fun onSuccess(void: Void?) {
// Ignore
}
})
} }
*/
} }


private fun handleSmartReply(intent: Intent, context: Context) { private fun handleSmartReply(intent: Intent, context: Context) {
/*
TODO
val message = getReplyMessage(intent) val message = getReplyMessage(intent)
val roomId = intent.getStringExtra(KEY_ROOM_ID) val roomId = intent.getStringExtra(KEY_ROOM_ID)


if (TextUtils.isEmpty(message) || TextUtils.isEmpty(roomId)) { if (message.isNullOrBlank() || roomId.isBlank()) {
//ignore this event //ignore this event
//Can this happen? should we update notification? //Can this happen? should we update notification?
return return
} }
val matrixId = intent.getStringExtra(EXTRA_MATRIX_ID) val matrixId = intent.getStringExtra(EXTRA_MATRIX_ID)
Matrix.getInstance(context)?.getSession(matrixId)?.let { session -> Matrix.getInstance().currentSession?.let { session ->
session.dataHandler?.getRoom(roomId)?.let { room -> session.getRoom(roomId)?.let { room ->
sendMatrixEvent(message!!, session, roomId!!, room, context) sendMatrixEvent(message, session, room, context)
} }
} }
*/
} }


private fun sendMatrixEvent(message: String, session: Session, roomId: String, room: Room, context: Context?) { private fun sendMatrixEvent(message: String, session: Session, room: Room, context: Context?) {
/*
TODO


val mxMessage = Message() room.sendTextMessage(message)
mxMessage.msgtype = Message.MSGTYPE_TEXT
mxMessage.body = message // Create a new event to be displayed in the notification drawer, right now

val notifiableMessageEvent = NotifiableMessageEvent(
Random().nextInt().toString(),// TODO event.eventId,
false,
System.currentTimeMillis(),
session.getUser(session.sessionParams.credentials.userId)?.displayName
?: context?.getString(R.string.notification_sender_me),
session.sessionParams.credentials.userId,
message,
room.roomId,
"Room name", // TODO room.getRoomDisplayName(context),
false // TODO room.isDirect
)
notifiableMessageEvent.outGoingMessage = true

notificationDrawerManager.onNotifiableEventReceived(notifiableMessageEvent)
notificationDrawerManager.refreshNotificationDrawer()

/*


val event = Event(mxMessage, session.credentials.userId, roomId) val event = Event(mxMessage, session.credentials.userId, roomId)
room.storeOutgoingEvent(event) room.storeOutgoingEvent(event)
room.sendEvent(event, object : MatrixCallback<Void?> { room.sendEvent(event, object : MatrixCallback<Void?> {
override fun onSuccess(info: Void?) { override fun onSuccess(info: Void?) {
Timber.v("Send message : onSuccess ") Timber.v("Send message : onSuccess ")
val notifiableMessageEvent = NotifiableMessageEvent(
event.eventId,
false,
System.currentTimeMillis(),
session.myUser?.displayname
?: context?.getString(R.string.notification_sender_me),
session.myUserId,
message,
roomId,
room.getRoomDisplayName(context),
room.isDirect)
notifiableMessageEvent.outGoingMessage = true
VectorApp.getInstance().notificationDrawerManager.onNotifiableEventReceived(notifiableMessageEvent)
VectorApp.getInstance().notificationDrawerManager.refreshNotificationDrawer(null)
} }


override fun onNetworkError(e: Exception) { override fun onNetworkError(e: Exception) {

View File

@ -127,8 +127,8 @@ class NotificationDrawerManager(val context: Context,
} }


/** /**
Should be called when the application is currently opened and showing timeline for the given roomId. * Should be called when the application is currently opened and showing timeline for the given roomId.
Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room. * Used to ignore events related to that room (no need to display notification) and clean any existing notification on this room.
*/ */
fun setCurrentRoom(roomId: String?) { fun setCurrentRoom(roomId: String?) {
var hasChanged: Boolean var hasChanged: Boolean

View File

@ -39,6 +39,8 @@ import im.vector.riotredesign.BuildConfig
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.utils.startNotificationChannelSettingsIntent import im.vector.riotredesign.core.utils.startNotificationChannelSettingsIntent
import im.vector.riotredesign.features.home.HomeActivity import im.vector.riotredesign.features.home.HomeActivity
import im.vector.riotredesign.features.home.room.detail.RoomDetailActivity
import im.vector.riotredesign.features.home.room.detail.RoomDetailArgs
import im.vector.riotredesign.features.settings.PreferencesManager import im.vector.riotredesign.features.settings.PreferencesManager
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -545,27 +547,21 @@ object NotificationUtils {
} }


private fun buildOpenRoomIntent(context: Context, roomId: String): PendingIntent? { private fun buildOpenRoomIntent(context: Context, roomId: String): PendingIntent? {
// TODO val roomIntentTap = RoomDetailActivity.newIntent(context, RoomDetailArgs(roomId))
return null
/*
val roomIntentTap = Intent(context, VectorRoomActivity::class.java)
roomIntentTap.putExtra(VectorRoomActivity.EXTRA_ROOM_ID, roomId)
roomIntentTap.action = TAP_TO_VIEW_ACTION roomIntentTap.action = TAP_TO_VIEW_ACTION
//pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that //pending intent get reused by system, this will mess up the extra params, so put unique info to avoid that
roomIntentTap.data = Uri.parse("foobar://openRoom?$roomId") roomIntentTap.data = Uri.parse("foobar://openRoom?$roomId")


// Recreate the back stack // Recreate the back stack
return TaskStackBuilder.create(context) return TaskStackBuilder.create(context)
.addNextIntentWithParentStack(Intent(context, VectorHomeActivity::class.java)) .addNextIntentWithParentStack(Intent(context, HomeActivity::class.java))
.addNextIntent(roomIntentTap) .addNextIntent(roomIntentTap)
.getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT) .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT)
*/
} }


private fun buildOpenHomePendingIntentForSummary(context: Context): PendingIntent { private fun buildOpenHomePendingIntentForSummary(context: Context): PendingIntent {
val intent = Intent(context, HomeActivity::class.java) val intent = HomeActivity.newIntent(context, clearNotification = true)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
// TODO intent.putExtra(VectorHomeActivity.EXTRA_CLEAR_EXISTING_NOTIFICATION, true)
intent.data = Uri.parse("foobar://tapSummary") intent.data = Uri.parse("foobar://tapSummary")
return PendingIntent.getActivity(context, Random().nextInt(1000), intent, PendingIntent.FLAG_UPDATE_CURRENT) return PendingIntent.getActivity(context, Random().nextInt(1000), intent, PendingIntent.FLAG_UPDATE_CURRENT)
} }