Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,10 @@ import org.junit.Assert.*
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.*
import org.mockito.ArgumentCaptor.forClass
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations

class BrowserViewModelTest {

Expand All @@ -78,7 +76,7 @@ class BrowserViewModelTest {
lateinit var mockQueryObserver: Observer<String>

@Mock
lateinit var mockNavigationObserver: Observer<Command>
lateinit var mockCommandObserver: Observer<Command>

@Mock
lateinit var mockTermsOfServiceStore: TermsOfServiceStore
Expand Down Expand Up @@ -121,7 +119,7 @@ class BrowserViewModelTest {
appConfigurationDao = appConfigurationDao)

testee.url.observeForever(mockQueryObserver)
testee.command.observeForever(mockNavigationObserver)
testee.command.observeForever(mockCommandObserver)

whenever(mockOmnibarConverter.convertQueryToUri(any())).thenReturn(Uri.parse("duckduckgo.com"))

Expand All @@ -132,7 +130,7 @@ class BrowserViewModelTest {
testee.onCleared()
db.close()
testee.url.removeObserver(mockQueryObserver)
testee.command.removeObserver(mockNavigationObserver)
testee.command.removeObserver(mockCommandObserver)
}

@Test
Expand Down Expand Up @@ -242,8 +240,8 @@ class BrowserViewModelTest {
@Test
fun whenSharedTextReceivedThenNavigationTriggered() {
testee.onSharedTextReceived("http://example.com")
val captor: ArgumentCaptor<Command> = ArgumentCaptor.forClass(Command::class.java)
verify(mockNavigationObserver, times(2)).onChanged(captor.capture())
val captor: ArgumentCaptor<Command> = forClass(Command::class.java)
verify(mockCommandObserver, times(2)).onChanged(captor.capture())
assertNotNull(captor.value)
assertTrue(captor.value is Navigate)
}
Expand All @@ -263,13 +261,13 @@ class BrowserViewModelTest {
@Test
fun whenUserDismissesKeyboardBeforeBrowserShownThenShouldNavigateToLandingPage() {
testee.userDismissedKeyboard()
verify(mockNavigationObserver).onChanged(ArgumentMatchers.any(LandingPage::class.java))
verify(mockCommandObserver).onChanged(ArgumentMatchers.any(LandingPage::class.java))
}

@Test
fun whenUserDismissesKeyboardAfterBrowserShownThenShouldNotNavigateToLandingPage() {
testee.urlChanged("")
verify(mockNavigationObserver, never()).onChanged(ArgumentMatchers.any(LandingPage::class.java))
verify(mockCommandObserver, never()).onChanged(ArgumentMatchers.any(LandingPage::class.java))
}

@Test
Expand Down Expand Up @@ -387,4 +385,18 @@ class BrowserViewModelTest {
testee.onOmnibarInputStateChanged("", true)
assertFalse(testee.viewState.value!!.showAutoCompleteSuggestions)
}

@Test
fun whenEnteringEmptyQueryThenHideKeyboardCommandNotIssued() {
testee.onUserSubmittedQuery("")
verify(mockCommandObserver, never()).onChanged(Mockito.any(Command.HideKeyboard.javaClass))
}

@Test
fun whenEnteringNonEmptyQueryThenHideKeyboardCommandIssued() {
val captor = ArgumentCaptor.forClass(BrowserViewModel.Command::class.java)
testee.onUserSubmittedQuery("foo")
verify(mockCommandObserver, Mockito.atLeastOnce()).onChanged(captor.capture())
assertTrue(captor.value == Command.HideKeyboard)
}
}
68 changes: 37 additions & 31 deletions app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import android.widget.Toast
import com.duckduckgo.app.bookmarks.ui.BookmarkAddEditDialogFragment
import com.duckduckgo.app.bookmarks.ui.BookmarkAddEditDialogFragment.BookmarkDialogCreationListener
import com.duckduckgo.app.bookmarks.ui.BookmarksActivity
import com.duckduckgo.app.browser.BrowserViewModel.Command
import com.duckduckgo.app.browser.autoComplete.BrowserAutoCompleteSuggestionsAdapter
import com.duckduckgo.app.browser.omnibar.OnBackKeyListener
import com.duckduckgo.app.global.DuckDuckGoActivity
Expand Down Expand Up @@ -129,38 +130,45 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener {
})

viewModel.command.observe(this, Observer {
when (it) {
is BrowserViewModel.Command.Refresh -> webView.reload()
is BrowserViewModel.Command.Navigate -> {
focusDummy.requestFocus()
webView.loadUrl(it.url)
}
is BrowserViewModel.Command.LandingPage -> finishActivityAnimated()
is BrowserViewModel.Command.DialNumber -> {
val intent = Intent(Intent.ACTION_DIAL)
intent.data = Uri.parse("tel:${it.telephoneNumber}")
launchExternalActivity(intent)
}
is BrowserViewModel.Command.SendEmail -> {
val intent = Intent(Intent.ACTION_SENDTO)
intent.data = Uri.parse(it.emailAddress)
launchExternalActivity(intent)
}
is BrowserViewModel.Command.SendSms -> {
val intent = Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:${it.telephoneNumber}"))
startActivity(intent)
}
is BrowserViewModel.Command.ShowKeyboard -> {
Timber.i("Command: showing keyboard")
omnibarTextInput.postDelayed({omnibarTextInput.showKeyboard()}, 300)
}
is BrowserViewModel.Command.ReinitialiseWebView -> {
webView.clearHistory()
}
}
processCommand(it)
})
}

private fun processCommand(it: Command?) {
when (it) {
Command.Refresh -> webView.reload()
is Command.Navigate -> {
focusDummy.requestFocus()
webView.loadUrl(it.url)
}
Command.LandingPage -> finishActivityAnimated()
is Command.DialNumber -> {
val intent = Intent(Intent.ACTION_DIAL)
intent.data = Uri.parse("tel:${it.telephoneNumber}")
launchExternalActivity(intent)
}
is Command.SendEmail -> {
val intent = Intent(Intent.ACTION_SENDTO)
intent.data = Uri.parse(it.emailAddress)
launchExternalActivity(intent)
}
is Command.SendSms -> {
val intent = Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:${it.telephoneNumber}"))
startActivity(intent)
}
Command.ShowKeyboard -> {
omnibarTextInput.postDelayed({omnibarTextInput.showKeyboard()}, 300)
}
Command.HideKeyboard -> {
omnibarTextInput.hideKeyboard()
focusDummy.requestFocus()
}
Command.ReinitialiseWebView -> {
webView.clearHistory()
}
}
}

private fun configureAutoComplete() {
autoCompleteSuggestionsList.layoutManager = LinearLayoutManager(this)
autoCompleteSuggestionsAdapter = BrowserAutoCompleteSuggestionsAdapter(
Expand Down Expand Up @@ -288,8 +296,6 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener {
}

private fun userEnteredQuery(query: String) {
omnibarTextInput.hideKeyboard()
focusDummy.requestFocus()
viewModel.onUserSubmittedQuery(query)
}

Expand Down
17 changes: 10 additions & 7 deletions app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,15 @@ class BrowserViewModel(
)

sealed class Command {
class LandingPage : Command()
class Refresh : Command()
object LandingPage : Command()
object Refresh : Command()
class Navigate(val url: String) : Command()
class DialNumber(val telephoneNumber: String) : Command()
class SendSms(val telephoneNumber: String) : Command()
class SendEmail(val emailAddress: String) : Command()
class ShowKeyboard : Command()
class ReinitialiseWebView : Command()
object ShowKeyboard : Command()
object HideKeyboard : Command()
object ReinitialiseWebView : Command()
}

/* Observable data for Activity to subscribe to */
Expand All @@ -109,7 +110,7 @@ class BrowserViewModel(
private var appConfigurationDownloaded = false

init {
command.value = Command.ShowKeyboard()
command.value = Command.ShowKeyboard
viewState.value = ViewState(canAddBookmarks = false)
appConfigurationObservable.observeForever(appConfigurationObserver)

Expand Down Expand Up @@ -150,6 +151,8 @@ class BrowserViewModel(
return
}

command.value = Command.HideKeyboard

val trimmedInput = input.trim()
url.value = buildUrl(trimmedInput)
viewState.value = currentViewState().copy(
Expand Down Expand Up @@ -294,14 +297,14 @@ class BrowserViewModel(
*/
fun userDismissedKeyboard(): Boolean {
if (!currentViewState().browserShowing) {
command.value = Command.LandingPage()
command.value = Command.LandingPage
return true
}
return false
}

fun receivedDashboardResult(resultCode: Int) {
if (resultCode == RELOAD_RESULT_CODE) command.value = Command.Refresh()
if (resultCode == RELOAD_RESULT_CODE) command.value = Command.Refresh
}

@WorkerThread
Expand Down