Merge pull request #2047 from vector-im/feature/universal_link_navigation

Handle room, user, group, email verification links by converting them to permalinks.
This commit is contained in:
Benoit Marty 2020-09-08 12:21:54 +02:00 committed by GitHub
commit 22cd6ae239
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 16 deletions

View file

@ -22,6 +22,8 @@ Bugfix 🐛:
- Loudspeaker is always used (#1685) - Loudspeaker is always used (#1685)
- Fix uploads still don't work with room v6 (#1879) - Fix uploads still don't work with room v6 (#1879)
- Can't handle ongoing call events in background (#1992) - Can't handle ongoing call events in background (#1992)
- Handle room, user and group links by the Element app (#1795)
- Update associated site domain (#1833)
- Crash / Attachment viewer: Cannot draw a recycled Bitmap #2034 - Crash / Attachment viewer: Cannot draw a recycled Bitmap #2034
- Login with Matrix-Id | Autodiscovery fails if identity server is invalid and Homeserver ok (#2027) - Login with Matrix-Id | Autodiscovery fails if identity server is invalid and Homeserver ok (#2027)
- Support for image compression on Android 10 - Support for image compression on Android 10

View file

@ -1,3 +1,3 @@
#!/usr/bin/env bash #!/usr/bin/env bash
adb shell am start -a android.intent.action.VIEW -d "https://riot.im/config/config?hs_url=https%3A%2F%2Fmozilla-test.modular.im" adb shell am start -a android.intent.action.VIEW -d "https://mobile.element.io?hs_url=https%3A%2F%2Fmozilla-test.modular.im"

View file

@ -144,8 +144,10 @@
<data android:scheme="https" /> <data android:scheme="https" />
<data android:host="riot.im" /> <data android:host="riot.im" />
<data android:host="element.io" /> <data android:host="app.element.io" />
<data android:pathPrefix="/config/" /> <data android:host="mobile.element.io" />
<data android:host="develop.element.io" />
<data android:host="staging.element.io" />
</intent-filter> </intent-filter>
</activity> </activity>

View file

@ -24,10 +24,14 @@ import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.ScreenComponent import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.toast
import im.vector.app.features.login.LoginActivity import im.vector.app.features.login.LoginActivity
import im.vector.app.features.login.LoginConfig import im.vector.app.features.login.LoginConfig
import im.vector.app.features.permalink.PermalinkHandler
import io.reactivex.android.schedulers.AndroidSchedulers
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import timber.log.Timber import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
/** /**
@ -37,6 +41,7 @@ class LinkHandlerActivity : VectorBaseActivity() {
@Inject lateinit var sessionHolder: ActiveSessionHolder @Inject lateinit var sessionHolder: ActiveSessionHolder
@Inject lateinit var errorFormatter: ErrorFormatter @Inject lateinit var errorFormatter: ErrorFormatter
@Inject lateinit var permalinkHandler: PermalinkHandler
override fun injectWith(injector: ScreenComponent) { override fun injectWith(injector: ScreenComponent) {
injector.inject(this) injector.inject(this)
@ -54,20 +59,57 @@ class LinkHandlerActivity : VectorBaseActivity() {
return return
} }
if (uri.path == PATH_CONFIG) { if (uri.getQueryParameter(CONFIG_PATH_HS_PARAMETER) != null) {
if (sessionHolder.hasActiveSession()) { handleConfigUrl(uri)
displayAlreadyLoginPopup(uri) } else if (SUPPORTED_HOSTS.contains(uri.host)) {
} else { handleSupportedHostUrl(uri)
// user is not yet logged in, this is the nominal case
startLoginActivity(uri)
}
} else {
// Other link are not yet handled, but should not comes here (manifest configuration error?)
Timber.w("Unable to handle this uir: $uri")
finish()
} }
} }
private fun handleConfigUrl(uri: Uri) {
if (sessionHolder.hasActiveSession()) {
displayAlreadyLoginPopup(uri)
} else {
// user is not yet logged in, this is the nominal case
startLoginActivity(uri)
}
}
private fun handleSupportedHostUrl(uri: Uri) {
if (!sessionHolder.hasActiveSession()) {
startLoginActivity(uri)
finish()
} else {
convertUriToPermalink(uri)?.let { permalink ->
startPermalinkHandler(permalink)
} ?: run {
// Host is correct but we do not recognize path
Timber.w("Unable to handle this uri: $uri")
finish()
}
}
}
private fun convertUriToPermalink(uri: Uri): String? {
val path = SUPPORTED_PATHS.find { it in uri.toString() } ?: return null
// https://riot.im/develop/#/room/#element-android:matrix.org -> https://matrix.to/#/#element-android:matrix.org
// https://app.element.io/#/room/#element-android:matrix.org -> https://matrix.to/#/#element-android:matrix.org
return "https://$MATRIX_TO_HOST/#" + uri.toString().substringAfter(path)
}
private fun startPermalinkHandler(permalink: String) {
permalinkHandler.launch(this, permalink, buildTask = true)
.delay(500, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { isHandled ->
if (!isHandled) {
toast(R.string.universal_link_malformed)
}
finish()
}
.disposeOnDestroy()
}
/** /**
* Start the login screen with identity server and home server pre-filled * Start the login screen with identity server and home server pre-filled
*/ */
@ -113,6 +155,10 @@ class LinkHandlerActivity : VectorBaseActivity() {
} }
companion object { companion object {
private const val PATH_CONFIG = "/config/config" private const val CONFIG_PATH_HS_PARAMETER = "hs_url"
private val SUPPORTED_HOSTS = arrayOf("app.element.io", "riot.im", "develop.element.io", "staging.element.io")
private val SUPPORTED_PATHS = arrayOf("/#/room", "/#/user", "/#/group")
private const val MATRIX_TO_HOST = "matrix.to"
} }
} }

View file

@ -22,7 +22,7 @@ import kotlinx.android.parcel.Parcelize
/** /**
* Parameters extracted from a configuration url * Parameters extracted from a configuration url
* Ex: https://riot.im/config/config?hs_url=https%3A%2F%2Fexample.modular.im&is_url=https%3A%2F%2Fcustom.identity.org * Ex: https://mobile.element.io?hs_url=https%3A%2F%2Fexample.modular.im&is_url=https%3A%2F%2Fcustom.identity.org
* *
* Note: On RiotX, identityServerUrl will never be used, so is declared private. Keep it for compatibility reason. * Note: On RiotX, identityServerUrl will never be used, so is declared private. Keep it for compatibility reason.
*/ */

View file

@ -2564,4 +2564,7 @@
<string name="auth_pin_confirm_to_disable_title">Confirm PIN to disable PIN</string> <string name="auth_pin_confirm_to_disable_title">Confirm PIN to disable PIN</string>
<string name="error_opening_banned_room">Can\'t open a room where you are banned from.</string> <string name="error_opening_banned_room">Can\'t open a room where you are banned from.</string>
<string name="room_error_not_found">Can\'t find this room. Make sure it exists.</string> <string name="room_error_not_found">Can\'t find this room. Make sure it exists.</string>
<!-- Universal link -->
<string name="universal_link_malformed">The link was malformed</string>
</resources> </resources>