From dda90f2d23e995eeb91f79566b8b5220b2b4d055 Mon Sep 17 00:00:00 2001
From: bogdan-niculescu-sch
<104439589+bogdan-niculescu-sch@users.noreply.github.com>
Date: Wed, 21 Jun 2023 11:07:09 +0200
Subject: [PATCH 1/2] Revert "Merge branch 'add-login-prompt' into master"
(#77)
This reverts commit 249267bdd28280be3259afd9e75b3af7ae367556, reversing
changes made to 96b90bcb120e52b99dee49f71d56dc29b81a3a80.
---
app/build.gradle | 4 +-
.../schibsted/account/example/MainActivity.kt | 6 -
app/src/main/res/layout/activity_main.xml | 11 --
app/src/main/res/values/colors.xml | 4 +-
app/src/main/res/values/styles.xml | 7 +-
webflows/build.gradle | 13 +-
.../webflows/api/UserProfileResponse.kt | 2 +-
.../account/webflows/client/Client.kt | 12 +-
.../loginPrompt/LoginPromptFragment.kt | 79 ------------
.../schibsted/account/webflows/util/Util.kt | 10 --
.../main/res/drawable/login_prompt_logos.xml | 106 ----------------
.../src/main/res/drawable/rounded_dialog.xml | 10 --
.../src/main/res/drawable/rounded_layout.xml | 5 -
webflows/src/main/res/layout/login_prompt.xml | 118 ------------------
webflows/src/main/res/values/strings.xml | 9 --
webflows/src/main/res/values/styles.xml | 11 --
16 files changed, 18 insertions(+), 389 deletions(-)
delete mode 100644 webflows/src/main/java/com/schibsted/account/webflows/loginPrompt/LoginPromptFragment.kt
delete mode 100644 webflows/src/main/res/drawable/login_prompt_logos.xml
delete mode 100644 webflows/src/main/res/drawable/rounded_dialog.xml
delete mode 100644 webflows/src/main/res/drawable/rounded_layout.xml
delete mode 100644 webflows/src/main/res/layout/login_prompt.xml
delete mode 100644 webflows/src/main/res/values/strings.xml
delete mode 100644 webflows/src/main/res/values/styles.xml
diff --git a/app/build.gradle b/app/build.gradle
index bb8fac26..09d2346b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,12 +2,12 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
- compileSdkVersion 33
+ compileSdkVersion 32
defaultConfig {
applicationId "com.schibsted.account"
minSdkVersion 21
- targetSdkVersion 32
+ targetSdkVersion 30
versionCode 1
versionName "1.0"
diff --git a/app/src/main/java/com/schibsted/account/example/MainActivity.kt b/app/src/main/java/com/schibsted/account/example/MainActivity.kt
index e48e8dbe..6fb297cb 100644
--- a/app/src/main/java/com/schibsted/account/example/MainActivity.kt
+++ b/app/src/main/java/com/schibsted/account/example/MainActivity.kt
@@ -8,7 +8,6 @@ import androidx.lifecycle.Observer
import com.schibsted.account.databinding.ActivityMainBinding
import com.schibsted.account.webflows.activities.AuthResultLiveData
import com.schibsted.account.webflows.activities.NotAuthed
-import com.schibsted.account.webflows.loginPrompt.LoginPromptFragment
import com.schibsted.account.webflows.user.User
import com.schibsted.account.webflows.util.Either
import timber.log.Timber
@@ -40,11 +39,6 @@ class MainActivity : AppCompatActivity() {
binding.manualLoginButton.setOnClickListener {
startActivity(Intent(this, ManualLoginActivity::class.java))
}
-
- binding.showLoginPrompt.setOnClickListener {
- val loginPromptFragment = LoginPromptFragment()
- loginPromptFragment.show(supportFragmentManager, "12345")
- }
}
private fun observeAuthResultLiveData() {
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index fe171a33..cdf50696 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -25,15 +25,4 @@
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/loginButton" />
-
-
-
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 67ca5909..4faecfa8 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,6 +1,6 @@
- #3274D4
- #2196F3
+ #6200EE
+ #3700B3
#03DAC5
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 5799a5d4..fac92916 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,15 +1,10 @@
-
-
-
\ No newline at end of file
diff --git a/webflows/build.gradle b/webflows/build.gradle
index 105993d8..13b5eda4 100644
--- a/webflows/build.gradle
+++ b/webflows/build.gradle
@@ -6,11 +6,11 @@ apply plugin: 'maven-publish'
apply plugin: 'signing'
android {
- compileSdkVersion 33
+ compileSdkVersion 32
defaultConfig {
minSdkVersion 21
- targetSdkVersion 33
+ targetSdkVersion 30
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
@@ -21,10 +21,6 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
- buildFeatures {
- viewBinding true
- }
-
buildTypes {
release {
minifyEnabled false
@@ -64,18 +60,15 @@ dependencies {
api "androidx.browser:browser:1.4.0"
implementation 'com.nimbusds:nimbus-jose-jwt:9.24.3'
- implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
//Logging
implementation "com.jakewharton.timber:timber:$timber_version"
- implementation 'androidx.constraintlayout:constraintlayout:2.2.0-alpha09'
- implementation 'com.google.android.material:material:1.8.0'
testImplementation 'junit:junit:4.13.2'
testImplementation "io.mockk:mockk:${mockkVersion}"
testImplementation "com.squareup.okhttp3:mockwebserver:${okHttpVersion}"
- testImplementation 'org.robolectric:robolectric:4.9.1'
+ testImplementation 'org.robolectric:robolectric:4.8.2'
testImplementation 'androidx.test.ext:junit:1.1.3'
testImplementation "androidx.test.espresso:espresso-core:${espressoVersion}"
testImplementation "androidx.test.espresso:espresso-intents:${espressoVersion}"
diff --git a/webflows/src/main/java/com/schibsted/account/webflows/api/UserProfileResponse.kt b/webflows/src/main/java/com/schibsted/account/webflows/api/UserProfileResponse.kt
index 6e2e4f30..3bcb7822 100644
--- a/webflows/src/main/java/com/schibsted/account/webflows/api/UserProfileResponse.kt
+++ b/webflows/src/main/java/com/schibsted/account/webflows/api/UserProfileResponse.kt
@@ -92,7 +92,7 @@ data class Address(
@SerializedName("invoice")
INVOICE;
- override fun toString(): String = super.toString().lowercase(Locale.ROOT)
+ override fun toString(): String = super.toString().toLowerCase(Locale.ROOT)
}
}
diff --git a/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt b/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt
index d6a72361..36f1220e 100644
--- a/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt
+++ b/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt
@@ -23,7 +23,6 @@ import com.schibsted.account.webflows.util.Either
import com.schibsted.account.webflows.util.Either.Left
import com.schibsted.account.webflows.util.Either.Right
import com.schibsted.account.webflows.util.Util
-import com.schibsted.account.webflows.util.Util.isCustomTabsSupported
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import org.json.JSONException
@@ -96,7 +95,7 @@ class Client {
@JvmOverloads
fun getAuthenticationIntent(context: Context, authRequest: AuthRequest = AuthRequest()): Intent {
val loginUrl = generateLoginUrl(authRequest)
- val intent: Intent = if (isCustomTabsSupported(context)) {
+ val intent: Intent = if (this.isCustomTabsSupported(context)) {
buildCustomTabsIntent()
.apply {
intent.data = loginUrl
@@ -115,7 +114,7 @@ class Client {
@JvmOverloads
fun launchAuth(context: Context, authRequest: AuthRequest = AuthRequest()) {
val loginUrl = generateLoginUrl(authRequest)
- if (isCustomTabsSupported(context)) {
+ if (this.isCustomTabsSupported(context)) {
buildCustomTabsIntent().launchUrl(context, loginUrl)
} else {
val intent = Intent(Intent.ACTION_VIEW, loginUrl).addCategory(Intent.CATEGORY_BROWSABLE)
@@ -134,6 +133,13 @@ class Client {
return Uri.parse(loginUrl)
}
+ private fun isCustomTabsSupported(context: Context): Boolean {
+ val serviceIntent = Intent(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION)
+ val resolveInfos = context.packageManager.queryIntentServices(serviceIntent, 0)
+
+ return !resolveInfos.isEmpty()
+ }
+
/**
* Call this with the intent received via deep link to complete the login flow.
*
diff --git a/webflows/src/main/java/com/schibsted/account/webflows/loginPrompt/LoginPromptFragment.kt b/webflows/src/main/java/com/schibsted/account/webflows/loginPrompt/LoginPromptFragment.kt
deleted file mode 100644
index 56a80373..00000000
--- a/webflows/src/main/java/com/schibsted/account/webflows/loginPrompt/LoginPromptFragment.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.schibsted.account.webflows.loginPrompt
-
-import android.content.Intent
-import android.net.Uri
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.browser.customtabs.CustomTabsIntent
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import com.google.android.material.bottomsheet.BottomSheetDialogFragment
-import com.schibsted.account.webflows.R
-import com.schibsted.account.webflows.databinding.LoginPromptBinding
-import com.schibsted.account.webflows.util.Util
-import kotlinx.coroutines.launch
-
-
-class LoginPromptFragment : BottomSheetDialogFragment() {
- private var _binding: LoginPromptBinding? = null
- private val binding get() = _binding!!
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setStyle(STYLE_NORMAL, R.style.LoginPromptDialog)
-
- lifecycleScope.launch {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- isCancelable = false
- }
-
- }
- }
-
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?,
- ): View {
- super.onCreateView(inflater, container, savedInstanceState)
- _binding = LoginPromptBinding.inflate(inflater, container, false)
- return binding.root
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
- initializeButtons()
- }
-
- override fun onDestroyView() {
- _binding = null
- super.onDestroyView()
- }
-
- private fun initializeButtons() {
- binding.loginPromptButton.setOnClickListener {
- // placeholder TODO: add call to handleAuthenticationResponse
- dismiss()
- }
- binding.loginPromptSkip.setOnClickListener {
- dismiss()
- }
-
- binding.loginPromptPrivacy.setOnClickListener {
- val uri = Uri.parse(getString(R.string.login_prompt_privacy_url))
- if (Util.isCustomTabsSupported(this.requireContext())) {
- CustomTabsIntent.Builder().build().launchUrl(this.requireContext(), uri)
- } else {
- startActivity(
- Intent(
- Intent.ACTION_VIEW,
- uri
- ).addCategory(Intent.CATEGORY_BROWSABLE)
- )
- }
- }
- }
-}
diff --git a/webflows/src/main/java/com/schibsted/account/webflows/util/Util.kt b/webflows/src/main/java/com/schibsted/account/webflows/util/Util.kt
index d257cfb8..d5dd90f9 100644
--- a/webflows/src/main/java/com/schibsted/account/webflows/util/Util.kt
+++ b/webflows/src/main/java/com/schibsted/account/webflows/util/Util.kt
@@ -1,8 +1,5 @@
package com.schibsted.account.webflows.util
-import android.content.Context
-import android.content.Intent
-import androidx.browser.customtabs.CustomTabsService
import java.net.URLDecoder
import kotlin.random.Random
@@ -45,11 +42,4 @@ internal object Util {
return "${split[0]}.${split[1]}"
}
-
- fun isCustomTabsSupported(context: Context): Boolean {
- val serviceIntent = Intent(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION)
- val resolveInfos = context.packageManager.queryIntentServices(serviceIntent, 0)
-
- return !resolveInfos.isEmpty()
- }
}
diff --git a/webflows/src/main/res/drawable/login_prompt_logos.xml b/webflows/src/main/res/drawable/login_prompt_logos.xml
deleted file mode 100644
index 734246a2..00000000
--- a/webflows/src/main/res/drawable/login_prompt_logos.xml
+++ /dev/null
@@ -1,106 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/webflows/src/main/res/drawable/rounded_dialog.xml b/webflows/src/main/res/drawable/rounded_dialog.xml
deleted file mode 100644
index 0d9082ac..00000000
--- a/webflows/src/main/res/drawable/rounded_dialog.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
diff --git a/webflows/src/main/res/drawable/rounded_layout.xml b/webflows/src/main/res/drawable/rounded_layout.xml
deleted file mode 100644
index 533708e3..00000000
--- a/webflows/src/main/res/drawable/rounded_layout.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/webflows/src/main/res/layout/login_prompt.xml b/webflows/src/main/res/layout/login_prompt.xml
deleted file mode 100644
index 65c2ebdc..00000000
--- a/webflows/src/main/res/layout/login_prompt.xml
+++ /dev/null
@@ -1,118 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/webflows/src/main/res/values/strings.xml b/webflows/src/main/res/values/strings.xml
deleted file mode 100644
index 126b7ded..00000000
--- a/webflows/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Logga inn
- Du är redan inloggad på någon av Schibsteds tjänster och kan därför snabbt logga in även på den här tjänsten
- Personuppgiftspolicy
- Fortsätt utan att logga in
- Logga inn
- https://info.privacy.schibsted.com/no/schibsted-norge-personvernerklaering/
-
\ No newline at end of file
diff --git a/webflows/src/main/res/values/styles.xml b/webflows/src/main/res/values/styles.xml
deleted file mode 100644
index 786d5609..00000000
--- a/webflows/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
From 695f2146b323bc1eb12e3b9a814148fb1812013e Mon Sep 17 00:00:00 2001
From: bogdan-niculescu-sch
<104439589+bogdan-niculescu-sch@users.noreply.github.com>
Date: Wed, 9 Aug 2023 17:01:49 +0200
Subject: [PATCH 2/2] Throw different error type if user cancels login (#83)
* Throw different error type if user cancels login
* Check error before state
- throw NotAuthed.CancelledByUser error
* Fix typo
---
.../webflows/activities/AuthResultLiveData.kt | 9 ++++++-
.../account/webflows/client/Client.kt | 27 ++++++++++++++++---
2 files changed, 31 insertions(+), 5 deletions(-)
diff --git a/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt b/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt
index 59132ebe..75a734af 100644
--- a/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt
+++ b/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt
@@ -58,7 +58,14 @@ class AuthResultLiveData private constructor(private val client: Client) :
client.handleAuthenticationResponse(intent) { result ->
when (result) {
is Right -> update(result)
- is Left -> update(Left(NotAuthed.LoginFailed(result.value)))
+ is Left -> update(
+ Left(
+ when (result.value) {
+ is LoginError.CancelledByUser -> NotAuthed.CancelledByUser
+ else -> NotAuthed.LoginFailed(result.value)
+ }
+ )
+ )
}
}
}
diff --git a/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt b/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt
index 36f1220e..4c03b420 100644
--- a/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt
+++ b/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt
@@ -28,7 +28,7 @@ import okhttp3.OkHttpClient
import org.json.JSONException
import org.json.JSONObject
import timber.log.Timber
-import java.util.*
+import java.util.Date
/** Represents a client registered with Schibsted account. */
class Client {
@@ -93,7 +93,10 @@ class Client {
* @param authRequest Authentication request parameters.
*/
@JvmOverloads
- fun getAuthenticationIntent(context: Context, authRequest: AuthRequest = AuthRequest()): Intent {
+ fun getAuthenticationIntent(
+ context: Context,
+ authRequest: AuthRequest = AuthRequest()
+ ): Intent {
val loginUrl = generateLoginUrl(authRequest)
val intent: Intent = if (this.isCustomTabsSupported(context)) {
buildCustomTabsIntent()
@@ -161,15 +164,27 @@ class Client {
val stored = stateStorage.getValue(AUTH_STATE_KEY, AuthState::class)
?: return callback(Left(LoginError.AuthStateReadError))
+ val eidUserCancelError = mapOf(
+ "error" to "access_denied",
+ "error_description" to "EID authentication was canceled by the user"
+ )
+ val error = authResponse["error"]
+ val errorDescription = authResponse["error_description"]
+ if (error != null && error == eidUserCancelError["error"] && errorDescription == eidUserCancelError["error_description"]) {
+ val oauthError = OAuthError(error, errorDescription)
+ callback(Left(LoginError.CancelledByUser(oauthError)))
+ return
+ }
+
if (stored.state != authResponse["state"]) {
callback(Left(LoginError.UnsolicitedResponse))
return
}
+
stateStorage.removeValue(AUTH_STATE_KEY)
- val error = authResponse["error"]
if (error != null) {
- val oauthError = OAuthError(error, authResponse["error_description"])
+ val oauthError = OAuthError(error, errorDescription)
callback(Left(LoginError.AuthenticationErrorResponse(oauthError)))
return
}
@@ -260,6 +275,7 @@ class Client {
Left(RefreshTokenError.UnexpectedError("User has logged-out during token refresh"))
}
}
+
is Left -> {
Timber.e("Failed to refresh token: $result")
Left(RefreshTokenError.RefreshRequestFailed(result.value.cause))
@@ -318,6 +334,9 @@ sealed class LoginError {
*/
data class TokenErrorResponse(val error: OAuthError) : LoginError()
+ /** User canceled login. */
+ data class CancelledByUser(val error: OAuthError) : LoginError()
+
/** Something went wrong. */
data class UnexpectedError(val message: String) : LoginError()
}