From 5d1c4125230e6c5c513c4930ee996aa30dc34c3e Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Wed, 21 Feb 2018 13:29:56 +0000 Subject: [PATCH 01/13] First pass at "request desktop site" mode. Includes removal of user device details - the make and model are omitted, though other details about the browser capabilities are retained to ensure a good browsing experience --- .../app/browser/BrowserViewModelTest.kt | 47 ++++++++++++ .../userAgent/UserAgentProviderTest.kt | 60 ++++++++++++++++ .../duckduckgo/app/browser/BrowserActivity.kt | 23 ++++++ .../app/browser/BrowserViewModel.kt | 29 +++++++- .../app/browser/WebViewRequestInterceptor.kt | 6 ++ .../browser/userAgent/UserAgentProvider.kt | 72 +++++++++++++++++++ .../duckduckgo/app/global/ViewModelFactory.kt | 3 + .../app/settings/db/SettingsDataStore.kt | 14 +++- .../res/layout/popup_window_browser_menu.xml | 11 +++ app/src/main/res/values/strings.xml | 3 +- 10 files changed, 263 insertions(+), 5 deletions(-) create mode 100644 app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt create mode 100644 app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt diff --git a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt index ddde50af9f6e..6f051ba9b528 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt @@ -32,6 +32,7 @@ import com.duckduckgo.app.browser.BrowserViewModel.Command import com.duckduckgo.app.browser.BrowserViewModel.Command.LandingPage import com.duckduckgo.app.browser.BrowserViewModel.Command.Navigate import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter +import com.duckduckgo.app.browser.userAgent.UserAgentProvider import com.duckduckgo.app.global.db.AppDatabase import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardDao import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardEntry @@ -126,6 +127,7 @@ class BrowserViewModelTest { appSettingsPreferencesStore = mockSettingsStore, bookmarksDao = bookmarksDao, longPressHandler = mockLongPressHandler, + userAgentProvider = UserAgentProvider(), appConfigurationDao = appConfigurationDao) testee.url.observeForever(mockQueryObserver) @@ -473,4 +475,49 @@ class BrowserViewModelTest { assertEquals("", testee.viewState.value!!.findInPage.searchTerm) } + @Test + fun whenUserSelectsDesktopSiteThenDesktopModeCommandIssued() { + testee.desktopSiteModeToggled("http://example.com", desktopSiteRequested = true) + verify(mockCommandObserver, Mockito.atLeastOnce()).onChanged(commandCaptor.capture()) + assertTrue(commandCaptor.allValues.contains(Command.DesktopMode)) + } + + @Test + fun whenUserSelectsMobileSiteThenMobileModeCommandIssued() { + testee.desktopSiteModeToggled("http://example.com", desktopSiteRequested = false) + verify(mockCommandObserver, Mockito.atLeastOnce()).onChanged(commandCaptor.capture()) + assertTrue(commandCaptor.allValues.contains(Command.MobileMode)) + } + + @Test + fun whenUserSelectsDesktopSiteWhenOnMobileSpecificSiteThenUrlModified() { + testee.desktopSiteModeToggled("http://m.example.com", desktopSiteRequested = true) + verify(mockCommandObserver, Mockito.atLeastOnce()).onChanged(commandCaptor.capture()) + val ultimateCommand = commandCaptor.lastValue as Navigate + assertEquals("http://example.com", ultimateCommand.url) + } + + @Test + fun whenUserSelectsDesktopSiteWhenNotOnMobileSpecificSiteThenUrlNotModified() { + testee.desktopSiteModeToggled("http://example.com", desktopSiteRequested = true) + verify(mockCommandObserver, Mockito.atLeastOnce()).onChanged(commandCaptor.capture()) + val ultimateCommand = commandCaptor.lastValue + assertTrue(ultimateCommand == Command.Refresh) + } + + @Test + fun whenUserSelectsMobileSiteWhenOnMobileSpecificSiteThenUrlNotModified() { + testee.desktopSiteModeToggled("http://m.example.com", desktopSiteRequested = false) + verify(mockCommandObserver, Mockito.atLeastOnce()).onChanged(commandCaptor.capture()) + val ultimateCommand = commandCaptor.lastValue + assertTrue(ultimateCommand == Command.Refresh) + } + + @Test + fun whenUserSelectsMobileSiteWhenNotOnMobileSpecificSiteThenUrlNotModified() { + testee.desktopSiteModeToggled("http://example.com", desktopSiteRequested = false) + verify(mockCommandObserver, Mockito.atLeastOnce()).onChanged(commandCaptor.capture()) + val ultimateCommand = commandCaptor.lastValue + assertTrue(ultimateCommand == Command.Refresh) + } } diff --git a/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt b/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt new file mode 100644 index 000000000000..44c3c64eb1af --- /dev/null +++ b/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 DuckDuckGo + * + * 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 com.duckduckgo.app.browser.userAgent + +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test + +private const val CHROME_UA_MOBILE = + "Mozilla/5.0 (Linux; Android 8.1.0; Nexus 6P Build/OPM3.171019.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36" + +// Some values will be dynamic based on OS/Architecture/Software versions, so use Regex to match around dynamic values +private val CHROME_UA_DESKTOP_REGEX = Regex( + "Mozilla/5.0 \\(X11; Linux .*?\\) AppleWebKit\\/[.0-9]+ \\(KHTML, like Gecko\\) Chrome\\/[.0-9]+ Safari/[.0-9]+" +) + +class UserAgentProviderTest { + + private lateinit var testee: UserAgentProvider + + @Before + fun setup() { + testee = UserAgentProvider() + } + + @Test + fun whenMobileUaRetrievedThenDeviceStrippedFromReturnedUa() { + val actual = testee.getUserAgent(CHROME_UA_MOBILE, desktopSiteRequested = false) + val expected = "Mozilla/5.0 (Linux; Android 8.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36" + assertEquals(expected, actual) + } + + @Test + fun whenDesktopUaRetrievedThenDeviceStrippedFromReturnedUa() { + val actual = testee.getUserAgent(CHROME_UA_MOBILE, desktopSiteRequested = true) + CHROME_UA_DESKTOP_REGEX.matches(actual) + } + + @Test + fun whenMissingAppleWebKitStringThenSimplyReturnsNothing() { + val missingAppleWebKitPart = "Mozilla/5.0 (Linux; Android 8.1.0; Nexus 6P Build/OPM3.171019.014) Chrome/64.0.3282.137 Mobile Safari/537.36" + val expected = "Mozilla/5.0 (Linux; Android 8.1.0)" + val actual = testee.getUserAgent(missingAppleWebKitPart, desktopSiteRequested = false) + assertEquals(expected, actual) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt index e7d35ed9ecef..16e0bfa5ae2a 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt @@ -50,6 +50,7 @@ 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.browser.userAgent.UserAgentProvider import com.duckduckgo.app.global.DuckDuckGoActivity import com.duckduckgo.app.global.ViewModelFactory import com.duckduckgo.app.global.view.* @@ -78,12 +79,17 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We @Inject lateinit var viewModelFactory: ViewModelFactory + @Inject + lateinit var userAgentProvider: UserAgentProvider + private lateinit var popupMenu: BrowserPopupMenu private lateinit var autoCompleteSuggestionsAdapter: BrowserAutoCompleteSuggestionsAdapter private var acceptingRenderUpdates = true + private lateinit var defaultUserAgentString : String + private val viewModel: BrowserViewModel by lazy { ViewModelProviders.of(this, viewModelFactory).get(BrowserViewModel::class.java) } @@ -129,6 +135,14 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We enableMenuOption(view.addBookmarksPopupMenuItem) { addBookmark() } enableMenuOption(view.settingsPopupMenuItem) { launchSettings() } enableMenuOption(view.findInPageMenuItem) { viewModel.userRequestingToFindInPage() } + enableMenuOption(view.requestDesktopSiteCheckMenuItem) { + Timber.i("here and now") + } + + view.requestDesktopSiteCheckMenuItem.setOnCheckedChangeListener { _, isChecked -> + Timber.i("changed, checked = $isChecked") + viewModel.desktopSiteModeToggled(urlString = webView.url, desktopSiteRequested = isChecked) + } } } @@ -186,6 +200,12 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We pendingFileDownload = PendingFileDownload(it.url, Environment.DIRECTORY_PICTURES) downloadFileWithPermissionCheck() } + Command.DesktopMode -> { + webView.settings.userAgentString = userAgentProvider.getUserAgent(defaultUserAgentString, desktopSiteRequested = true) + } + Command.MobileMode -> { + webView.settings.userAgentString = userAgentProvider.getUserAgent(defaultUserAgentString, desktopSiteRequested = false) + } is Command.FindInPageCommand -> webView.findAllAsync(it.searchTerm) Command.DismissFindInPage -> webView.findAllAsync(null) } @@ -401,10 +421,13 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We @SuppressLint("SetJavaScriptEnabled") private fun configureWebView() { webView = layoutInflater.inflate(R.layout.include_duckduckgo_browser_webview, webViewContainer, true).findViewById(R.id.browserWebView) as WebView + defaultUserAgentString = webView.settings.userAgentString + webView.webViewClient = webViewClient webView.webChromeClient = webChromeClient webView.settings.apply { + userAgentString = userAgentProvider.getUserAgent(defaultUserAgentString) javaScriptEnabled = true domStorageEnabled = true loadWithOverviewMode = true diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt index 6b741756cfae..8fae4e977de2 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt @@ -34,6 +34,9 @@ import com.duckduckgo.app.bookmarks.db.BookmarksDao import com.duckduckgo.app.browser.BrowserViewModel.Command.Navigate import com.duckduckgo.app.browser.LongPressHandler.RequiredAction import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter +import com.duckduckgo.app.browser.userAgent.UserAgentProvider +import com.duckduckgo.app.browser.userAgent.isMobileSite +import com.duckduckgo.app.browser.userAgent.toDesktopUri import com.duckduckgo.app.global.SingleLiveEvent import com.duckduckgo.app.privacymonitor.SiteMonitor import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardDao @@ -66,6 +69,7 @@ class BrowserViewModel( private val autoCompleteApi: AutoCompleteApi, private val appSettingsPreferencesStore: SettingsDataStore, private val longPressHandler: LongPressHandler, + private val userAgentProvider: UserAgentProvider, appConfigurationDao: AppConfigurationDao) : WebViewClientListener, ViewModel() { data class ViewState( @@ -97,6 +101,8 @@ class BrowserViewModel( class DownloadImage(val url: String) : Command() class FindInPageCommand(val searchTerm: String) : Command() object DismissFindInPage : Command() + object DesktopMode: Command() + object MobileMode: Command() } /* Observable data for Activity to subscribe to */ val viewState: MutableLiveData = MutableLiveData() @@ -145,7 +151,6 @@ class BrowserViewModel( viewState.value = currentViewState.copy(autoComplete = searchResultViewState.copy(searchResults = AutoCompleteResult(result.query, results))) } - @VisibleForTesting public override fun onCleared() { super.onCleared() @@ -360,7 +365,6 @@ class BrowserViewModel( } } - fun userRequestingToFindInPage() { viewState.value = currentViewState().copy(findInPage = FindInPage(visible = true)) } @@ -388,6 +392,27 @@ class BrowserViewModel( viewState.value = currentViewState().copy(findInPage = findInPage) } + + fun desktopSiteModeToggled(urlString: String, desktopSiteRequested: Boolean) { + appSettingsPreferencesStore.desktopSiteRequested = desktopSiteRequested + + val url = Uri.parse(urlString) + + if(desktopSiteRequested) { + command.value = BrowserViewModel.Command.DesktopMode + } else { + command.value = BrowserViewModel.Command.MobileMode + } + + if(desktopSiteRequested && url.isMobileSite()) { + val desktopUrl = url.toDesktopUri() + Timber.i("Original URL $urlString - attempting $desktopUrl with desktop site UA string") + command.value = Navigate(desktopUrl.toString()) + } else { + command.value = Command.Refresh + } + } + data class FindInPage( val visible: Boolean = false, val showNumberMatches: Boolean = false, diff --git a/app/src/main/java/com/duckduckgo/app/browser/WebViewRequestInterceptor.kt b/app/src/main/java/com/duckduckgo/app/browser/WebViewRequestInterceptor.kt index c4c024fb6898..7205e641db05 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/WebViewRequestInterceptor.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/WebViewRequestInterceptor.kt @@ -89,6 +89,12 @@ class WebViewRequestInterceptor @Inject constructor( return null } + private fun shouldStripRequestedWithHeader(request: WebResourceRequest): Boolean { + if(!request.isForMainFrame) return false + val requestedWithHeader = request.requestHeaders["X-Requested-With"] ?: request.requestHeaders["x-requested-with"] + return requestedWithHeader != "" + } + private fun shouldUpgrade(request: WebResourceRequest) = request.isForMainFrame && request.url != null && httpsUpgrader.shouldUpgrade(request.url) diff --git a/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt new file mode 100644 index 000000000000..9c9b9e61796c --- /dev/null +++ b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018 DuckDuckGo + * + * 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 com.duckduckgo.app.browser.userAgent + +import android.net.Uri +import android.os.Build +import javax.inject.Inject + + +fun Uri.isMobileSite() : Boolean = this.authority.startsWith("m.") + +fun Uri.toDesktopUri(): Uri { + return if(this.isMobileSite()) { + Uri.parse(toString().replaceFirst("m.", "")) + } else { + this + } +} + +/** + * Example Default User Agent (From Chrome): + * Mozilla/5.0 (Linux; Android 8.1.0; Nexus 6P Build/OPM3.171019.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36 + * + * Example Default Desktop User Agent (From Chrome): + * Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36 + */ +class UserAgentProvider @Inject constructor() { + + companion object { + private val WEB_KIT_REGEX = Regex("AppleWebKit/.*") + + private const val MOZILLA_PREFIX = "Mozilla/5.0" + } + + /** + * Returns a modified UA string which omits the user's device make and model + * If the user is requesting a desktop site, we add generic X11 Linux indicator, but include the real architecture + * If the user is requesting a mobile site, we add Linux Android indicator, and include the real Android OS version + * + * We include everything from the original UA string from AppleWebKit onwards (omitting if missing) + */ + fun getUserAgent(defaultUaString: String, desktopSiteRequested: Boolean = false) : String{ + + val platform = if(desktopSiteRequested) desktopUaPrefix() else mobileUaPrefix() + val userAgentStringSuffix = getWebKitVersionOnwards(defaultUaString) + + return "$MOZILLA_PREFIX ($platform)$userAgentStringSuffix" + } + + private fun mobileUaPrefix() = "Linux; Android ${Build.VERSION.RELEASE}" + + private fun desktopUaPrefix() = "X11; Linux ${System.getProperty("os.arch")}" + + private fun getWebKitVersionOnwards(defaultUaString: String): String { + val result = WEB_KIT_REGEX.find(defaultUaString) ?: return "" + return " ${result.groupValues[0]}" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt b/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt index d22ff294194e..3c35555973e5 100644 --- a/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt +++ b/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt @@ -25,6 +25,7 @@ import com.duckduckgo.app.browser.BrowserViewModel import com.duckduckgo.app.browser.DuckDuckGoUrlDetector import com.duckduckgo.app.browser.LongPressHandler import com.duckduckgo.app.browser.omnibar.QueryUrlConverter +import com.duckduckgo.app.browser.userAgent.UserAgentProvider import com.duckduckgo.app.launch.LaunchViewModel import com.duckduckgo.app.onboarding.store.OnboardingStore import com.duckduckgo.app.onboarding.ui.OnboardingViewModel @@ -58,6 +59,7 @@ class ViewModelFactory @Inject constructor( private val bookmarksDao: BookmarksDao, private val autoCompleteApi: AutoCompleteApi, private val appSettingsPreferencesStore: SettingsDataStore, + private val userAgentProvider: UserAgentProvider, private val webViewLongPressHandler: LongPressHandler ) : ViewModelProvider.NewInstanceFactory() { @@ -88,5 +90,6 @@ class ViewModelFactory @Inject constructor( appSettingsPreferencesStore = appSettingsPreferencesStore, appConfigurationDao = appConfigurationDao, longPressHandler = webViewLongPressHandler, + userAgentProvider = userAgentProvider, autoCompleteApi = autoCompleteApi) } diff --git a/app/src/main/java/com/duckduckgo/app/settings/db/SettingsDataStore.kt b/app/src/main/java/com/duckduckgo/app/settings/db/SettingsDataStore.kt index 232920b01554..36f266de0c2a 100644 --- a/app/src/main/java/com/duckduckgo/app/settings/db/SettingsDataStore.kt +++ b/app/src/main/java/com/duckduckgo/app/settings/db/SettingsDataStore.kt @@ -23,13 +23,15 @@ import javax.inject.Inject interface SettingsDataStore { var autoCompleteSuggestionsEnabled: Boolean + var desktopSiteRequested: Boolean } class AppSettingsPreferencesStore @Inject constructor(private val context: Context) : SettingsDataStore { companion object { - val SHARED_PREFERENCES_FILENAME = "com.duckduckgo.app.settings_activity.settings" - val KEY_AUTOCOMPLETE_ENABLED = "AUTOCOMPLETE_ENABLED" + const val SHARED_PREFERENCES_FILENAME = "com.duckduckgo.app.settings_activity.settings" + const val KEY_AUTOCOMPLETE_ENABLED = "AUTOCOMPLETE_ENABLED" + const val KEY_DESKTOP_SITE_REQUESTED = "KEY_DESKTOP_SITE_REQUESTED" } override var autoCompleteSuggestionsEnabled: Boolean @@ -40,6 +42,14 @@ class AppSettingsPreferencesStore @Inject constructor(private val context: Conte .apply() } + override var desktopSiteRequested: Boolean + get() = preferences.getBoolean(KEY_DESKTOP_SITE_REQUESTED, false) + set(desktopSiteRequested) { + preferences.edit() + .putBoolean(KEY_DESKTOP_SITE_REQUESTED, desktopSiteRequested) + .apply() + } + private val preferences: SharedPreferences get() = context.getSharedPreferences(SHARED_PREFERENCES_FILENAME, Context.MODE_PRIVATE) } \ No newline at end of file diff --git a/app/src/main/res/layout/popup_window_browser_menu.xml b/app/src/main/res/layout/popup_window_browser_menu.xml index 7f5921ef064f..557d2979f372 100644 --- a/app/src/main/res/layout/popup_window_browser_menu.xml +++ b/app/src/main/res/layout/popup_window_browser_menu.xml @@ -83,6 +83,17 @@ android:enabled="false" android:text="@string/addBookmarkMenuTitle" /> + + Download Image Image Options Downloading requires storage permission - Find in page + Request Desktop Site + Find in page Find next Find previous Close find in page view From e5ea895feb01ceb6d6e35844fe64a40b0dd045c3 Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Thu, 22 Feb 2018 12:50:52 +0000 Subject: [PATCH 02/13] Tidy up request desktop site feature --- .../com/duckduckgo/app/browser/BrowserActivity.kt | 7 +------ .../com/duckduckgo/app/browser/BrowserViewModel.kt | 14 +++++++------- .../app/settings/db/SettingsDataStore.kt | 10 ---------- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt index 16e0bfa5ae2a..ca704f096777 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt @@ -136,12 +136,7 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We enableMenuOption(view.settingsPopupMenuItem) { launchSettings() } enableMenuOption(view.findInPageMenuItem) { viewModel.userRequestingToFindInPage() } enableMenuOption(view.requestDesktopSiteCheckMenuItem) { - Timber.i("here and now") - } - - view.requestDesktopSiteCheckMenuItem.setOnCheckedChangeListener { _, isChecked -> - Timber.i("changed, checked = $isChecked") - viewModel.desktopSiteModeToggled(urlString = webView.url, desktopSiteRequested = isChecked) + viewModel.desktopSiteModeToggled(urlString = webView.url, desktopSiteRequested = view.requestDesktopSiteCheckMenuItem.isChecked) } } } diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt index 8fae4e977de2..4623e45ca56d 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt @@ -393,18 +393,18 @@ class BrowserViewModel( } - fun desktopSiteModeToggled(urlString: String, desktopSiteRequested: Boolean) { - appSettingsPreferencesStore.desktopSiteRequested = desktopSiteRequested - - val url = Uri.parse(urlString) - - if(desktopSiteRequested) { + fun desktopSiteModeToggled(urlString: String?, desktopSiteRequested: Boolean) { + if (desktopSiteRequested) { command.value = BrowserViewModel.Command.DesktopMode } else { command.value = BrowserViewModel.Command.MobileMode } - if(desktopSiteRequested && url.isMobileSite()) { + if (urlString == null) { + return + } + val url = Uri.parse(urlString) + if (desktopSiteRequested && url.isMobileSite()) { val desktopUrl = url.toDesktopUri() Timber.i("Original URL $urlString - attempting $desktopUrl with desktop site UA string") command.value = Navigate(desktopUrl.toString()) diff --git a/app/src/main/java/com/duckduckgo/app/settings/db/SettingsDataStore.kt b/app/src/main/java/com/duckduckgo/app/settings/db/SettingsDataStore.kt index 36f266de0c2a..f67b07978e08 100644 --- a/app/src/main/java/com/duckduckgo/app/settings/db/SettingsDataStore.kt +++ b/app/src/main/java/com/duckduckgo/app/settings/db/SettingsDataStore.kt @@ -23,7 +23,6 @@ import javax.inject.Inject interface SettingsDataStore { var autoCompleteSuggestionsEnabled: Boolean - var desktopSiteRequested: Boolean } class AppSettingsPreferencesStore @Inject constructor(private val context: Context) : SettingsDataStore { @@ -31,7 +30,6 @@ class AppSettingsPreferencesStore @Inject constructor(private val context: Conte companion object { const val SHARED_PREFERENCES_FILENAME = "com.duckduckgo.app.settings_activity.settings" const val KEY_AUTOCOMPLETE_ENABLED = "AUTOCOMPLETE_ENABLED" - const val KEY_DESKTOP_SITE_REQUESTED = "KEY_DESKTOP_SITE_REQUESTED" } override var autoCompleteSuggestionsEnabled: Boolean @@ -42,14 +40,6 @@ class AppSettingsPreferencesStore @Inject constructor(private val context: Conte .apply() } - override var desktopSiteRequested: Boolean - get() = preferences.getBoolean(KEY_DESKTOP_SITE_REQUESTED, false) - set(desktopSiteRequested) { - preferences.edit() - .putBoolean(KEY_DESKTOP_SITE_REQUESTED, desktopSiteRequested) - .apply() - } - private val preferences: SharedPreferences get() = context.getSharedPreferences(SHARED_PREFERENCES_FILENAME, Context.MODE_PRIVATE) } \ No newline at end of file From dc09e269b3bba94f58c5793932541da076f586da Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Thu, 22 Feb 2018 15:36:05 +0000 Subject: [PATCH 03/13] Fix last few failing tests after refactor --- .../browser/userAgent/UserAgentProviderTest.kt | 17 +++++++++++------ .../app/browser/userAgent/UserAgentProvider.kt | 12 ++++++++---- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt b/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt index 44c3c64eb1af..363c936b56d9 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt @@ -16,7 +16,7 @@ package com.duckduckgo.app.browser.userAgent -import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test @@ -27,6 +27,13 @@ private const val CHROME_UA_MOBILE = private val CHROME_UA_DESKTOP_REGEX = Regex( "Mozilla/5.0 \\(X11; Linux .*?\\) AppleWebKit\\/[.0-9]+ \\(KHTML, like Gecko\\) Chrome\\/[.0-9]+ Safari/[.0-9]+" ) +private val CHROME_UA_MOBILE_REGEX = Regex( + "Mozilla/5.0 \\(Linux; Android .*?\\) AppleWebKit\\/[.0-9]+ \\(KHTML, like Gecko\\) Chrome\\/[.0-9]+ Mobile Safari/[.0-9]+" +) + +private val CHROME_UA_MOBILE_REGEX_MISSING_APPLE_WEBKIT_DETAILS = Regex( + "Mozilla/5.0 \\(Linux; Android .*?\\)" +) class UserAgentProviderTest { @@ -40,21 +47,19 @@ class UserAgentProviderTest { @Test fun whenMobileUaRetrievedThenDeviceStrippedFromReturnedUa() { val actual = testee.getUserAgent(CHROME_UA_MOBILE, desktopSiteRequested = false) - val expected = "Mozilla/5.0 (Linux; Android 8.1.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36" - assertEquals(expected, actual) + assertTrue(CHROME_UA_MOBILE_REGEX.matches(actual)) } @Test fun whenDesktopUaRetrievedThenDeviceStrippedFromReturnedUa() { val actual = testee.getUserAgent(CHROME_UA_MOBILE, desktopSiteRequested = true) - CHROME_UA_DESKTOP_REGEX.matches(actual) + assertTrue(CHROME_UA_DESKTOP_REGEX.matches(actual)) } @Test fun whenMissingAppleWebKitStringThenSimplyReturnsNothing() { val missingAppleWebKitPart = "Mozilla/5.0 (Linux; Android 8.1.0; Nexus 6P Build/OPM3.171019.014) Chrome/64.0.3282.137 Mobile Safari/537.36" - val expected = "Mozilla/5.0 (Linux; Android 8.1.0)" val actual = testee.getUserAgent(missingAppleWebKitPart, desktopSiteRequested = false) - assertEquals(expected, actual) + assertTrue(CHROME_UA_MOBILE_REGEX_MISSING_APPLE_WEBKIT_DETAILS.matches(actual)) } } \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt index 9c9b9e61796c..f18987679826 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt @@ -56,7 +56,7 @@ class UserAgentProvider @Inject constructor() { fun getUserAgent(defaultUaString: String, desktopSiteRequested: Boolean = false) : String{ val platform = if(desktopSiteRequested) desktopUaPrefix() else mobileUaPrefix() - val userAgentStringSuffix = getWebKitVersionOnwards(defaultUaString) + val userAgentStringSuffix = getWebKitVersionOnwards(defaultUaString, desktopSiteRequested) return "$MOZILLA_PREFIX ($platform)$userAgentStringSuffix" } @@ -65,8 +65,12 @@ class UserAgentProvider @Inject constructor() { private fun desktopUaPrefix() = "X11; Linux ${System.getProperty("os.arch")}" - private fun getWebKitVersionOnwards(defaultUaString: String): String { - val result = WEB_KIT_REGEX.find(defaultUaString) ?: return "" - return " ${result.groupValues[0]}" + private fun getWebKitVersionOnwards(defaultUaString: String, desktopSiteRequested: Boolean): String { + val matches = WEB_KIT_REGEX.find(defaultUaString) ?: return "" + var result = matches.groupValues[0] + if(desktopSiteRequested) { + result = result.replace(" Mobile ", " ") + } + return " $result" } } \ No newline at end of file From baaae01488c5aeeb28a4935e250efca2b117731d Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Mon, 26 Feb 2018 12:01:24 +0000 Subject: [PATCH 04/13] Change string to "Desktop Site" instead of "Request Desktop Site" --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fbd5d2a2af7d..71af9afdbf27 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -27,7 +27,7 @@ Download Image Image Options Downloading requires storage permission - Request Desktop Site + Desktop Site Find in page From 980a36da3590ddf0823f6f58c1a34d2d52cd41a8 Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Mon, 26 Feb 2018 12:01:57 +0000 Subject: [PATCH 05/13] Make "userAgent" package lowercase --- .../java/com/duckduckgo/app/browser/BrowserViewModelTest.kt | 2 +- .../app/browser/userAgent/UserAgentProviderTest.kt | 2 +- .../main/java/com/duckduckgo/app/browser/BrowserActivity.kt | 2 +- .../java/com/duckduckgo/app/browser/BrowserViewModel.kt | 6 +++--- .../duckduckgo/app/browser/userAgent/UserAgentProvider.kt | 2 +- .../main/java/com/duckduckgo/app/global/ViewModelFactory.kt | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt index 6f051ba9b528..7efd789e6603 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt @@ -32,7 +32,7 @@ import com.duckduckgo.app.browser.BrowserViewModel.Command import com.duckduckgo.app.browser.BrowserViewModel.Command.LandingPage import com.duckduckgo.app.browser.BrowserViewModel.Command.Navigate import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter -import com.duckduckgo.app.browser.userAgent.UserAgentProvider +import com.duckduckgo.app.browser.useragent.UserAgentProvider import com.duckduckgo.app.global.db.AppDatabase import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardDao import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardEntry diff --git a/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt b/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt index 363c936b56d9..07978c287054 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.duckduckgo.app.browser.userAgent +package com.duckduckgo.app.browser.useragent import org.junit.Assert.assertTrue import org.junit.Before diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt index ca704f096777..b2be561b37a5 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt @@ -50,7 +50,7 @@ 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.browser.userAgent.UserAgentProvider +import com.duckduckgo.app.browser.useragent.UserAgentProvider import com.duckduckgo.app.global.DuckDuckGoActivity import com.duckduckgo.app.global.ViewModelFactory import com.duckduckgo.app.global.view.* diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt index 4623e45ca56d..9bfb12dba740 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt @@ -34,9 +34,9 @@ import com.duckduckgo.app.bookmarks.db.BookmarksDao import com.duckduckgo.app.browser.BrowserViewModel.Command.Navigate import com.duckduckgo.app.browser.LongPressHandler.RequiredAction import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter -import com.duckduckgo.app.browser.userAgent.UserAgentProvider -import com.duckduckgo.app.browser.userAgent.isMobileSite -import com.duckduckgo.app.browser.userAgent.toDesktopUri +import com.duckduckgo.app.browser.useragent.UserAgentProvider +import com.duckduckgo.app.browser.useragent.isMobileSite +import com.duckduckgo.app.browser.useragent.toDesktopUri import com.duckduckgo.app.global.SingleLiveEvent import com.duckduckgo.app.privacymonitor.SiteMonitor import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardDao diff --git a/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt index f18987679826..42de0ae1f185 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.duckduckgo.app.browser.userAgent +package com.duckduckgo.app.browser.useragent import android.net.Uri import android.os.Build diff --git a/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt b/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt index 3c35555973e5..6d056b7731fd 100644 --- a/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt +++ b/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt @@ -25,7 +25,7 @@ import com.duckduckgo.app.browser.BrowserViewModel import com.duckduckgo.app.browser.DuckDuckGoUrlDetector import com.duckduckgo.app.browser.LongPressHandler import com.duckduckgo.app.browser.omnibar.QueryUrlConverter -import com.duckduckgo.app.browser.userAgent.UserAgentProvider +import com.duckduckgo.app.browser.useragent.UserAgentProvider import com.duckduckgo.app.launch.LaunchViewModel import com.duckduckgo.app.onboarding.store.OnboardingStore import com.duckduckgo.app.onboarding.ui.OnboardingViewModel From ae1c31ee028edf507535bc95038e93ef47965e64 Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Mon, 26 Feb 2018 12:02:16 +0000 Subject: [PATCH 06/13] Fix checkbox UI - tweaking paddings and margins --- app/src/main/res/layout/popup_window_browser_menu.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/popup_window_browser_menu.xml b/app/src/main/res/layout/popup_window_browser_menu.xml index ed31dbdcca5f..a5f484c93c2c 100644 --- a/app/src/main/res/layout/popup_window_browser_menu.xml +++ b/app/src/main/res/layout/popup_window_browser_menu.xml @@ -99,8 +99,11 @@ android:id="@+id/requestDesktopSiteCheckMenuItem" style="@style/BrowserTextMenuItem" android:button="@null" + android:paddingStart="30dp" + android:paddingEnd="0dp" + android:layout_marginEnd="20dp" android:enabled="false" - android:drawablePadding="20dp" + android:drawablePadding="30dp" android:drawableEnd="?android:attr/listChoiceIndicatorMultiple" android:text="@string/requestDesktopSiteMenuTitle" android:layout_width="match_parent" From 5786279fc76e362418d0e891ae43c37704f3004c Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Mon, 26 Feb 2018 12:24:31 +0000 Subject: [PATCH 07/13] Instantiate UserAgentProvider with default user agent string --- .../app/browser/BrowserViewModelTest.kt | 2 -- .../userAgent/UserAgentProviderTest.kt | 15 +++++------- .../duckduckgo/app/browser/BrowserActivity.kt | 11 ++++----- .../app/browser/BrowserViewModel.kt | 2 -- .../browser/userAgent/UserAgentProvider.kt | 24 +++++++++---------- .../duckduckgo/app/global/ViewModelFactory.kt | 3 --- 6 files changed, 22 insertions(+), 35 deletions(-) diff --git a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt index 7efd789e6603..45bf07c80fe4 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt @@ -32,7 +32,6 @@ import com.duckduckgo.app.browser.BrowserViewModel.Command import com.duckduckgo.app.browser.BrowserViewModel.Command.LandingPage import com.duckduckgo.app.browser.BrowserViewModel.Command.Navigate import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter -import com.duckduckgo.app.browser.useragent.UserAgentProvider import com.duckduckgo.app.global.db.AppDatabase import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardDao import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardEntry @@ -127,7 +126,6 @@ class BrowserViewModelTest { appSettingsPreferencesStore = mockSettingsStore, bookmarksDao = bookmarksDao, longPressHandler = mockLongPressHandler, - userAgentProvider = UserAgentProvider(), appConfigurationDao = appConfigurationDao) testee.url.observeForever(mockQueryObserver) diff --git a/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt b/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt index 07978c287054..32fd3d5c208d 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/browser/userAgent/UserAgentProviderTest.kt @@ -17,7 +17,6 @@ package com.duckduckgo.app.browser.useragent import org.junit.Assert.assertTrue -import org.junit.Before import org.junit.Test private const val CHROME_UA_MOBILE = @@ -39,27 +38,25 @@ class UserAgentProviderTest { private lateinit var testee: UserAgentProvider - @Before - fun setup() { - testee = UserAgentProvider() - } - @Test fun whenMobileUaRetrievedThenDeviceStrippedFromReturnedUa() { - val actual = testee.getUserAgent(CHROME_UA_MOBILE, desktopSiteRequested = false) + testee = UserAgentProvider(CHROME_UA_MOBILE) + val actual = testee.getUserAgent(desktopSiteRequested = false) assertTrue(CHROME_UA_MOBILE_REGEX.matches(actual)) } @Test fun whenDesktopUaRetrievedThenDeviceStrippedFromReturnedUa() { - val actual = testee.getUserAgent(CHROME_UA_MOBILE, desktopSiteRequested = true) + testee = UserAgentProvider(CHROME_UA_MOBILE) + val actual = testee.getUserAgent(desktopSiteRequested = true) assertTrue(CHROME_UA_DESKTOP_REGEX.matches(actual)) } @Test fun whenMissingAppleWebKitStringThenSimplyReturnsNothing() { val missingAppleWebKitPart = "Mozilla/5.0 (Linux; Android 8.1.0; Nexus 6P Build/OPM3.171019.014) Chrome/64.0.3282.137 Mobile Safari/537.36" - val actual = testee.getUserAgent(missingAppleWebKitPart, desktopSiteRequested = false) + testee = UserAgentProvider(missingAppleWebKitPart) + val actual = testee.getUserAgent(desktopSiteRequested = false) assertTrue(CHROME_UA_MOBILE_REGEX_MISSING_APPLE_WEBKIT_DETAILS.matches(actual)) } } \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt index b2be561b37a5..a80dfb2c103e 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt @@ -79,7 +79,6 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We @Inject lateinit var viewModelFactory: ViewModelFactory - @Inject lateinit var userAgentProvider: UserAgentProvider private lateinit var popupMenu: BrowserPopupMenu @@ -88,8 +87,6 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We private var acceptingRenderUpdates = true - private lateinit var defaultUserAgentString : String - private val viewModel: BrowserViewModel by lazy { ViewModelProviders.of(this, viewModelFactory).get(BrowserViewModel::class.java) } @@ -196,10 +193,10 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We downloadFileWithPermissionCheck() } Command.DesktopMode -> { - webView.settings.userAgentString = userAgentProvider.getUserAgent(defaultUserAgentString, desktopSiteRequested = true) + webView.settings.userAgentString = userAgentProvider.getUserAgent(desktopSiteRequested = true) } Command.MobileMode -> { - webView.settings.userAgentString = userAgentProvider.getUserAgent(defaultUserAgentString, desktopSiteRequested = false) + webView.settings.userAgentString = userAgentProvider.getUserAgent(desktopSiteRequested = false) } is Command.FindInPageCommand -> webView.findAllAsync(it.searchTerm) Command.DismissFindInPage -> webView.findAllAsync(null) @@ -416,13 +413,13 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We @SuppressLint("SetJavaScriptEnabled") private fun configureWebView() { webView = layoutInflater.inflate(R.layout.include_duckduckgo_browser_webview, webViewContainer, true).findViewById(R.id.browserWebView) as WebView - defaultUserAgentString = webView.settings.userAgentString + userAgentProvider = UserAgentProvider(webView.settings.userAgentString) webView.webViewClient = webViewClient webView.webChromeClient = webChromeClient webView.settings.apply { - userAgentString = userAgentProvider.getUserAgent(defaultUserAgentString) + userAgentString = userAgentProvider.getUserAgent() javaScriptEnabled = true domStorageEnabled = true loadWithOverviewMode = true diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt index 9bfb12dba740..a5155eea7caf 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt @@ -34,7 +34,6 @@ import com.duckduckgo.app.bookmarks.db.BookmarksDao import com.duckduckgo.app.browser.BrowserViewModel.Command.Navigate import com.duckduckgo.app.browser.LongPressHandler.RequiredAction import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter -import com.duckduckgo.app.browser.useragent.UserAgentProvider import com.duckduckgo.app.browser.useragent.isMobileSite import com.duckduckgo.app.browser.useragent.toDesktopUri import com.duckduckgo.app.global.SingleLiveEvent @@ -69,7 +68,6 @@ class BrowserViewModel( private val autoCompleteApi: AutoCompleteApi, private val appSettingsPreferencesStore: SettingsDataStore, private val longPressHandler: LongPressHandler, - private val userAgentProvider: UserAgentProvider, appConfigurationDao: AppConfigurationDao) : WebViewClientListener, ViewModel() { data class ViewState( diff --git a/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt index 42de0ae1f185..087096d908f9 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt @@ -18,7 +18,6 @@ package com.duckduckgo.app.browser.useragent import android.net.Uri import android.os.Build -import javax.inject.Inject fun Uri.isMobileSite() : Boolean = this.authority.startsWith("m.") @@ -38,13 +37,7 @@ fun Uri.toDesktopUri(): Uri { * Example Default Desktop User Agent (From Chrome): * Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36 */ -class UserAgentProvider @Inject constructor() { - - companion object { - private val WEB_KIT_REGEX = Regex("AppleWebKit/.*") - - private const val MOZILLA_PREFIX = "Mozilla/5.0" - } +class UserAgentProvider constructor(private val defaultUserAgent: String) { /** * Returns a modified UA string which omits the user's device make and model @@ -53,10 +46,10 @@ class UserAgentProvider @Inject constructor() { * * We include everything from the original UA string from AppleWebKit onwards (omitting if missing) */ - fun getUserAgent(defaultUaString: String, desktopSiteRequested: Boolean = false) : String{ + fun getUserAgent(desktopSiteRequested: Boolean = false) : String{ val platform = if(desktopSiteRequested) desktopUaPrefix() else mobileUaPrefix() - val userAgentStringSuffix = getWebKitVersionOnwards(defaultUaString, desktopSiteRequested) + val userAgentStringSuffix = getWebKitVersionOnwards(desktopSiteRequested) return "$MOZILLA_PREFIX ($platform)$userAgentStringSuffix" } @@ -65,12 +58,19 @@ class UserAgentProvider @Inject constructor() { private fun desktopUaPrefix() = "X11; Linux ${System.getProperty("os.arch")}" - private fun getWebKitVersionOnwards(defaultUaString: String, desktopSiteRequested: Boolean): String { - val matches = WEB_KIT_REGEX.find(defaultUaString) ?: return "" + private fun getWebKitVersionOnwards(desktopSiteRequested: Boolean): String { + val matches = WEB_KIT_REGEX.find(defaultUserAgent) ?: return "" var result = matches.groupValues[0] if(desktopSiteRequested) { result = result.replace(" Mobile ", " ") } return " $result" } + + companion object { + private val WEB_KIT_REGEX = Regex("AppleWebKit/.*") + + private const val MOZILLA_PREFIX = "Mozilla/5.0" + } + } \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt b/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt index 6d056b7731fd..d22ff294194e 100644 --- a/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt +++ b/app/src/main/java/com/duckduckgo/app/global/ViewModelFactory.kt @@ -25,7 +25,6 @@ import com.duckduckgo.app.browser.BrowserViewModel import com.duckduckgo.app.browser.DuckDuckGoUrlDetector import com.duckduckgo.app.browser.LongPressHandler import com.duckduckgo.app.browser.omnibar.QueryUrlConverter -import com.duckduckgo.app.browser.useragent.UserAgentProvider import com.duckduckgo.app.launch.LaunchViewModel import com.duckduckgo.app.onboarding.store.OnboardingStore import com.duckduckgo.app.onboarding.ui.OnboardingViewModel @@ -59,7 +58,6 @@ class ViewModelFactory @Inject constructor( private val bookmarksDao: BookmarksDao, private val autoCompleteApi: AutoCompleteApi, private val appSettingsPreferencesStore: SettingsDataStore, - private val userAgentProvider: UserAgentProvider, private val webViewLongPressHandler: LongPressHandler ) : ViewModelProvider.NewInstanceFactory() { @@ -90,6 +88,5 @@ class ViewModelFactory @Inject constructor( appSettingsPreferencesStore = appSettingsPreferencesStore, appConfigurationDao = appConfigurationDao, longPressHandler = webViewLongPressHandler, - userAgentProvider = userAgentProvider, autoCompleteApi = autoCompleteApi) } From f4b912461892365952c1f07b598ff35a6a811ab1 Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Mon, 26 Feb 2018 12:41:30 +0000 Subject: [PATCH 08/13] Move url checking around desktop/mobile site to UriExtension.kt --- .../duckduckgo/app/global/UriExtensionTest.kt | 26 +++++++++++++++++++ .../app/browser/BrowserViewModel.kt | 6 ++--- .../browser/userAgent/UserAgentProvider.kt | 10 ------- .../com/duckduckgo/app/global/UriExtension.kt | 11 ++++++++ 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/app/src/androidTest/java/com/duckduckgo/app/global/UriExtensionTest.kt b/app/src/androidTest/java/com/duckduckgo/app/global/UriExtensionTest.kt index 89af8f1cfa35..5737fe3b9de7 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/global/UriExtensionTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/global/UriExtensionTest.kt @@ -102,4 +102,30 @@ class UriExtensionTest { assertFalse(Uri.parse("http://example.com").hasIpHost) } + @Test + fun whenUrlStartsMDotThenIdentifiedAsMobileSite() { + assertTrue(Uri.parse("https://m.example.com").isMobileSite) + } + + @Test + fun whenUrlSubdomainEndsWithMThenNotIdentifiedAsMobileSite() { + assertFalse(Uri.parse("https://adam.example.com").isMobileSite) + } + + @Test + fun whenUrlDoesNotStartWithMDotThenNotIdentifiedAsMobileSite() { + assertFalse(Uri.parse("https://example.com").isMobileSite) + } + + @Test + fun whenConvertingMobileSiteToDesktopSiteThenMobilePrefixStripped() { + val converted = Uri.parse("https://m.example.com").toDesktopUri() + assertEquals("https://example.com", converted.toString()) + } + + @Test + fun whenConvertingDesktopSiteToDesktopSiteThenUrlUnchanged() { + val converted = Uri.parse("https://example.com").toDesktopUri() + assertEquals("https://example.com", converted.toString()) + } } diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt index a5155eea7caf..8ebbe68692d7 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt @@ -34,9 +34,9 @@ import com.duckduckgo.app.bookmarks.db.BookmarksDao import com.duckduckgo.app.browser.BrowserViewModel.Command.Navigate import com.duckduckgo.app.browser.LongPressHandler.RequiredAction import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter -import com.duckduckgo.app.browser.useragent.isMobileSite -import com.duckduckgo.app.browser.useragent.toDesktopUri import com.duckduckgo.app.global.SingleLiveEvent +import com.duckduckgo.app.global.isMobileSite +import com.duckduckgo.app.global.toDesktopUri import com.duckduckgo.app.privacymonitor.SiteMonitor import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardDao import com.duckduckgo.app.privacymonitor.db.NetworkLeaderboardEntry @@ -402,7 +402,7 @@ class BrowserViewModel( return } val url = Uri.parse(urlString) - if (desktopSiteRequested && url.isMobileSite()) { + if (desktopSiteRequested && url.isMobileSite) { val desktopUrl = url.toDesktopUri() Timber.i("Original URL $urlString - attempting $desktopUrl with desktop site UA string") command.value = Navigate(desktopUrl.toString()) diff --git a/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt index 087096d908f9..34d3e5e864b0 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/userAgent/UserAgentProvider.kt @@ -20,16 +20,6 @@ import android.net.Uri import android.os.Build -fun Uri.isMobileSite() : Boolean = this.authority.startsWith("m.") - -fun Uri.toDesktopUri(): Uri { - return if(this.isMobileSite()) { - Uri.parse(toString().replaceFirst("m.", "")) - } else { - this - } -} - /** * Example Default User Agent (From Chrome): * Mozilla/5.0 (Linux; Android 8.1.0; Nexus 6P Build/OPM3.171019.014) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36 diff --git a/app/src/main/java/com/duckduckgo/app/global/UriExtension.kt b/app/src/main/java/com/duckduckgo/app/global/UriExtension.kt index 756d7856971b..fab50c14a83b 100644 --- a/app/src/main/java/com/duckduckgo/app/global/UriExtension.kt +++ b/app/src/main/java/com/duckduckgo/app/global/UriExtension.kt @@ -45,3 +45,14 @@ val Uri.hasIpHost: Boolean val ipRegex = Regex("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$") return baseHost?.matches(ipRegex) ?: false } + +val Uri.isMobileSite: Boolean + get() = authority.startsWith("m.") + +fun Uri.toDesktopUri(): Uri { + return if (isMobileSite) { + Uri.parse(toString().replaceFirst("m.", "")) + } else { + this + } +} From aa05e11dc18a7a17e4780a9d7c72f8b530a7a54a Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Mon, 26 Feb 2018 12:41:47 +0000 Subject: [PATCH 09/13] Remove unused function --- .../com/duckduckgo/app/browser/WebViewRequestInterceptor.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/src/main/java/com/duckduckgo/app/browser/WebViewRequestInterceptor.kt b/app/src/main/java/com/duckduckgo/app/browser/WebViewRequestInterceptor.kt index 7205e641db05..c4c024fb6898 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/WebViewRequestInterceptor.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/WebViewRequestInterceptor.kt @@ -89,12 +89,6 @@ class WebViewRequestInterceptor @Inject constructor( return null } - private fun shouldStripRequestedWithHeader(request: WebResourceRequest): Boolean { - if(!request.isForMainFrame) return false - val requestedWithHeader = request.requestHeaders["X-Requested-With"] ?: request.requestHeaders["x-requested-with"] - return requestedWithHeader != "" - } - private fun shouldUpgrade(request: WebResourceRequest) = request.isForMainFrame && request.url != null && httpsUpgrader.shouldUpgrade(request.url) From d318565d5ea49a209ddb21c67e052dd141256bbb Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Tue, 27 Feb 2018 16:55:34 +0000 Subject: [PATCH 10/13] Add better support for responsive websites when toggling desktop mode --- .../duckduckgo/app/browser/BrowserViewModelTest.kt | 9 ++++----- .../com/duckduckgo/app/browser/BrowserActivity.kt | 14 ++++++++------ .../com/duckduckgo/app/browser/BrowserViewModel.kt | 12 ++++-------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt index 45bf07c80fe4..a805db07ba52 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/browser/BrowserViewModelTest.kt @@ -474,17 +474,16 @@ class BrowserViewModelTest { } @Test - fun whenUserSelectsDesktopSiteThenDesktopModeCommandIssued() { + fun whenUserSelectsDesktopSiteThenDesktopModeStateUpdated() { testee.desktopSiteModeToggled("http://example.com", desktopSiteRequested = true) verify(mockCommandObserver, Mockito.atLeastOnce()).onChanged(commandCaptor.capture()) - assertTrue(commandCaptor.allValues.contains(Command.DesktopMode)) + assertTrue(testee.viewState.value!!.isDesktopBrowsingMode) } @Test - fun whenUserSelectsMobileSiteThenMobileModeCommandIssued() { + fun whenUserSelectsMobileSiteThenMobileModeStateUpdated() { testee.desktopSiteModeToggled("http://example.com", desktopSiteRequested = false) - verify(mockCommandObserver, Mockito.atLeastOnce()).onChanged(commandCaptor.capture()) - assertTrue(commandCaptor.allValues.contains(Command.MobileMode)) + assertFalse(testee.viewState.value!!.isDesktopBrowsingMode) } @Test diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt index a80dfb2c103e..3cb874609460 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt @@ -192,12 +192,6 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We pendingFileDownload = PendingFileDownload(it.url, Environment.DIRECTORY_PICTURES) downloadFileWithPermissionCheck() } - Command.DesktopMode -> { - webView.settings.userAgentString = userAgentProvider.getUserAgent(desktopSiteRequested = true) - } - Command.MobileMode -> { - webView.settings.userAgentString = userAgentProvider.getUserAgent(desktopSiteRequested = false) - } is Command.FindInPageCommand -> webView.findAllAsync(it.searchTerm) Command.DismissFindInPage -> webView.findAllAsync(null) } @@ -234,6 +228,8 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We false -> webView.hide() } + toggleDesktopSiteMode(viewState.isDesktopBrowsingMode) + when (viewState.isLoading) { true -> pageLoadingIndicator.show() false -> pageLoadingIndicator.hide() @@ -450,6 +446,12 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We viewModel.registerWebViewListener(webViewClient, webChromeClient) } + private fun toggleDesktopSiteMode(isDesktopSiteMode: Boolean) { + webView.setInitialScale(if (isDesktopSiteMode) 100 else 0) + webView.settings.useWideViewPort = !isDesktopSiteMode + webView.settings.userAgentString = userAgentProvider.getUserAgent(desktopSiteRequested = isDesktopSiteMode) + } + private fun downloadFileWithPermissionCheck() { if (hasWriteStoragePermission()) { downloadFile() diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt index 8ebbe68692d7..81bae491dc14 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserViewModel.kt @@ -82,7 +82,9 @@ class BrowserViewModel( val canAddBookmarks: Boolean = false, val isFullScreen: Boolean = false, val autoComplete: AutoCompleteViewState = AutoCompleteViewState(), - val findInPage: FindInPage = FindInPage(canFindInPage = false) + val findInPage: FindInPage = FindInPage(canFindInPage = false), + val webViewScale: Int = 0, + val isDesktopBrowsingMode: Boolean = false ) sealed class Command { @@ -99,8 +101,6 @@ class BrowserViewModel( class DownloadImage(val url: String) : Command() class FindInPageCommand(val searchTerm: String) : Command() object DismissFindInPage : Command() - object DesktopMode: Command() - object MobileMode: Command() } /* Observable data for Activity to subscribe to */ val viewState: MutableLiveData = MutableLiveData() @@ -392,11 +392,7 @@ class BrowserViewModel( fun desktopSiteModeToggled(urlString: String?, desktopSiteRequested: Boolean) { - if (desktopSiteRequested) { - command.value = BrowserViewModel.Command.DesktopMode - } else { - command.value = BrowserViewModel.Command.MobileMode - } + viewState.value = currentViewState().copy(isDesktopBrowsingMode = desktopSiteRequested) if (urlString == null) { return From 88611089a78623b727397871e050810650599cda Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Wed, 28 Feb 2018 12:31:57 +0000 Subject: [PATCH 11/13] Tweak initial scale value up to 120 --- .../main/java/com/duckduckgo/app/browser/BrowserActivity.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt index bbbf81153984..180820939fca 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt @@ -40,6 +40,7 @@ import android.view.View.VISIBLE import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.inputmethod.EditorInfo.IME_ACTION_DONE import android.webkit.URLUtil +import android.webkit.WebSettings import android.webkit.WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE import android.webkit.WebView import android.widget.TextView @@ -424,6 +425,7 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We displayZoomControls = false mixedContentMode = MIXED_CONTENT_COMPATIBILITY_MODE setSupportZoom(true) + layoutAlgorithm =WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING } webView.setDownloadListener { url, _, _, _, _ -> @@ -447,7 +449,7 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We } private fun toggleDesktopSiteMode(isDesktopSiteMode: Boolean) { - webView.setInitialScale(if (isDesktopSiteMode) 100 else 0) + webView.setInitialScale(if (isDesktopSiteMode) 120 else 1) webView.settings.useWideViewPort = !isDesktopSiteMode webView.settings.userAgentString = userAgentProvider.getUserAgent(desktopSiteRequested = isDesktopSiteMode) } From 686c1c7baefafd75db615d81dfa4423aec62109e Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Wed, 28 Feb 2018 13:36:22 +0000 Subject: [PATCH 12/13] Remove use of `setInitialScale` which seems to do more damage than good The result of this is that some responsive sites do not present differently under desktop or mobile modes. theguardian.com/uk is one such example site where we render both modes identically (despite Chrome rendering them correctly for each) Some other responsive sites do work just fine though - arstechnica.com for example renders differently for us under desktop and mobile modes. Will revisit fixing sites like theguardian.com/uk in another task. --- .../java/com/duckduckgo/app/browser/BrowserActivity.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt index 180820939fca..13822eeb5e19 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt @@ -40,7 +40,6 @@ import android.view.View.VISIBLE import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.inputmethod.EditorInfo.IME_ACTION_DONE import android.webkit.URLUtil -import android.webkit.WebSettings import android.webkit.WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE import android.webkit.WebView import android.widget.TextView @@ -419,13 +418,10 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We userAgentString = userAgentProvider.getUserAgent() javaScriptEnabled = true domStorageEnabled = true - loadWithOverviewMode = true - useWideViewPort = true builtInZoomControls = true displayZoomControls = false mixedContentMode = MIXED_CONTENT_COMPATIBILITY_MODE setSupportZoom(true) - layoutAlgorithm =WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING } webView.setDownloadListener { url, _, _, _, _ -> @@ -449,9 +445,9 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We } private fun toggleDesktopSiteMode(isDesktopSiteMode: Boolean) { - webView.setInitialScale(if (isDesktopSiteMode) 120 else 1) - webView.settings.useWideViewPort = !isDesktopSiteMode - webView.settings.userAgentString = userAgentProvider.getUserAgent(desktopSiteRequested = isDesktopSiteMode) + webView.settings.loadWithOverviewMode = isDesktopSiteMode + webView.settings.useWideViewPort = isDesktopSiteMode + webView.settings.userAgentString = userAgentProvider.getUserAgent(isDesktopSiteMode) } private fun downloadFileWithPermissionCheck() { From aa2ad28c037182b77b5857296128767396f45e4f Mon Sep 17 00:00:00 2001 From: Craig Russell Date: Wed, 28 Feb 2018 14:48:20 +0000 Subject: [PATCH 13/13] Return `loadWithOverviewMode` and `useWideViewPort` to always be true --- .../main/java/com/duckduckgo/app/browser/BrowserActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt index 13822eeb5e19..ff31f2a846f2 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt @@ -418,6 +418,8 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We userAgentString = userAgentProvider.getUserAgent() javaScriptEnabled = true domStorageEnabled = true + loadWithOverviewMode = true + useWideViewPort = true builtInZoomControls = true displayZoomControls = false mixedContentMode = MIXED_CONTENT_COMPATIBILITY_MODE @@ -445,8 +447,6 @@ class BrowserActivity : DuckDuckGoActivity(), BookmarkDialogCreationListener, We } private fun toggleDesktopSiteMode(isDesktopSiteMode: Boolean) { - webView.settings.loadWithOverviewMode = isDesktopSiteMode - webView.settings.useWideViewPort = isDesktopSiteMode webView.settings.userAgentString = userAgentProvider.getUserAgent(isDesktopSiteMode) }