Skip to content

Commit 88a6f74

Browse files
committed
Merge branch 'release/5.36.3'
2 parents 12be8c6 + 4362446 commit 88a6f74

File tree

40 files changed

+274
-283
lines changed

40 files changed

+274
-283
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import com.duckduckgo.app.statistics.VariantManager.Companion.DEFAULT_VARIANT
6262
import com.duckduckgo.app.statistics.api.StatisticsUpdater
6363
import com.duckduckgo.app.statistics.pixels.Pixel
6464
import com.duckduckgo.app.survey.db.SurveyDao
65+
import com.duckduckgo.app.tabs.model.TabEntity
6566
import com.duckduckgo.app.tabs.model.TabRepository
6667
import com.duckduckgo.app.trackerdetection.model.TrackerNetwork
6768
import com.duckduckgo.app.trackerdetection.model.TrackerNetworks
@@ -1133,6 +1134,15 @@ class BrowserTabViewModelTest {
11331134
assertTrue(command is Command.LaunchNewTab)
11341135
}
11351136

1137+
@Test
1138+
fun whenCloseCurrentTabSelectedThenTabDeletedFromRepository() = runBlocking {
1139+
val liveData = MutableLiveData<TabEntity>()
1140+
liveData.value = TabEntity("TAB_ID", "", "", false, true, 0)
1141+
whenever(mockTabsRepository.liveSelectedTab).thenReturn(liveData)
1142+
testee.closeCurrentTab()
1143+
verify(mockTabsRepository).delete(liveData.value!!)
1144+
}
1145+
11361146
@Test
11371147
fun whenUserPressesBackAndSkippingHomeThenWebViewPreviewGenerated() {
11381148
setupNavigation(isBrowsing = true, canGoBack = false, skipHome = true)

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.duckduckgo.app.browser
1818

1919
import android.content.Context
2020
import android.os.Build
21+
import android.webkit.CookieManager
2122
import android.webkit.HttpAuthHandler
2223
import android.webkit.RenderProcessGoneDetail
2324
import android.webkit.WebView
@@ -36,25 +37,25 @@ class BrowserWebViewClientTest {
3637
private lateinit var testee: BrowserWebViewClient
3738
private lateinit var webView: WebView
3839

40+
private val requestRewriter: RequestRewriter = mock()
3941
private val specialUrlDetector: SpecialUrlDetector = mock()
4042
private val requestInterceptor: RequestInterceptor = mock()
4143
private val listener: WebViewClientListener = mock()
44+
private val cookieManager: CookieManager = mock()
4245
private val offlinePixelCountDataStore: OfflinePixelCountDataStore = mock()
4346
private val uncaughtExceptionRepository: UncaughtExceptionRepository = mock()
44-
private val mainFrameUrlHandler: SpecialUrlHandler = mock()
45-
private val subFrameUrlHandler: SpecialUrlHandler = mock()
4647

4748
@UiThreadTest
4849
@Before
4950
fun setup() {
5051
webView = TestWebView(InstrumentationRegistry.getInstrumentation().targetContext)
5152
testee = BrowserWebViewClient(
53+
requestRewriter,
5254
specialUrlDetector,
5355
requestInterceptor,
5456
offlinePixelCountDataStore,
5557
uncaughtExceptionRepository,
56-
mainFrameUrlHandler,
57-
subFrameUrlHandler
58+
cookieManager
5859
)
5960
testee.webViewClientListener = listener
6061
}

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
package com.duckduckgo.app.browser
1818

1919
import com.duckduckgo.app.browser.SpecialUrlDetector.UrlType.*
20+
import com.duckduckgo.app.browser.SpecialUrlDetectorImpl.Companion.EMAIL_MAX_LENGTH
21+
import com.duckduckgo.app.browser.SpecialUrlDetectorImpl.Companion.PHONE_MAX_LENGTH
22+
import com.duckduckgo.app.browser.SpecialUrlDetectorImpl.Companion.SMS_MAX_LENGTH
2023
import org.junit.Assert.assertEquals
2124
import org.junit.Before
2225
import org.junit.Test
@@ -152,4 +155,44 @@ class SpecialUrlDetectorImplTest {
152155
val type = testee.determineType("javascript:alert(0)") as SearchQuery
153156
assertEquals("javascript:alert(0)", type.query)
154157
}
158+
159+
@Test
160+
fun whenSmsContentIsLongerThanMaxAllowedThenTruncateToMax() {
161+
val longSms = randomString(SMS_MAX_LENGTH + 1)
162+
val type = testee.determineType("sms:$longSms") as Sms
163+
assertEquals(longSms.substring(0, SMS_MAX_LENGTH), type.telephoneNumber)
164+
}
165+
166+
@Test
167+
fun whenSmsToContentIsLongerThanMaxAllowedThenTruncateToMax() {
168+
val longSms = randomString(SMS_MAX_LENGTH + 1)
169+
val type = testee.determineType("smsto:$longSms") as Sms
170+
assertEquals(longSms.substring(0, SMS_MAX_LENGTH), type.telephoneNumber)
171+
}
172+
173+
@Test
174+
fun whenEmailContentIsLongerThanMaxAllowedThenTruncateToMax() {
175+
val longEmail = "mailto:${randomString(EMAIL_MAX_LENGTH + 1)}"
176+
val type = testee.determineType(longEmail) as Email
177+
assertEquals(longEmail.substring(0, EMAIL_MAX_LENGTH), type.emailAddress)
178+
}
179+
180+
@Test
181+
fun whenTelephoneContentIsLongerThanMaxAllowedThenTruncateToMax() {
182+
val longTelephone = randomString(PHONE_MAX_LENGTH + 1)
183+
val type = testee.determineType("tel:$longTelephone") as Telephone
184+
assertEquals(longTelephone.substring(0, PHONE_MAX_LENGTH), type.telephoneNumber)
185+
}
186+
187+
@Test
188+
fun whenTelephonePromptContentIsLongerThanMaxAllowedThenTruncateToMax() {
189+
val longTelephone = randomString(PHONE_MAX_LENGTH + 1)
190+
val type = testee.determineType("telprompt:$longTelephone") as Telephone
191+
assertEquals(longTelephone.substring(0, PHONE_MAX_LENGTH), type.telephoneNumber)
192+
}
193+
194+
private fun randomString(length: Int): String {
195+
val charList: List<Char> = ('a'..'z') + ('0'..'9')
196+
return List(length) { charList.random() }.joinToString("")
197+
}
155198
}

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

Lines changed: 0 additions & 76 deletions
This file was deleted.

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

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
217217

218218
private val logoHidingListener by lazy { LogoHidingLayoutChangeLifecycleListener(ddgLogo) }
219219

220+
private var alertDialog: AlertDialog? = null
221+
220222
override fun onAttach(context: Context) {
221223
AndroidSupportInjection.inject(this)
222224
super.onAttach(context)
@@ -426,16 +428,16 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
426428
is Command.DialNumber -> {
427429
val intent = Intent(Intent.ACTION_DIAL)
428430
intent.data = Uri.parse("tel:${it.telephoneNumber}")
429-
activity?.launchExternalActivity(intent)
431+
openExternalDialog(intent, null, false)
430432
}
431433
is Command.SendEmail -> {
432434
val intent = Intent(Intent.ACTION_SENDTO)
433435
intent.data = Uri.parse(it.emailAddress)
434-
activity?.launchExternalActivity(intent)
436+
openExternalDialog(intent)
435437
}
436438
is Command.SendSms -> {
437439
val intent = Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:${it.telephoneNumber}"))
438-
startActivity(intent)
440+
openExternalDialog(intent)
439441
}
440442
Command.ShowKeyboard -> {
441443
showKeyboard()
@@ -470,7 +472,7 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
470472
}
471473
}
472474
is Command.HandleExternalAppLink -> {
473-
externalAppLinkClicked(it)
475+
openExternalDialog(it.appLink.intent, it.appLink.fallbackUrl, false)
474476
}
475477
is Command.LaunchSurvey -> launchSurvey(it.survey)
476478
is Command.LaunchAddWidget -> launchAddWidget()
@@ -511,42 +513,53 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
511513
}
512514
}
513515

514-
private fun externalAppLinkClicked(appLinkCommand: Command.HandleExternalAppLink) {
516+
private fun openExternalDialog(intent: Intent, fallbackUrl: String? = null, useFirstActivityFound: Boolean = true) {
515517
context?.let {
516518
val pm = it.packageManager
517-
val intent = appLinkCommand.appLink.intent
518519
val activities = pm.queryIntentActivities(intent, 0)
519520

520-
Timber.i("Found ${activities.size} that could consume ${appLinkCommand.appLink.url}")
521-
522-
when (activities.size) {
523-
0 -> {
524-
if (appLinkCommand.appLink.fallbackUrl != null) {
525-
webView?.loadUrl(appLinkCommand.appLink.fallbackUrl)
526-
} else {
527-
showToast(R.string.unableToOpenLink)
528-
}
529-
return
521+
if (activities.isEmpty()) {
522+
if (fallbackUrl != null) {
523+
webView?.loadUrl(fallbackUrl)
524+
} else {
525+
showToast(R.string.unableToOpenLink)
530526
}
531-
1 -> {
527+
} else {
528+
if (activities.size == 1 || useFirstActivityFound) {
532529
val activity = activities.first()
533530
val appTitle = activity.loadLabel(pm)
534531
Timber.i("Exactly one app available for intent: $appTitle")
535-
536-
AlertDialog.Builder(it)
537-
.setTitle(R.string.launchingExternalApp)
538-
.setMessage(getString(R.string.confirmOpenExternalApp))
539-
.setPositiveButton(R.string.openExternalApp) { _, _ -> it.startActivity(intent) }
540-
.setNegativeButton(android.R.string.cancel) { dialog, _ -> dialog.dismiss() }
541-
.show()
542-
}
543-
else -> {
532+
launchExternalAppDialog(it) { it.startActivity(intent) }
533+
} else {
544534
val title = getString(R.string.openExternalApp)
545535
val intentChooser = Intent.createChooser(intent, title)
546-
it.startActivity(intentChooser)
536+
launchExternalAppDialog(it) { it.startActivity(intentChooser) }
547537
}
548538
}
539+
}
540+
}
541+
542+
private fun launchExternalAppDialog(context: Context, onClick: () -> Unit) {
543+
val isShowing = alertDialog?.isShowing
549544

545+
if (isShowing != true) {
546+
alertDialog = AlertDialog.Builder(context)
547+
.setTitle(R.string.launchingExternalApp)
548+
.setMessage(getString(R.string.confirmOpenExternalApp))
549+
.setPositiveButton(R.string.yes) { _, _ ->
550+
onClick()
551+
}
552+
.setNeutralButton(R.string.closeTab) { dialog, _ ->
553+
dialog.dismiss()
554+
launch {
555+
viewModel.closeCurrentTab()
556+
destroyWebView()
557+
}
558+
}
559+
.setNegativeButton(R.string.no) { dialog, _ ->
560+
dialog.dismiss()
561+
}
562+
.show()
550563
}
551564
}
552565

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,13 @@ class BrowserTabViewModel(
351351
return !currentBrowserViewState().browserShowing && navigation.hasNavigationHistory
352352
}
353353

354+
suspend fun closeCurrentTab() {
355+
val currentTab = tabRepository.liveSelectedTab.value
356+
currentTab?.let {
357+
tabRepository.delete(currentTab)
358+
}
359+
}
360+
354361
fun onUserPressedForward() {
355362
if (!currentBrowserViewState().browserShowing) {
356363
browserViewState.value = currentBrowserViewState().copy(browserShowing = true)

0 commit comments

Comments
 (0)