diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt index 8284b50332..3832bc5af4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/PushersService.kt @@ -71,12 +71,14 @@ interface PushersService { * @param url the Sygnal url (full path) * @param appId the application id * @param pushkey the FCM token - * @param callback callback to know if Sygnal has accepted the request. In this case, the app should receive a Push with the provided data (TODO) - * + * @param eventId the eventId which will be sent in the Push message. Use a fake eventId. + * @param callback callback to know if Sygnal has accepted the request. In this case, the app should receive a Push with the provided eventId. + * In case of error, PusherRejected failure can happen. In this case it means that the pushkey is not valid. */ fun testPush(url: String, appId: String, pushkey: String, + eventId: String, callback: MatrixCallback) /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/SygnalFailure.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/SygnalFailure.kt new file mode 100644 index 0000000000..ebedba9d92 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/pushers/SygnalFailure.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.session.pushers + +import org.matrix.android.sdk.api.failure.Failure + +sealed class SygnalFailure : Failure.FeatureFailure() { + object PusherRejected : SygnalFailure() +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt index c7d5e1f8b8..02f147f815 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/DefaultPushersService.kt @@ -50,9 +50,10 @@ internal class DefaultPushersService @Inject constructor( override fun testPush(url: String, appId: String, pushkey: String, + eventId: String, callback: MatrixCallback) { sygnalNotifyTask - .configureWith(SygnalNotifyTask.Params(url, appId, pushkey)) { + .configureWith(SygnalNotifyTask.Params(url, appId, pushkey, eventId)) { this.callback = callback } .executeBy(taskExecutor) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotification.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotification.kt index b28449a481..a2c016feb8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotification.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotification.kt @@ -21,6 +21,9 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) internal data class SygnalNotification( + @Json(name = "event_id") + val eventId: String, + /** * Required. This is an array of devices that the notification should be sent to. */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyTask.kt index eb3cd433a9..663d0cd3c2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyTask.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.session.pushers.sygnal import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.session.pushers.SygnalFailure import org.matrix.android.sdk.internal.di.Unauthenticated import org.matrix.android.sdk.internal.network.NetworkConstants import org.matrix.android.sdk.internal.network.RetrofitFactory @@ -27,7 +28,8 @@ internal interface SygnalNotifyTask : Task { data class Params( val url: String, val appId: String, - val pushKey: String + val pushKey: String, + val eventId: String ) } @@ -47,6 +49,7 @@ internal class DefaultSygnalNotifyTask @Inject constructor( apiCall = sygnalApi.notify( SygnalNotifyBody( SygnalNotification( + eventId = params.eventId, devices = listOf( SygnalDevice( params.appId, @@ -59,7 +62,7 @@ internal class DefaultSygnalNotifyTask @Inject constructor( } if (response.rejectedPushKey.contains(params.pushKey)) { - throw IllegalStateException("Failure") + throw SygnalFailure.PusherRejected } } } diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromSygnal.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromSygnal.kt index b291b750b4..105c54c64f 100644 --- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromSygnal.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromSygnal.kt @@ -17,11 +17,13 @@ package im.vector.app.gplay.features.settings.troubleshoot import androidx.appcompat.app.AppCompatActivity import im.vector.app.R +import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.pushers.PushersManager import im.vector.app.core.resources.StringProvider import im.vector.app.features.settings.troubleshoot.TroubleshootTest import im.vector.app.push.fcm.FcmHelper import org.matrix.android.sdk.api.MatrixCallback +import org.matrix.android.sdk.api.session.pushers.SygnalFailure import javax.inject.Inject /** @@ -29,6 +31,7 @@ import javax.inject.Inject */ class TestPushFromSygnal @Inject constructor(private val context: AppCompatActivity, private val stringProvider: StringProvider, + private val errorFormatter: ErrorFormatter, private val pushersManager: PushersManager) : TroubleshootTest(R.string.settings_troubleshoot_test_push_loop_title) { @@ -39,7 +42,11 @@ class TestPushFromSygnal @Inject constructor(private val context: AppCompatActiv } pushersManager.testPush(fcmToken, object : MatrixCallback { override fun onFailure(failure: Throwable) { - description = stringProvider.getString(R.string.settings_troubleshoot_test_push_loop_failed) + description = if (failure is SygnalFailure.PusherRejected) { + stringProvider.getString(R.string.settings_troubleshoot_test_push_loop_failed) + } else { + errorFormatter.toHumanReadable(failure) + } status = TestStatus.FAILED } diff --git a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt index ba58ef6677..801b85ce0c 100755 --- a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt @@ -75,6 +75,13 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { * @param message the message */ override fun onMessageReceived(message: RemoteMessage) { + // Diagnostic Push + if (message.data["event_id"] == PushersManager.TEST_EVENT_ID) { + // Display the notification right now + notificationDrawerManager.displayDiagnosticNotification() + return + } + if (!vectorPreferences.areNotificationEnabledForDevice()) { Timber.i("Notification are disabled for this device") return diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt index e86ff104b7..cfdc61a045 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt @@ -41,6 +41,7 @@ class PushersManager @Inject constructor( stringProvider.getString(R.string.pusher_http_url), stringProvider.getString(R.string.pusher_app_id), pushKey, + TEST_EVENT_ID, callback ) } @@ -66,4 +67,8 @@ class PushersManager @Inject constructor( val currentSession = activeSessionHolder.getSafeActiveSession() ?: return currentSession.removeHttpPusher(pushKey, stringProvider.getString(R.string.pusher_app_id), callback) } + + companion object { + const val TEST_EVENT_ID = "\$THIS_IS_A_FAKE_EVENT_ID" + } } diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt index 26f00fcef9..7147968d49 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationDrawerManager.kt @@ -590,6 +590,10 @@ class NotificationDrawerManager @Inject constructor(private val context: Context } } + fun displayDiagnosticNotification() { + notificationUtils.displayDiagnosticNotification() + } + companion object { private const val SUMMARY_NOTIFICATION_ID = 0 private const val ROOM_MESSAGES_NOTIFICATION_ID = 1 diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 9d89168bb8..7e7fd60b59 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -27,8 +27,10 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import android.graphics.Bitmap +import android.graphics.Canvas import android.net.Uri import android.os.Build +import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat @@ -36,6 +38,7 @@ import androidx.core.app.RemoteInput import androidx.core.app.TaskStackBuilder import androidx.core.content.ContextCompat import androidx.core.content.getSystemService +import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.IconCompat import androidx.fragment.app.Fragment import im.vector.app.BuildConfig @@ -47,7 +50,6 @@ import im.vector.app.features.call.service.CallHeadsUpActionReceiver import im.vector.app.features.home.HomeActivity import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.RoomDetailArgs -import im.vector.app.features.pin.PinLocker import im.vector.app.features.settings.VectorPreferences import timber.log.Timber import javax.inject.Inject @@ -61,7 +63,6 @@ import kotlin.random.Random @Singleton class NotificationUtils @Inject constructor(private val context: Context, private val stringProvider: StringProvider, - private val pinLocker: PinLocker, private val vectorPreferences: VectorPreferences) { companion object { @@ -845,6 +846,33 @@ class NotificationUtils @Inject constructor(private val context: Context, } } + fun displayDiagnosticNotification() { + notificationManager.notify( + "DIAGNOSTIC", + 888, + NotificationCompat.Builder(context, NOISY_NOTIFICATION_CHANNEL_ID) + .setContentTitle(stringProvider.getString(R.string.app_name)) + .setContentText(stringProvider.getString(R.string.settings_troubleshoot_test_push_notification_content)) + .setSmallIcon(R.drawable.ic_status_bar) + .setLargeIcon(getBitmap(context, R.drawable.element_logo_green)) + .setColor(ContextCompat.getColor(context, R.color.notification_accent_color)) + .setPriority(NotificationCompat.PRIORITY_MAX) + .setCategory(NotificationCompat.CATEGORY_STATUS) + .setAutoCancel(true) + .build() + ) + } + + private fun getBitmap(context: Context, @DrawableRes drawableRes: Int): Bitmap? { + val drawable = ResourcesCompat.getDrawable(context.resources, drawableRes, null) ?: return null + val canvas = Canvas() + val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888) + canvas.setBitmap(bitmap) + drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight) + drawable.draw(canvas) + return bitmap + } + /** * Return true it the user has enabled the do not disturb mode */ diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index be83a6dc50..d5e590375c 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -752,6 +752,7 @@ Test Push The application is receiving PUSH, you should see a notification. Failed to receive push. Solution could be to reinstall the application. + You are receiving PUSH! Notifications Service Notifications Service is running.