Skip to content

Commit b132c4a

Browse files
authored
Android: Authentication popup shown in the context of previous website (#820)
* show/hide background webview while showing auth popup * dismiss dialog when sending to background * If dialog dismissed by activity, cancel authentication
1 parent f610a2a commit b132c4a

File tree

4 files changed

+81
-4
lines changed

4 files changed

+81
-4
lines changed

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,32 @@ class BrowserTabViewModelTest {
12841284
assertSame(authenticationRequest, requiresAuthCommand.request)
12851285
}
12861286

1287+
@Test
1288+
fun whenAuthenticationIsRequiredForSameHostThenNoChangesOnBrowser() {
1289+
val mockHandler = mock<HttpAuthHandler>()
1290+
val siteURL = "http://example.com/requires-auth"
1291+
val authenticationRequest = BasicAuthenticationRequest(mockHandler, "example.com", "test realm", siteURL)
1292+
1293+
loadUrl(url = "http://example.com", isBrowserShowing = true)
1294+
testee.requiresAuthentication(authenticationRequest)
1295+
1296+
assertCommandNotIssued<Command.HideWebContent>()
1297+
assertEquals("http://example.com", omnibarViewState().omnibarText)
1298+
}
1299+
1300+
@Test
1301+
fun whenAuthenticationIsRequiredForDifferentHostThenUpdateUrlAndHideWebContent() {
1302+
val mockHandler = mock<HttpAuthHandler>()
1303+
val siteURL = "http://example.com/requires-auth"
1304+
val authenticationRequest = BasicAuthenticationRequest(mockHandler, "example.com", "test realm", siteURL)
1305+
1306+
loadUrl(url = "http://another.website.com", isBrowserShowing = true)
1307+
testee.requiresAuthentication(authenticationRequest)
1308+
1309+
assertCommandIssued<Command.HideWebContent>()
1310+
assertEquals(siteURL, omnibarViewState().omnibarText)
1311+
}
1312+
12871313
@Test
12881314
fun whenHandleAuthenticationThenHandlerCalledWithParameters() {
12891315
val mockHandler = mock<HttpAuthHandler>()
@@ -1296,6 +1322,25 @@ class BrowserTabViewModelTest {
12961322
verify(mockHandler, atLeastOnce()).proceed(username, password)
12971323
}
12981324

1325+
@Test
1326+
fun whenAuthenticationDialogAcceptedThenShowWebContent() {
1327+
val authenticationRequest = BasicAuthenticationRequest(mock(), "example.com", "test realm", "")
1328+
val credentials = BasicAuthenticationCredentials(username = "user", password = "password")
1329+
1330+
testee.handleAuthentication(request = authenticationRequest, credentials = credentials)
1331+
1332+
assertCommandIssued<Command.ShowWebContent>()
1333+
}
1334+
1335+
@Test
1336+
fun whenAuthenticationDialogCanceledThenShowWebContent() {
1337+
val authenticationRequest = BasicAuthenticationRequest(mock(), "example.com", "test realm", "")
1338+
1339+
testee.cancelAuthentication(request = authenticationRequest)
1340+
1341+
assertCommandIssued<Command.ShowWebContent>()
1342+
}
1343+
12991344
@Test
13001345
fun whenBookmarkSuggestionSubmittedThenAutoCompleteBookmarkSelectionPixelSent() = runBlocking {
13011346
whenever(mockBookmarksDao.hasBookmarks()).thenReturn(true)
@@ -1718,6 +1763,11 @@ class BrowserTabViewModelTest {
17181763
(issuedCommand as T).apply { instanceAssertions() }
17191764
}
17201765

1766+
private inline fun <reified T : Command> assertCommandNotIssued() {
1767+
val issuedCommand = commandCaptor.allValues.find { it is T }
1768+
assertNull(issuedCommand)
1769+
}
1770+
17211771
private fun pixelParams(showedBookmarks: Boolean, bookmarkCapable: Boolean) = mapOf(
17221772
Pixel.PixelParameter.SHOWED_BOOKMARKS to showedBookmarks.toString(),
17231773
Pixel.PixelParameter.BOOKMARK_CAPABLE to bookmarkCapable.toString()

app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,9 +374,17 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope, DaxDialogLi
374374
override fun onPause() {
375375
logoHidingListener.onPause()
376376
dismissDownloadFragment()
377+
dismissAuthenticationDialog()
377378
super.onPause()
378379
}
379380

381+
private fun dismissAuthenticationDialog() {
382+
if (isAdded) {
383+
val fragment = parentFragmentManager.findFragmentByTag(AUTHENTICATION_DIALOG_TAG) as? HttpAuthenticationDialogFragment
384+
fragment?.dismiss()
385+
}
386+
}
387+
380388
private fun dismissDownloadFragment() {
381389
val fragment = fragmentManager?.findFragmentByTag(DOWNLOAD_CONFIRMATION_TAG) as? DownloadConfirmationFragment
382390
fragment?.dismiss()
@@ -567,6 +575,8 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope, DaxDialogLi
567575
is Command.ShowErrorWithAction -> showErrorSnackbar(it)
568576
is Command.DaxCommand.FinishTrackerAnimation -> finishTrackerAnimation()
569577
is Command.DaxCommand.HideDaxDialog -> showHideTipsDialog(it.cta)
578+
is Command.HideWebContent -> webView?.hide()
579+
is Command.ShowWebContent -> webView?.show()
570580
}
571581
}
572582

app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ class BrowserTabViewModel(
207207
class SaveCredentials(val request: BasicAuthenticationRequest, val credentials: BasicAuthenticationCredentials) : Command()
208208
object GenerateWebViewPreviewImage : Command()
209209
object LaunchTabSwitcher : Command()
210+
object HideWebContent : Command()
211+
object ShowWebContent : Command()
212+
210213
class ShowErrorWithAction(val action: () -> Unit) : Command()
211214
sealed class DaxCommand : Command() {
212215
object FinishTrackerAnimation : DaxCommand()
@@ -1114,16 +1117,22 @@ class BrowserTabViewModel(
11141117
}
11151118

11161119
override fun requiresAuthentication(request: BasicAuthenticationRequest) {
1120+
if (request.host != site?.uri?.host) {
1121+
omnibarViewState.value = currentOmnibarViewState().copy(omnibarText = request.site)
1122+
command.value = HideWebContent
1123+
}
11171124
command.value = RequiresAuthentication(request)
11181125
}
11191126

11201127
override fun handleAuthentication(request: BasicAuthenticationRequest, credentials: BasicAuthenticationCredentials) {
11211128
request.handler.proceed(credentials.username, credentials.password)
1129+
command.value = ShowWebContent
11221130
command.value = SaveCredentials(request, credentials)
11231131
}
11241132

11251133
override fun cancelAuthentication(request: BasicAuthenticationRequest) {
11261134
request.handler.cancel()
1135+
command.value = ShowWebContent
11271136
}
11281137

11291138
fun userLaunchingTabSwitcher() {

app/src/main/java/com/duckduckgo/app/browser/ui/HttpAuthenticationDialogFragment.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616

1717
package com.duckduckgo.app.browser.ui
1818

19-
import androidx.appcompat.app.AlertDialog
2019
import android.app.Dialog
20+
import android.content.DialogInterface
2121
import android.os.Bundle
2222
import android.view.View
2323
import android.view.WindowManager
2424
import android.widget.EditText
2525
import android.widget.TextView
26+
import androidx.appcompat.app.AlertDialog
2627
import androidx.fragment.app.DialogFragment
2728
import com.duckduckgo.app.browser.R
2829
import com.duckduckgo.app.browser.model.BasicAuthenticationCredentials
@@ -33,8 +34,9 @@ import org.jetbrains.anko.find
3334

3435
class HttpAuthenticationDialogFragment : DialogFragment() {
3536

36-
var listener: HttpAuthenticationListener? = null
37+
private var didUserCompleteAuthentication: Boolean = false
3738
lateinit var request: BasicAuthenticationRequest
39+
var listener: HttpAuthenticationListener? = null
3840

3941
interface HttpAuthenticationListener {
4042
fun handleAuthentication(request: BasicAuthenticationRequest, credentials: BasicAuthenticationCredentials)
@@ -60,18 +62,24 @@ class HttpAuthenticationDialogFragment : DialogFragment() {
6062
request,
6163
BasicAuthenticationCredentials(username = usernameInput.text.toString(), password = passwordInput.text.toString())
6264
)
63-
65+
didUserCompleteAuthentication = true
6466
}.setNegativeButton(R.string.authenticationDialogNegativeButton) { _, _ ->
6567
rootView.hideKeyboard()
6668
listener?.cancelAuthentication(request)
69+
didUserCompleteAuthentication = true
6770
}
6871
.setTitle(R.string.authenticationDialogTitle)
6972

7073
val alert = alertBuilder.create()
7174
showKeyboard(usernameInput, alert)
72-
7375
return alert
76+
}
7477

78+
override fun onDismiss(dialog: DialogInterface) {
79+
super.onDismiss(dialog)
80+
if (!didUserCompleteAuthentication) {
81+
listener?.cancelAuthentication(request)
82+
}
7583
}
7684

7785
private fun validateBundleArguments() {

0 commit comments

Comments
 (0)