diff --git a/.idea/dictionaries/bmarty.xml b/.idea/dictionaries/bmarty.xml index 5c27da044e..d13e40248f 100644 --- a/.idea/dictionaries/bmarty.xml +++ b/.idea/dictionaries/bmarty.xml @@ -29,6 +29,7 @@ signout signup ssss + sygnal threepid unwedging diff --git a/CHANGES.md b/CHANGES.md index 05d189ed12..e365768f86 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,7 @@ Improvements 🙌: - Drawer: move settings access and add sign out action (#2171) - Filter room member (and banned users) by name (#2184) - Implement "Jump to read receipt" and "Mention" actions on the room member profile screen + - Add Sygnal API implementation to test is Push are correctly received Bugfix 🐛: - Improve support for image/audio/video/file selection with intent changes (#1376) 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 0e33be400c..8284b50332 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 @@ -66,6 +66,19 @@ interface PushersService { append: Boolean, withEventIdOnly: Boolean): UUID + /** + * Directly ask Sygnal to send a push to this device + * @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) + * + */ + fun testPush(url: String, + appId: String, + pushkey: String, + callback: MatrixCallback) + /** * Remove the http pusher */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConstants.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConstants.kt index 1154d1967c..0dfdec1804 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConstants.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/NetworkConstants.kt @@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.network internal object NetworkConstants { - + // Homeserver private const val URI_API_PREFIX_PATH = "_matrix/client" const val URI_API_PREFIX_PATH_ = "$URI_API_PREFIX_PATH/" const val URI_API_PREFIX_PATH_R0 = "$URI_API_PREFIX_PATH/r0/" @@ -31,5 +31,9 @@ internal object NetworkConstants { const val URI_IDENTITY_PREFIX_PATH = "_matrix/identity/v2" const val URI_IDENTITY_PATH_V2 = "$URI_IDENTITY_PREFIX_PATH/" + // Sygnal + const val URI_SYGNAL_PREFIX_PATH = "_matrix/push/v1/" + + // Integration const val URI_INTEGRATION_MANAGER_PATH = "_matrix/integrations/v1/" } 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 8f80ac46e4..c7d5e1f8b8 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 @@ -28,6 +28,7 @@ import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.WorkManagerProvider +import org.matrix.android.sdk.internal.session.pushers.sygnal.SygnalNotifyTask import org.matrix.android.sdk.internal.task.TaskExecutor import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.worker.WorkerParamsFactory @@ -41,10 +42,22 @@ internal class DefaultPushersService @Inject constructor( @SessionDatabase private val monarchy: Monarchy, @SessionId private val sessionId: String, private val getPusherTask: GetPushersTask, + private val sygnalNotifyTask: SygnalNotifyTask, private val removePusherTask: RemovePusherTask, private val taskExecutor: TaskExecutor ) : PushersService { + override fun testPush(url: String, + appId: String, + pushkey: String, + callback: MatrixCallback) { + sygnalNotifyTask + .configureWith(SygnalNotifyTask.Params(url, appId, pushkey)) { + this.callback = callback + } + .executeBy(taskExecutor) + } + override fun refreshPushers() { getPusherTask .configureWith() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushersModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushersModule.kt index a6042b27a2..5810f26c85 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushersModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/PushersModule.kt @@ -25,6 +25,8 @@ import org.matrix.android.sdk.api.session.pushers.PushersService import org.matrix.android.sdk.internal.session.notification.DefaultProcessEventForPushTask import org.matrix.android.sdk.internal.session.notification.DefaultPushRuleService import org.matrix.android.sdk.internal.session.notification.ProcessEventForPushTask +import org.matrix.android.sdk.internal.session.pushers.sygnal.DefaultSygnalNotifyTask +import org.matrix.android.sdk.internal.session.pushers.sygnal.SygnalNotifyTask import org.matrix.android.sdk.internal.session.room.notification.DefaultSetRoomNotificationStateTask import org.matrix.android.sdk.internal.session.room.notification.SetRoomNotificationStateTask import retrofit2.Retrofit @@ -86,4 +88,7 @@ internal abstract class PushersModule { @Binds abstract fun bindProcessEventForPushTask(task: DefaultProcessEventForPushTask): ProcessEventForPushTask + + @Binds + abstract fun bindSygnalNotifyTask(task: DefaultSygnalNotifyTask): SygnalNotifyTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalAPI.kt new file mode 100644 index 0000000000..7550e14a97 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalAPI.kt @@ -0,0 +1,32 @@ +/* + * 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.internal.session.pushers.sygnal + +import org.matrix.android.sdk.internal.network.NetworkConstants +import retrofit2.Call +import retrofit2.http.Body +import retrofit2.http.POST + +internal interface SygnalAPI { + /** + * Ask Sygnal to send a push to the current device. + * + * Ref: https://matrix.org/docs/spec/push_gateway/r0.1.1#post-matrix-push-v1-notify + */ + @POST(NetworkConstants.URI_SYGNAL_PREFIX_PATH + "notify") + fun notify(@Body body: SygnalNotifyBody): Call +} + diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalDevice.kt new file mode 100644 index 0000000000..a5cfe389cc --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalDevice.kt @@ -0,0 +1,34 @@ +/* + * 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.internal.session.pushers.sygnal + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class SygnalDevice( + /** + * Required. The app_id given when the pusher was created. + */ + @Json(name = "app_id") + val appId: String, + /** + * Required. The pushkey given when the pusher was created. + */ + @Json(name = "pushkey") + val pushKey: String +) 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 new file mode 100644 index 0000000000..b28449a481 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotification.kt @@ -0,0 +1,29 @@ +/* + * 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.internal.session.pushers.sygnal + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class SygnalNotification( + /** + * Required. This is an array of devices that the notification should be sent to. + */ + @Json(name = "devices") + val devices: List +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyBody.kt new file mode 100644 index 0000000000..7b13d8ff79 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyBody.kt @@ -0,0 +1,29 @@ +/* + * 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.internal.session.pushers.sygnal + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class SygnalNotifyBody( + /** + * Required. Information about the push notification + */ + @Json(name = "notification") + val notification: SygnalNotification +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyResponse.kt new file mode 100644 index 0000000000..73d5aa1e2c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyResponse.kt @@ -0,0 +1,26 @@ +/* + * 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.internal.session.pushers.sygnal + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class SygnalNotifyResponse( + @Json(name = "rejected") + val rejectedPushKey: List +) 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 new file mode 100644 index 0000000000..eb3cd433a9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushers/sygnal/SygnalNotifyTask.kt @@ -0,0 +1,65 @@ +/* + * 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.internal.session.pushers.sygnal + +import okhttp3.OkHttpClient +import org.matrix.android.sdk.internal.di.Unauthenticated +import org.matrix.android.sdk.internal.network.NetworkConstants +import org.matrix.android.sdk.internal.network.RetrofitFactory +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal interface SygnalNotifyTask : Task { + data class Params( + val url: String, + val appId: String, + val pushKey: String + ) +} + +internal class DefaultSygnalNotifyTask @Inject constructor( + private val retrofitFactory: RetrofitFactory, + @Unauthenticated private val unauthenticatedOkHttpClient: OkHttpClient +) : SygnalNotifyTask { + + override suspend fun execute(params: SygnalNotifyTask.Params) { + val sygnalApi = retrofitFactory.create( + unauthenticatedOkHttpClient, + params.url.substringBefore(NetworkConstants.URI_SYGNAL_PREFIX_PATH) + ) + .create(SygnalAPI::class.java) + + val response = executeRequest(null) { + apiCall = sygnalApi.notify( + SygnalNotifyBody( + SygnalNotification( + devices = listOf( + SygnalDevice( + params.appId, + params.pushKey + ) + ) + ) + ) + ) + } + + if (response.rejectedPushKey.contains(params.pushKey)) { + throw IllegalStateException("Failure") + } + } +} 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 new file mode 100644 index 0000000000..b291b750b4 --- /dev/null +++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromSygnal.kt @@ -0,0 +1,52 @@ +/* + * Copyright 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 im.vector.app.gplay.features.settings.troubleshoot + +import androidx.appcompat.app.AppCompatActivity +import im.vector.app.R +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 javax.inject.Inject + +/** + * Test Push by asking Sygnal to send a Push back + */ +class TestPushFromSygnal @Inject constructor(private val context: AppCompatActivity, + private val stringProvider: StringProvider, + private val pushersManager: PushersManager) + : TroubleshootTest(R.string.settings_troubleshoot_test_push_loop_title) { + + override fun perform() { + val fcmToken = FcmHelper.getFcmToken(context) ?: run { + status = TestStatus.FAILED + return + } + pushersManager.testPush(fcmToken, object : MatrixCallback { + override fun onFailure(failure: Throwable) { + description = stringProvider.getString(R.string.settings_troubleshoot_test_push_loop_failed) + status = TestStatus.FAILED + } + + override fun onSuccess(data: Unit) { + description = stringProvider.getString(R.string.settings_troubleshoot_test_push_loop_success) + status = TestStatus.SUCCESS + } + }) + } +} diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt index b2dad09483..06d3283afa 100644 --- a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -23,16 +23,20 @@ import im.vector.app.features.settings.troubleshoot.TestPushRulesSettings import im.vector.app.features.settings.troubleshoot.TestSystemSettings import im.vector.app.gplay.features.settings.troubleshoot.TestFirebaseToken import im.vector.app.gplay.features.settings.troubleshoot.TestPlayServices +import im.vector.app.gplay.features.settings.troubleshoot.TestPushFromSygnal import im.vector.app.gplay.features.settings.troubleshoot.TestTokenRegistration import javax.inject.Inject -class NotificationTroubleshootTestManagerFactory @Inject constructor(private val testSystemSettings: TestSystemSettings, - private val testAccountSettings: TestAccountSettings, - private val testDeviceSettings: TestDeviceSettings, - private val testBingRulesSettings: TestPushRulesSettings, - private val testPlayServices: TestPlayServices, - private val testFirebaseToken: TestFirebaseToken, - private val testTokenRegistration: TestTokenRegistration) { +class NotificationTroubleshootTestManagerFactory @Inject constructor( + private val testSystemSettings: TestSystemSettings, + private val testAccountSettings: TestAccountSettings, + private val testDeviceSettings: TestDeviceSettings, + private val testBingRulesSettings: TestPushRulesSettings, + private val testPlayServices: TestPlayServices, + private val testFirebaseToken: TestFirebaseToken, + private val testTokenRegistration: TestTokenRegistration, + private val testPushFromSygnal: TestPushFromSygnal +) { fun create(fragment: Fragment): NotificationTroubleshootTestManager { val mgr = NotificationTroubleshootTestManager(fragment) @@ -43,6 +47,7 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(private val mgr.addTest(testPlayServices) mgr.addTest(testFirebaseToken) mgr.addTest(testTokenRegistration) + mgr.addTest(testPushFromSygnal) return mgr } } 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 f0d27182e7..e86ff104b7 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 @@ -34,6 +34,16 @@ class PushersManager @Inject constructor( private val stringProvider: StringProvider, private val appNameProvider: AppNameProvider ) { + fun testPush(pushKey: String, callback: MatrixCallback) { + val currentSession = activeSessionHolder.getActiveSession() + + currentSession.testPush( + stringProvider.getString(R.string.pusher_http_url), + stringProvider.getString(R.string.pusher_app_id), + pushKey, + callback + ) + } fun registerPusherWithFcmKey(pushKey: String): UUID { val currentSession = activeSessionHolder.getActiveSession() diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index d48162de29..be83a6dc50 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -749,6 +749,10 @@ FCM token successfully registered to HomeServer. Failed to register FCM token to HomeServer:\n%1$s + Test Push + The application is receiving PUSH, you should see a notification. + Failed to receive push. Solution could be to reinstall the application. + Notifications Service Notifications Service is running. Notifications Service is not running.\nTry to restart the application.