From 2dc103f7ee5c04cec9bb171d57279b44d2fcca7b Mon Sep 17 00:00:00 2001 From: NIkita Fedrunov Date: Thu, 22 Dec 2022 14:38:05 +0100 Subject: [PATCH] use clipboard hack to get deferred deeplink --- .../matrix/android/sdk/api/session/Session.kt | 6 +++ .../permalinks/DeferredPermalinkService.kt | 29 ++++++++++++ .../sdk/internal/session/DefaultSession.kt | 4 ++ .../sdk/internal/session/SessionModule.kt | 5 ++ .../DefaultDeferredPermalinkService.kt | 47 +++++++++++++++++++ .../vector/app/features/home/HomeActivity.kt | 12 +++++ .../features/home/HomeActivityViewEvents.kt | 1 + .../features/home/HomeActivityViewModel.kt | 7 +++ 8 files changed, 111 insertions(+) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/DeferredPermalinkService.kt create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultDeferredPermalinkService.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt index 13993149f4e..2d20cd5ebe1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/Session.kt @@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.session.identity.IdentityService import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService import org.matrix.android.sdk.api.session.media.MediaService import org.matrix.android.sdk.api.session.openid.OpenIdService +import org.matrix.android.sdk.api.session.permalinks.DeferredPermalinkService import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.presence.PresenceService import org.matrix.android.sdk.api.session.profile.ProfileService @@ -248,6 +249,11 @@ interface Session { */ fun permalinkService(): PermalinkService + /** + * Returns the deferredPermalinkService service associated with the session. + */ + fun deferredPermalinkService(): DeferredPermalinkService + /** * Returns the search service associated with the session. */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/DeferredPermalinkService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/DeferredPermalinkService.kt new file mode 100644 index 00000000000..9aef373b225 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/DeferredPermalinkService.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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.permalinks + +/** + * Service to handle deferred links, e.g. when user open link to the room but the app is not installed yet + */ +interface DeferredPermalinkService { + + /** + * Checks system clipboard for matrix.to links and returns first room link if any found + * @return first room link in clipboard or null if none is found + */ + fun getLinkFromClipBoard(): String? +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt index 679c5085efc..12c608de068 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultSession.kt @@ -46,6 +46,7 @@ import org.matrix.android.sdk.api.session.identity.IdentityService import org.matrix.android.sdk.api.session.integrationmanager.IntegrationManagerService import org.matrix.android.sdk.api.session.media.MediaService import org.matrix.android.sdk.api.session.openid.OpenIdService +import org.matrix.android.sdk.api.session.permalinks.DeferredPermalinkService import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.presence.PresenceService import org.matrix.android.sdk.api.session.profile.ProfileService @@ -135,6 +136,7 @@ internal class DefaultSession @Inject constructor( @UnauthenticatedWithCertificate private val unauthenticatedWithCertificateOkHttpClient: Lazy, private val sessionState: SessionState, + private val deferredPermalinkService: Lazy, ) : Session, GlobalErrorHandler.Listener { @@ -222,6 +224,8 @@ internal class DefaultSession @Inject constructor( override fun eventStreamService(): EventStreamService = eventStreamService.get() override fun fileService(): FileService = defaultFileService.get() override fun permalinkService(): PermalinkService = permalinkService.get() + override fun deferredPermalinkService(): DeferredPermalinkService = deferredPermalinkService.get() + override fun widgetService(): WidgetService = widgetService.get() override fun mediaService(): MediaService = mediaService.get() override fun integrationManagerService(): IntegrationManagerService = integrationManagerService.get() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt index b9f56cbc9f1..7b7c9faf3d4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/SessionModule.kt @@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.accountdata.SessionAccountDataService import org.matrix.android.sdk.api.session.events.EventService import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService import org.matrix.android.sdk.api.session.openid.OpenIdService +import org.matrix.android.sdk.api.session.permalinks.DeferredPermalinkService import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageService import org.matrix.android.sdk.api.session.typing.TypingUsersTracker @@ -83,6 +84,7 @@ import org.matrix.android.sdk.internal.session.homeserver.DefaultHomeServerCapab import org.matrix.android.sdk.internal.session.identity.DefaultIdentityService import org.matrix.android.sdk.internal.session.integrationmanager.IntegrationManager import org.matrix.android.sdk.internal.session.openid.DefaultOpenIdService +import org.matrix.android.sdk.internal.session.permalinks.DefaultDeferredPermalinkService import org.matrix.android.sdk.internal.session.permalinks.DefaultPermalinkService import org.matrix.android.sdk.internal.session.room.EventRelationsAggregationProcessor import org.matrix.android.sdk.internal.session.room.aggregation.poll.DefaultPollAggregationProcessor @@ -405,4 +407,7 @@ internal abstract class SessionModule { @Binds abstract fun bindPollAggregationProcessor(processor: DefaultPollAggregationProcessor): PollAggregationProcessor + + @Binds + abstract fun bindDeferredPermalinkService(service: DefaultDeferredPermalinkService): DeferredPermalinkService } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultDeferredPermalinkService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultDeferredPermalinkService.kt new file mode 100644 index 00000000000..6c5c716e481 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/permalinks/DefaultDeferredPermalinkService.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * 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.permalinks + +import android.content.ClipboardManager +import android.content.Context +import org.matrix.android.sdk.api.session.permalinks.DeferredPermalinkService +import org.matrix.android.sdk.api.session.permalinks.PermalinkData +import org.matrix.android.sdk.api.session.permalinks.PermalinkParser +import androidx.core.content.getSystemService +import javax.inject.Inject + +class DefaultDeferredPermalinkService @Inject constructor( + private val context: Context +) : DeferredPermalinkService { + + override fun getLinkFromClipBoard(): String? { + val clipboard = context.getSystemService() + clipboard?.primaryClip?.let { clip -> + if (clip.itemCount == 0) { + return null + } + for (i in 0 until clip.itemCount) { + val clipText = clip.getItemAt(i).text.toString() + val data = PermalinkParser.parse(clipText) + if (data is PermalinkData.RoomLink) { + return clipText + } + } + } + return null + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index e08ed6db465..c13997b7637 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -267,6 +267,7 @@ class HomeActivity : HomeActivityViewEvents.NotifyUserForThreadsMigration -> handleNotifyUserForThreadsMigration() is HomeActivityViewEvents.MigrateThreads -> migrateThreadsIfNeeded(it.checkSession) is HomeActivityViewEvents.AskUserForPushDistributor -> askUserToSelectPushDistributor() + is HomeActivityViewEvents.NavigatePermalink -> handleNavigatePermalink(it.permalink) } } homeActivityViewModel.onEach { renderState(it) } @@ -279,6 +280,17 @@ class HomeActivity : homeActivityViewModel.handle(HomeActivityViewActions.ViewStarted) } + private fun handleNavigatePermalink(permalink: String) { + lifecycleScope.launch { + permalinkHandler.launch( + fragmentActivity = this@HomeActivity, + deepLink = permalink, + navigationInterceptor = this@HomeActivity, + buildTask = true + ) + } + } + private fun askUserToSelectPushDistributor() { unifiedPushHelper.showSelectDistributorDialog(this) { selection -> homeActivityViewModel.handle(HomeActivityViewActions.RegisterPushDistributor(selection)) diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt index be5aa7def0c..098696ca297 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt @@ -40,4 +40,5 @@ sealed interface HomeActivityViewEvents : VectorViewEvents { object StartRecoverySetupFlow : HomeActivityViewEvents data class ForceVerification(val sendRequest: Boolean) : HomeActivityViewEvents object AskUserForPushDistributor : HomeActivityViewEvents + data class NavigatePermalink(val permalink: String) : HomeActivityViewEvents } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt index 8f16121a306..6df800e6e80 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt @@ -293,6 +293,7 @@ class HomeActivityViewModel @AssistedInject constructor( .onEach { status -> when (status) { is SyncRequestState.Idle -> { + checkDeferredPermalink() maybeVerifyOrBootstrapCrossSigning() } else -> Unit @@ -371,6 +372,12 @@ class HomeActivityViewModel @AssistedInject constructor( } } + private fun checkDeferredPermalink() { + activeSessionHolder.getActiveSession().deferredPermalinkService().getLinkFromClipBoard()?.let { roomPermalink -> + _viewEvents.post(HomeActivityViewEvents.NavigatePermalink(permalink = roomPermalink)) + } + } + private fun maybeVerifyOrBootstrapCrossSigning() { // The contents of this method should only run once if (hasCheckedBootstrap) return