Refactor + fix sso in LoginFragment
This commit is contained in:
parent
351793d456
commit
42d1bf57f6
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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 im.vector.app.features.login
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.browser.customtabs.CustomTabsClient
|
||||||
|
import androidx.browser.customtabs.CustomTabsServiceConnection
|
||||||
|
import androidx.browser.customtabs.CustomTabsSession
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import im.vector.app.core.utils.openUrlInChromeCustomTab
|
||||||
|
|
||||||
|
abstract class AbstractSSOLoginFragment : AbstractLoginFragment() {
|
||||||
|
|
||||||
|
// For sso
|
||||||
|
private var customTabsServiceConnection: CustomTabsServiceConnection? = null
|
||||||
|
private var customTabsClient: CustomTabsClient? = null
|
||||||
|
private var customTabsSession: CustomTabsSession? = null
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
val hasSSO = withState(loginViewModel) { it.loginMode.hasSso() }
|
||||||
|
if (hasSSO) {
|
||||||
|
val packageName = CustomTabsClient.getPackageName(requireContext(), null)
|
||||||
|
|
||||||
|
// packageName can be null if there are 0 or several CustomTabs compatible browsers installed on the device
|
||||||
|
if (packageName != null) {
|
||||||
|
customTabsServiceConnection = object : CustomTabsServiceConnection() {
|
||||||
|
override fun onCustomTabsServiceConnected(name: ComponentName, client: CustomTabsClient) {
|
||||||
|
customTabsClient = client
|
||||||
|
.also { it.warmup(0L) }
|
||||||
|
prefetchIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.also {
|
||||||
|
CustomTabsClient.bindCustomTabsService(
|
||||||
|
requireContext(),
|
||||||
|
// Despite the API, packageName cannot be null
|
||||||
|
packageName,
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
val hasSSO = withState(loginViewModel) { it.loginMode.hasSso() }
|
||||||
|
if (hasSSO) {
|
||||||
|
customTabsServiceConnection?.let { requireContext().unbindService(it) }
|
||||||
|
customTabsServiceConnection = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prefetchUrl(url: String) {
|
||||||
|
if (customTabsSession == null) {
|
||||||
|
customTabsSession = customTabsClient?.newSession(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
customTabsSession?.mayLaunchUrl(Uri.parse(url), null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun openInCustomTab(ssoUrl: String) {
|
||||||
|
openUrlInChromeCustomTab(requireContext(), customTabsSession, ssoUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun prefetchIfNeeded() {
|
||||||
|
withState(loginViewModel) { state ->
|
||||||
|
if (state.loginMode.hasSso() && state.loginMode.ssoProviders().isNullOrEmpty()) {
|
||||||
|
// in this case we can prefetch (not other cases for privacy concerns)
|
||||||
|
prefetchUrl(state.getSsoUrl(null))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,7 @@ import javax.inject.Inject
|
|||||||
* In signup mode:
|
* In signup mode:
|
||||||
* - the user is asked for login and password
|
* - the user is asked for login and password
|
||||||
*/
|
*/
|
||||||
class LoginFragment @Inject constructor() : AbstractLoginFragment() {
|
class LoginFragment @Inject constructor() : AbstractSSOLoginFragment() {
|
||||||
|
|
||||||
private var passwordShown = false
|
private var passwordShown = false
|
||||||
private var isSignupMode = false
|
private var isSignupMode = false
|
||||||
@ -176,6 +176,11 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
|
|||||||
if (state.loginMode is LoginMode.SsoAndPassword) {
|
if (state.loginMode is LoginMode.SsoAndPassword) {
|
||||||
loginSocialLoginContainer.isVisible = true
|
loginSocialLoginContainer.isVisible = true
|
||||||
loginSocialLoginButtons.identityProviders = state.loginMode.identityProviders
|
loginSocialLoginButtons.identityProviders = state.loginMode.identityProviders
|
||||||
|
loginSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
||||||
|
override fun onProviderSelected(id: String?) {
|
||||||
|
openInCustomTab(state.getSsoUrl(id))
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
loginSocialLoginContainer.isVisible = false
|
loginSocialLoginContainer.isVisible = false
|
||||||
loginSocialLoginButtons.identityProviders = null
|
loginSocialLoginButtons.identityProviders = null
|
||||||
|
@ -16,31 +16,18 @@
|
|||||||
|
|
||||||
package im.vector.app.features.login
|
package im.vector.app.features.login
|
||||||
|
|
||||||
import android.content.ComponentName
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.browser.customtabs.CustomTabsClient
|
|
||||||
import androidx.browser.customtabs.CustomTabsServiceConnection
|
|
||||||
import androidx.browser.customtabs.CustomTabsSession
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import butterknife.OnClick
|
import butterknife.OnClick
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.extensions.toReducedUrl
|
import im.vector.app.core.extensions.toReducedUrl
|
||||||
import im.vector.app.core.utils.openUrlInChromeCustomTab
|
|
||||||
import kotlinx.android.synthetic.main.fragment_login_signup_signin_selection.*
|
import kotlinx.android.synthetic.main.fragment_login_signup_signin_selection.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In this screen, the user is asked to sign up or to sign in to the homeserver
|
* In this screen, the user is asked to sign up or to sign in to the homeserver
|
||||||
*/
|
*/
|
||||||
class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractLoginFragment() {
|
class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractSSOLoginFragment() {
|
||||||
|
|
||||||
// Map of sso urls by providers if any
|
|
||||||
private var ssoUrls = emptyMap<String?, String>().toMutableMap()
|
|
||||||
|
|
||||||
private var customTabsServiceConnection: CustomTabsServiceConnection? = null
|
|
||||||
private var customTabsClient: CustomTabsClient? = null
|
|
||||||
private var customTabsSession: CustomTabsSession? = null
|
|
||||||
|
|
||||||
override fun getLayoutResId() = R.layout.fragment_login_signup_signin_selection
|
override fun getLayoutResId() = R.layout.fragment_login_signup_signin_selection
|
||||||
|
|
||||||
@ -73,7 +60,8 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractLoginFr
|
|||||||
loginSignupSigninSocialLoginButtons.identityProviders = identityProviders
|
loginSignupSigninSocialLoginButtons.identityProviders = identityProviders
|
||||||
loginSignupSigninSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
loginSignupSigninSocialLoginButtons.listener = object : SocialLoginButtonsView.InteractionListener {
|
||||||
override fun onProviderSelected(id: String?) {
|
override fun onProviderSelected(id: String?) {
|
||||||
ssoUrls[id]?.let { openUrlInChromeCustomTab(requireContext(), customTabsSession, it) }
|
val url = withState(loginViewModel) { it.getSsoUrl(id) }
|
||||||
|
openInCustomTab(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,72 +73,6 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractLoginFr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
val hasSSO = withState(loginViewModel) { it.loginMode.hasSso() }
|
|
||||||
if (hasSSO) {
|
|
||||||
val packageName = CustomTabsClient.getPackageName(requireContext(), null)
|
|
||||||
|
|
||||||
// packageName can be null if there are 0 or several CustomTabs compatible browsers installed on the device
|
|
||||||
if (packageName != null) {
|
|
||||||
customTabsServiceConnection = object : CustomTabsServiceConnection() {
|
|
||||||
override fun onCustomTabsServiceConnected(name: ComponentName, client: CustomTabsClient) {
|
|
||||||
customTabsClient = client
|
|
||||||
.also { it.warmup(0L) }
|
|
||||||
|
|
||||||
// prefetch urls
|
|
||||||
prefetchSsoUrls()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onServiceDisconnected(name: ComponentName?) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.also {
|
|
||||||
CustomTabsClient.bindCustomTabsService(
|
|
||||||
requireContext(),
|
|
||||||
// Despite the API, packageName cannot be null
|
|
||||||
packageName,
|
|
||||||
it
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStop() {
|
|
||||||
super.onStop()
|
|
||||||
val hasSSO = withState(loginViewModel) { it.loginMode.hasSso() }
|
|
||||||
if (hasSSO) {
|
|
||||||
customTabsServiceConnection?.let { requireContext().unbindService(it) }
|
|
||||||
customTabsServiceConnection = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun prefetchSsoUrls() = withState(loginViewModel) { state ->
|
|
||||||
val providers = state.loginMode.ssoProviders()
|
|
||||||
if (providers.isNullOrEmpty()) {
|
|
||||||
state.getSsoUrl(null).let {
|
|
||||||
ssoUrls[null] = it
|
|
||||||
prefetchUrl(it)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
providers.forEach { identityProvider ->
|
|
||||||
state.getSsoUrl(identityProvider.id).let {
|
|
||||||
ssoUrls[identityProvider.id] = it
|
|
||||||
// we don't prefetch for privacy reasons
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun prefetchUrl(url: String) {
|
|
||||||
if (customTabsSession == null) {
|
|
||||||
customTabsSession = customTabsClient?.newSession(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
customTabsSession?.mayLaunchUrl(Uri.parse(url), null, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupButtons(state: LoginViewState) {
|
private fun setupButtons(state: LoginViewState) {
|
||||||
when (state.loginMode) {
|
when (state.loginMode) {
|
||||||
is LoginMode.Sso -> {
|
is LoginMode.Sso -> {
|
||||||
@ -168,7 +90,7 @@ class LoginSignUpSignInSelectionFragment @Inject constructor() : AbstractLoginFr
|
|||||||
@OnClick(R.id.loginSignupSigninSubmit)
|
@OnClick(R.id.loginSignupSigninSubmit)
|
||||||
fun submit() = withState(loginViewModel) { state ->
|
fun submit() = withState(loginViewModel) { state ->
|
||||||
if (state.loginMode is LoginMode.Sso) {
|
if (state.loginMode is LoginMode.Sso) {
|
||||||
ssoUrls[null]?.let { openUrlInChromeCustomTab(requireContext(), customTabsSession, it) }
|
openInCustomTab(state.getSsoUrl(null))
|
||||||
} else {
|
} else {
|
||||||
loginViewModel.handle(LoginAction.UpdateSignMode(SignMode.SignUp))
|
loginViewModel.handle(LoginAction.UpdateSignMode(SignMode.SignUp))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user