diff --git a/.gitignore b/.gitignore index 0717ae63c95a..81b8084c4792 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,7 @@ captures/ fastlane/report.xml # Bitrise configuration -bitrise.yml \ No newline at end of file +bitrise.yml + +# NDK files +**/.cxx \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ce7198ec2070..8fe5ed44476f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -78,12 +78,12 @@ android { ext { androidX = "1.0.2" - materialDesign = "1.0.0" + materialDesign = "1.1.0-alpha05" architectureComponents = "1.1.1" architectureComponentsExtensions = "1.1.1" androidKtx = "1.0.1" fragmentKtx = "1.0.0" - constraintLayout = "2.0.0-alpha3" + constraintLayout = "2.0.0-beta1" lifecycle = "2.1.0-alpha04" room = "2.1.0-alpha05" workManager = "2.0.0" diff --git a/app/src/androidTest/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModelTest.kt b/app/src/androidTest/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModelTest.kt index 29e740656b78..537552def615 100644 --- a/app/src/androidTest/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModelTest.kt +++ b/app/src/androidTest/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModelTest.kt @@ -17,14 +17,14 @@ package com.duckduckgo.app.onboarding.ui import androidx.arch.core.executor.testing.InstantTaskExecutorRule +import com.duckduckgo.app.browser.R import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector import com.duckduckgo.app.onboarding.store.OnboardingStore import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import org.junit.Assert.assertNull -import org.junit.Assert.assertTrue +import org.junit.Assert.* import org.junit.Rule import org.junit.Test @@ -50,29 +50,79 @@ class OnboardingViewModelTest { } @Test - fun whenFirstPageRequestedThenProtectDataReturned() { - val page = testee.getItem(0) - assertTrue(page is OnboardingPageFragment.ProtectDataPage) + fun whenFreshInstallFirstPageRequestedThenUnifiedWelcomePageReturned() { + val page = testee.getItem(0, isFreshAppInstall = true) + assertTrue(page is OnboardingPageFragment.UnifiedWelcomePage) } @Test - fun whenSecondPageRequestedThenNoTracePageReturned() { - val page = testee.getItem(1) - assertTrue(page is OnboardingPageFragment.NoTracePage) + fun whenNotFreshInstallFirstPageRequestedThenUnifiedWelcomePageReturned() { + val page = testee.getItem(0, isFreshAppInstall = false) + assertTrue(page is OnboardingPageFragment.UnifiedWelcomePage) } @Test - fun whenThirdPageRequestedWithDefaultBrowserCapableThenDefaultBrowserPageReturned() { - whenever(mockDefaultBrowserDetector.deviceSupportsDefaultBrowserConfiguration()).thenReturn(true) - val page = testee.getItem(2) + fun whenFreshInstallSecondPageRequestedWithDefaultBrowserCapableThenDefaultBrowserPageReturned() { + configureDeviceSupportsDefaultBrowser() + val page = testee.getItem(1, isFreshAppInstall = true) assertTrue(page is OnboardingPageFragment.DefaultBrowserPage) } @Test - fun whenThirdPageRequestedButDefaultBrowserNotCapableThenNoPageReturned() { - whenever(mockDefaultBrowserDetector.deviceSupportsDefaultBrowserConfiguration()).thenReturn(false) - val page = testee.getItem(2) + fun whenNotFreshInstallSecondPageRequestedWithDefaultBrowserCapableThenNoPageReturned() { + configureDeviceSupportsDefaultBrowser() + val page = testee.getItem(1, isFreshAppInstall = false) + assertNull(page) + } + + @Test + fun whenFreshInstallSecondPageRequestedButDefaultBrowserNotCapableThenNoPageReturned() { + configureDeviceDoesNotSupportDefaultBrowser() + val page = testee.getItem(1, isFreshAppInstall = true) + assertNull(page) + } + + @Test + fun whenNotFreshInstallSecondPageRequestedButDefaultBrowserNotCapableThenNoPageReturned() { + configureDeviceDoesNotSupportDefaultBrowser() + val page = testee.getItem(1, isFreshAppInstall = false) assertNull(page) } + @Test + fun whenDefaultBrowserSupportedThenFirstPageShowsContinueTextOnButton() { + configureDeviceSupportsDefaultBrowser() + val resourceId = testee.getContinueButtonTextResourceId(0, isFreshAppInstall = true) + assertEquals(R.string.onboardingContinue, resourceId) + } + + @Test + fun whenFreshInstallDefaultBrowserNotSupportedThenFirstPageShowsFinalTextOnButton() { + configureDeviceDoesNotSupportDefaultBrowser() + val resourceId = testee.getContinueButtonTextResourceId(0, isFreshAppInstall = true) + assertEquals(R.string.onboardingContinueFinalPage, resourceId) + } + + @Test + fun whenNotFreshInstallDefaultBrowserSupportedThenFirstPageShowsBackTextOnButton() { + configureDeviceSupportsDefaultBrowser() + val resourceId = testee.getContinueButtonTextResourceId(0, isFreshAppInstall = false) + assertEquals(R.string.onboardingBackButton, resourceId) + } + + @Test + fun whenNotFreshInstallDefaultBrowserNotSupportedThenFirstPageShowsBackTextOnButton() { + configureDeviceDoesNotSupportDefaultBrowser() + val resourceId = testee.getContinueButtonTextResourceId(0, isFreshAppInstall = false) + assertEquals(R.string.onboardingBackButton, resourceId) + } + + private fun configureDeviceSupportsDefaultBrowser() { + whenever(mockDefaultBrowserDetector.deviceSupportsDefaultBrowserConfiguration()).thenReturn(true) + } + + private fun configureDeviceDoesNotSupportDefaultBrowser() { + whenever(mockDefaultBrowserDetector.deviceSupportsDefaultBrowserConfiguration()).thenReturn(false) + } + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d045c6bfb9e9..a2a7c1493696 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -132,9 +132,6 @@ - diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt index ba75e618721f..c329b0d28c77 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt @@ -503,11 +503,12 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope { } private fun showAuthenticationDialog(request: BasicAuthenticationRequest) { - val dialog = HttpAuthenticationDialogFragment.createHttpAuthenticationDialog(request.site) - - dialog.show(activity?.supportFragmentManager, AUTHENTICATION_DIALOG_TAG) - dialog.listener = viewModel - dialog.request = request + activity?.supportFragmentManager?.let { fragmentManager -> + val dialog = HttpAuthenticationDialogFragment.createHttpAuthenticationDialog(request.site) + dialog.show(fragmentManager, AUTHENTICATION_DIALOG_TAG) + dialog.listener = viewModel + dialog.request = request + } } private fun saveBasicAuthCredentials(request: BasicAuthenticationRequest, credentials: BasicAuthenticationCredentials) { diff --git a/app/src/main/java/com/duckduckgo/app/browser/defaultbrowsing/DefaultBrowserInfoActivity.kt b/app/src/main/java/com/duckduckgo/app/browser/defaultbrowsing/DefaultBrowserInfoActivity.kt deleted file mode 100644 index 448a388c5ce5..000000000000 --- a/app/src/main/java/com/duckduckgo/app/browser/defaultbrowsing/DefaultBrowserInfoActivity.kt +++ /dev/null @@ -1,99 +0,0 @@ -/* - * 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.defaultbrowsing - -import android.annotation.TargetApi -import android.content.ActivityNotFoundException -import android.content.Context -import android.content.Intent -import android.os.Build -import android.os.Bundle -import android.provider.Settings -import android.widget.Toast -import androidx.annotation.RequiresApi -import com.duckduckgo.app.browser.R -import com.duckduckgo.app.global.DuckDuckGoActivity -import kotlinx.android.synthetic.main.activity_default_browser_info.* -import timber.log.Timber -import javax.inject.Inject - -class DefaultBrowserInfoActivity : DuckDuckGoActivity() { - - @Inject - lateinit var defaultBrowserDetector: DefaultBrowserDetector - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_default_browser_info) - configureUiEventHandlers() - } - - @TargetApi(Build.VERSION_CODES.N) - private fun configureUiEventHandlers() { - dismissButton.setOnClickListener { exitActivity() } - launchSettingsButton.setOnClickListener { launchDefaultAppActivityForResult() } - defaultBrowserIllustration.setOnClickListener { launchDefaultAppActivityForResult() } - } - - @RequiresApi(Build.VERSION_CODES.N) - private fun launchDefaultAppActivityForResult() { - try { - val intent = Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS) - startActivityForResult(intent, DEFAULT_BROWSER_REQUEST_CODE) - } catch (e: ActivityNotFoundException) { - val errorMessage = getString(R.string.cannotLaunchDefaultAppSettings) - Timber.w(e, errorMessage) - Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT).show() - } - } - - override fun onResume() { - super.onResume() - - if (defaultBrowserDetector.isDefaultBrowser()) { - finish() - } - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - when (requestCode) { - DEFAULT_BROWSER_REQUEST_CODE -> { - val wasSet = if (defaultBrowserDetector.isDefaultBrowser()) "was" else "was not" - Timber.i("User returned from default settings; DDG $wasSet set as the default") - } - else -> super.onActivityResult(requestCode, resultCode, data) - } - } - - override fun onBackPressed() { - exitActivity() - } - - private fun exitActivity() { - launchSettingsButton.text = "" - finishAfterTransition() - } - - companion object { - - private const val DEFAULT_BROWSER_REQUEST_CODE = 100 - - fun intent(context: Context): Intent { - return Intent(context, DefaultBrowserInfoActivity::class.java) - } - } -} diff --git a/app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt b/app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt index 4d076e3dd80e..4bdc402bad7d 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/di/BrowserModule.kt @@ -22,9 +22,9 @@ import android.webkit.CookieManager import com.duckduckgo.app.browser.* import com.duckduckgo.app.browser.addtohome.AddToHomeCapabilityDetector import com.duckduckgo.app.browser.addtohome.AddToHomeSystemCapabilityDetector -import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserObserver import com.duckduckgo.app.browser.defaultbrowsing.AndroidDefaultBrowserDetector import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector +import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserObserver import com.duckduckgo.app.browser.session.WebViewSessionInMemoryStorage import com.duckduckgo.app.browser.session.WebViewSessionStorage import com.duckduckgo.app.fire.DuckDuckGoCookieManager diff --git a/app/src/main/java/com/duckduckgo/app/di/AndroidBindingModule.kt b/app/src/main/java/com/duckduckgo/app/di/AndroidBindingModule.kt index 6f6f33a650f4..8238a491ba30 100644 --- a/app/src/main/java/com/duckduckgo/app/di/AndroidBindingModule.kt +++ b/app/src/main/java/com/duckduckgo/app/di/AndroidBindingModule.kt @@ -21,7 +21,6 @@ import com.duckduckgo.app.bookmarks.ui.BookmarksActivity import com.duckduckgo.app.brokensite.BrokenSiteActivity import com.duckduckgo.app.browser.BrowserActivity import com.duckduckgo.app.browser.BrowserTabFragment -import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserInfoActivity import com.duckduckgo.app.browser.rating.ui.AppEnjoymentDialogFragment import com.duckduckgo.app.browser.rating.ui.GiveFeedbackDialogFragment import com.duckduckgo.app.browser.rating.ui.RateAppDialogFragment @@ -111,10 +110,6 @@ abstract class AndroidBindingModule { @ContributesAndroidInjector abstract fun bookmarksActivity(): BookmarksActivity - @ActivityScoped - @ContributesAndroidInjector - abstract fun defaultBrowserInfoActivity(): DefaultBrowserInfoActivity - @ActivityScoped @ContributesAndroidInjector abstract fun fireActivity(): FireActivity diff --git a/app/src/main/java/com/duckduckgo/app/launch/LaunchActivity.kt b/app/src/main/java/com/duckduckgo/app/launch/LaunchActivity.kt index e8d16c38b438..f3b4feb518d4 100644 --- a/app/src/main/java/com/duckduckgo/app/launch/LaunchActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/launch/LaunchActivity.kt @@ -16,8 +16,8 @@ package com.duckduckgo.app.launch -import androidx.lifecycle.Observer import android.os.Bundle +import androidx.lifecycle.Observer import com.duckduckgo.app.browser.BrowserActivity import com.duckduckgo.app.browser.R import com.duckduckgo.app.global.DuckDuckGoActivity @@ -55,7 +55,7 @@ class LaunchActivity : DuckDuckGoActivity() { startActivity(BrowserActivity.intent(this)) if (showOnboarding) { - startActivity(OnboardingActivity.intent(this)) + startActivity(OnboardingActivity.intent(this, isFreshAppInstall = true)) } finish() diff --git a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingActivity.kt b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingActivity.kt index 23a93fb9263c..0980bfa168f2 100644 --- a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingActivity.kt @@ -19,7 +19,6 @@ package com.duckduckgo.app.onboarding.ui import android.content.Context import android.content.Intent import android.os.Bundle -import android.view.View import androidx.annotation.ColorInt import androidx.core.content.ContextCompat import com.duckduckgo.app.browser.R @@ -42,7 +41,7 @@ class OnboardingActivity : DuckDuckGoActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_onboarding) - configurePager() + configurePager(intent.getBooleanExtra(IS_FRESH_INSTALL_EXTRA, true)) } override fun onResume() { @@ -50,7 +49,7 @@ class OnboardingActivity : DuckDuckGoActivity() { super.onResume() } - fun onContinueClicked(view: View) { + fun onContinueClicked() { val next = viewPager.currentItem + 1 if (next < viewPager.adapter!!.count) { viewPager.setCurrentItem(next, true) @@ -60,9 +59,9 @@ class OnboardingActivity : DuckDuckGoActivity() { } } - private fun configurePager() { + private fun configurePager(isFreshAppInstall: Boolean) { - viewPageAdapter = PagerAdapter(supportFragmentManager, viewModel) + viewPageAdapter = PagerAdapter(supportFragmentManager, viewModel, isFreshAppInstall) viewPager.adapter = viewPageAdapter val pageListener = ColorChangingPageListener(colorCombiner, object : NewColorListener { override fun update(@ColorInt color: Int) = updateColor(color) @@ -80,8 +79,13 @@ class OnboardingActivity : DuckDuckGoActivity() { } companion object { - fun intent(context: Context): Intent { - return Intent(context, OnboardingActivity::class.java) + + private const val IS_FRESH_INSTALL_EXTRA = "IS_FRESH_INSTALL_EXTRA" + + fun intent(context: Context, isFreshAppInstall: Boolean): Intent { + val intent = Intent(context, OnboardingActivity::class.java) + intent.putExtra(IS_FRESH_INSTALL_EXTRA, isFreshAppInstall) + return intent } } } \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingPageFragment.kt b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingPageFragment.kt index 0f600b63831a..ebd54c9c61a6 100644 --- a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingPageFragment.kt +++ b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingPageFragment.kt @@ -26,6 +26,7 @@ import android.view.View import android.view.ViewGroup import androidx.annotation.ColorRes import androidx.annotation.LayoutRes +import androidx.annotation.StringRes import androidx.fragment.app.Fragment import com.duckduckgo.app.browser.R import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector @@ -35,6 +36,8 @@ import com.duckduckgo.app.statistics.pixels.Pixel import com.duckduckgo.app.statistics.pixels.Pixel.PixelName.* import dagger.android.support.AndroidSupportInjection import kotlinx.android.synthetic.main.content_onboarding_default_browser.* +import kotlinx.android.synthetic.main.content_onboarding_default_browser.continueButton +import kotlinx.android.synthetic.main.content_onboarding_unified_welcome.* import timber.log.Timber import javax.inject.Inject @@ -46,25 +49,65 @@ sealed class OnboardingPageFragment : Fragment() { @LayoutRes abstract fun layoutResource(): Int - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? = inflater.inflate(layoutResource(), container, false) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = + inflater.inflate(layoutResource(), container, false) - class ProtectDataPage : OnboardingPageFragment() { - override fun layoutResource(): Int = R.layout.content_onboarding_protect_data - override fun backgroundColor(): Int = R.color.lightOliveGreen + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + + val continueButtonText = extractContinueButtonTextResourceId() + continueButton.setText(continueButtonText) } - class NoTracePage : OnboardingPageFragment() { - override fun layoutResource(): Int = R.layout.content_onboarding_no_trace - override fun backgroundColor(): Int = R.color.cornflowerBlue + private fun extractContinueButtonTextResourceId() = + arguments?.getInt(CONTINUE_BUTTON_TEXT_RESOURCE_ID_EXTRA, R.string.onboardingContinue) ?: R.string.onboardingContinue + + fun onContinuePressed() { + val onboardingActivity = activity as OnboardingActivity + onboardingActivity.onContinueClicked() + } + + companion object { + private const val CONTINUE_BUTTON_TEXT_RESOURCE_ID_EXTRA = "CONTINUE_BUTTON_TEXT_RESOURCE_ID_EXTRA" + private const val TITLE_TEXT_RESOURCE_ID_EXTRA = "TITLE_TEXT_RESOURCE_ID_EXTRA" + } + + class UnifiedWelcomePage : OnboardingPageFragment() { + override fun layoutResource(): Int = R.layout.content_onboarding_unified_welcome + override fun backgroundColor(): Int = R.color.white + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + + val titleText = extractTitleText() + title.setText(titleText) + + continueButton.setOnClickListener { onContinuePressed() } + } + + @StringRes + private fun extractTitleText(): Int { + return arguments?.getInt(TITLE_TEXT_RESOURCE_ID_EXTRA, R.string.unifiedOnboardingTitleFirstVisit) + ?: R.string.unifiedOnboardingTitleFirstVisit + } + + companion object { + + fun instance(@StringRes continueButtonTextResourceId: Int, @StringRes titleResourceId: Int): UnifiedWelcomePage { + val bundle = Bundle() + bundle.putInt(CONTINUE_BUTTON_TEXT_RESOURCE_ID_EXTRA, continueButtonTextResourceId) + bundle.putInt(TITLE_TEXT_RESOURCE_ID_EXTRA, titleResourceId) + + val fragment = UnifiedWelcomePage() + fragment.arguments = bundle + return fragment + } + } } class DefaultBrowserPage : OnboardingPageFragment() { override fun layoutResource(): Int = R.layout.content_onboarding_default_browser - override fun backgroundColor(): Int = R.color.eastBay + override fun backgroundColor(): Int = R.color.white @Inject lateinit var pixel: Pixel @@ -75,6 +118,8 @@ sealed class OnboardingPageFragment : Fragment() { @Inject lateinit var defaultBrowserDetector: DefaultBrowserDetector + private var userLaunchedDefaultBrowserSettings = false + override fun onAttach(context: Context) { AndroidSupportInjection.inject(this) super.onAttach(context) @@ -82,10 +127,31 @@ sealed class OnboardingPageFragment : Fragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) - launchSettingsButton.setOnClickListener { onLaunchDefaultBrowserSettingsClicked() } + + if (savedInstanceState != null) { + userLaunchedDefaultBrowserSettings = savedInstanceState.getBoolean(SAVED_STATE_LAUNCHED_SETTINGS) + } + + launchSettingsButton.setOnClickListener { + onLaunchDefaultBrowserSettingsClicked() + } + continueButton.setOnClickListener { + if (!userLaunchedDefaultBrowserSettings) { + pixel.fire(ONBOARDING_DEFAULT_BROWSER_SKIPPED) + } + onContinuePressed() + } + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + + outState.putBoolean(SAVED_STATE_LAUNCHED_SETTINGS, userLaunchedDefaultBrowserSettings) } private fun onLaunchDefaultBrowserSettingsClicked() { + userLaunchedDefaultBrowserSettings = true + pixel.fire(ONBOARDING_DEFAULT_BROWSER_SETTINGS_LAUNCHED) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val intent = DefaultBrowserSystemSettings.intent() try { @@ -118,6 +184,17 @@ sealed class OnboardingPageFragment : Fragment() { companion object { private const val DEFAULT_BROWSER_REQUEST_CODE = 100 + private const val SAVED_STATE_LAUNCHED_SETTINGS = "SAVED_STATE_LAUNCHED_SETTINGS" + + fun instance(@StringRes continueButtonTextResourceId: Int): DefaultBrowserPage { + val bundle = Bundle() + bundle.putInt(CONTINUE_BUTTON_TEXT_RESOURCE_ID_EXTRA, continueButtonTextResourceId) + + val fragment = DefaultBrowserPage() + fragment.arguments = bundle + return fragment + } + } } } \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModel.kt b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModel.kt index 110797a6b6ea..5f08a5d68659 100644 --- a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModel.kt +++ b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModel.kt @@ -16,7 +16,9 @@ package com.duckduckgo.app.onboarding.ui +import androidx.annotation.StringRes import androidx.lifecycle.ViewModel +import com.duckduckgo.app.browser.R import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector import com.duckduckgo.app.onboarding.store.OnboardingStore @@ -25,28 +27,58 @@ class OnboardingViewModel( private val defaultWebBrowserCapability: DefaultBrowserDetector ) : ViewModel() { - fun pageCount(): Int { - return if (shouldShowDefaultBrowserPage()) 3 else 2 + fun pageCount(isFreshAppInstall: Boolean): Int { + + // always show first welcome screen + var count = 1 + + if (shouldShowDefaultBrowserPage(isFreshAppInstall)) { + count++ + } + + return count + } + + fun getItem(position: Int, isFreshAppInstall: Boolean): OnboardingPageFragment? { + val continueButtonTextResourceId = getContinueButtonTextResourceId(position, isFreshAppInstall) + return when (position) { + 0 -> buildFragmentForFirstPage(isFreshAppInstall, continueButtonTextResourceId) + 1 -> buildFragmentForSecondPage(isFreshAppInstall, continueButtonTextResourceId) + else -> null + } } fun onOnboardingDone() { onboardingStore.onboardingShown() } - fun getItem(position: Int): OnboardingPageFragment? { - return when (position) { - 0 -> OnboardingPageFragment.ProtectDataPage() - 1 -> OnboardingPageFragment.NoTracePage() - 2 -> { - return if (shouldShowDefaultBrowserPage()) { - OnboardingPageFragment.DefaultBrowserPage() - } else null - } - else -> null + private fun buildFragmentForFirstPage(isFreshAppInstall: Boolean, continueButtonTextResourceId: Int): OnboardingPageFragment.UnifiedWelcomePage { + val titleTextResourceId = + if (isFreshAppInstall) R.string.unifiedOnboardingTitleFirstVisit else R.string.unifiedOnboardingTitleSubsequentVisits + return OnboardingPageFragment.UnifiedWelcomePage.instance(continueButtonTextResourceId, titleTextResourceId) + } + + private fun buildFragmentForSecondPage(isFreshAppInstall: Boolean, continueButtonTextResourceId: Int): OnboardingPageFragment? { + return if (shouldShowDefaultBrowserPage(isFreshAppInstall)) { + OnboardingPageFragment.DefaultBrowserPage.instance(continueButtonTextResourceId) + } else null + } + + @StringRes + fun getContinueButtonTextResourceId(position: Int, isFreshAppInstall: Boolean): Int { + if (!isFreshAppInstall) { + return R.string.onboardingBackButton + } + return if (isFinalPage(position, isFreshAppInstall)) { + R.string.onboardingContinueFinalPage + } else { + R.string.onboardingContinue } } - private fun shouldShowDefaultBrowserPage(): Boolean { - return defaultWebBrowserCapability.deviceSupportsDefaultBrowserConfiguration() + private fun isFinalPage(position: Int, isFreshAppInstall: Boolean) = position == pageCount(isFreshAppInstall) - 1 + + private fun shouldShowDefaultBrowserPage(isFreshAppInstall: Boolean): Boolean { + return isFreshAppInstall && defaultWebBrowserCapability.deviceSupportsDefaultBrowserConfiguration() } } diff --git a/app/src/main/java/com/duckduckgo/app/onboarding/ui/PagerAdapter.kt b/app/src/main/java/com/duckduckgo/app/onboarding/ui/PagerAdapter.kt index 14f20e423b2c..10eb3dbcdde5 100644 --- a/app/src/main/java/com/duckduckgo/app/onboarding/ui/PagerAdapter.kt +++ b/app/src/main/java/com/duckduckgo/app/onboarding/ui/PagerAdapter.kt @@ -22,14 +22,15 @@ import androidx.core.content.ContextCompat import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentPagerAdapter -class PagerAdapter(fragmentManager: FragmentManager, private val viewModel: OnboardingViewModel) : FragmentPagerAdapter(fragmentManager) { +class PagerAdapter(fragmentManager: FragmentManager, private val viewModel: OnboardingViewModel, private val isFreshAppInstall: Boolean) : + FragmentPagerAdapter(fragmentManager) { override fun getCount(): Int { - return viewModel.pageCount() + return viewModel.pageCount(isFreshAppInstall) } override fun getItem(position: Int): OnboardingPageFragment { - return viewModel.getItem(position) ?: throw IllegalArgumentException("No items exists at position $position") + return viewModel.getItem(position, isFreshAppInstall) ?: throw IllegalArgumentException("No items exists at position $position") } @ColorInt @@ -39,7 +40,7 @@ class PagerAdapter(fragmentManager: FragmentManager, private val viewModel: Onbo } fun backgroundColor(position: Int): Int? { - val item = viewModel.getItem(position) ?: return null + val item = viewModel.getItem(position, isFreshAppInstall) ?: return null return item.backgroundColor() } } \ No newline at end of file diff --git a/app/src/main/java/com/duckduckgo/app/settings/SettingsActivity.kt b/app/src/main/java/com/duckduckgo/app/settings/SettingsActivity.kt index fbfb43226c27..e070fd78f742 100644 --- a/app/src/main/java/com/duckduckgo/app/settings/SettingsActivity.kt +++ b/app/src/main/java/com/duckduckgo/app/settings/SettingsActivity.kt @@ -79,7 +79,7 @@ class SettingsActivity : DuckDuckGoActivity(), SettingsAutomaticallyClearWhatFra } private fun configureUiEventHandlers() { - onboarding.setOnClickListener { startActivity(OnboardingActivity.intent(this)) } + onboarding.setOnClickListener { startActivity(OnboardingActivity.intent(this, isFreshAppInstall = false)) } about.setOnClickListener { startActivity(AboutDuckDuckGoActivity.intent(this)) } provideFeedback.setOnClickListener { viewModel.userRequestedToSendFeedback() } diff --git a/app/src/main/java/com/duckduckgo/app/statistics/pixels/Pixel.kt b/app/src/main/java/com/duckduckgo/app/statistics/pixels/Pixel.kt index 8f4da91fd654..5a11ce78542a 100644 --- a/app/src/main/java/com/duckduckgo/app/statistics/pixels/Pixel.kt +++ b/app/src/main/java/com/duckduckgo/app/statistics/pixels/Pixel.kt @@ -33,6 +33,9 @@ interface Pixel { APP_LAUNCH("ml"), FORGET_ALL_EXECUTED("mf"), + ONBOARDING_DEFAULT_BROWSER_SETTINGS_LAUNCHED("m_odb_l"), + ONBOARDING_DEFAULT_BROWSER_SKIPPED("m_odb_s"), + PRIVACY_DASHBOARD_OPENED("mp"), PRIVACY_DASHBOARD_SCORECARD("mp_c"), PRIVACY_DASHBOARD_ENCRYPTION("mp_e"), diff --git a/app/src/main/res/drawable-hdpi/icon_block_trackers_alt.png b/app/src/main/res/drawable-hdpi/icon_block_trackers_alt.png new file mode 100644 index 000000000000..e0973f058771 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_block_trackers_alt.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_customize.png b/app/src/main/res/drawable-hdpi/icon_customize.png new file mode 100644 index 000000000000..37b3a88adb65 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_customize.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_default_browser_illustration.png b/app/src/main/res/drawable-hdpi/icon_default_browser_illustration.png deleted file mode 100644 index 11b73776627e..000000000000 Binary files a/app/src/main/res/drawable-hdpi/icon_default_browser_illustration.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/icon_flame.png b/app/src/main/res/drawable-hdpi/icon_flame.png new file mode 100644 index 000000000000..732255e26349 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_flame.png differ diff --git a/app/src/main/res/drawable-hdpi/icon_search_privately.png b/app/src/main/res/drawable-hdpi/icon_search_privately.png new file mode 100644 index 000000000000..a014add17330 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/icon_search_privately.png differ diff --git a/app/src/main/res/drawable-hdpi/onboarding_image_default_browser.png b/app/src/main/res/drawable-hdpi/onboarding_image_default_browser.png deleted file mode 100644 index 20f763fcceb2..000000000000 Binary files a/app/src/main/res/drawable-hdpi/onboarding_image_default_browser.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/onboarding_image_no_trace.png b/app/src/main/res/drawable-hdpi/onboarding_image_no_trace.png deleted file mode 100644 index bcd43ed3e7a7..000000000000 Binary files a/app/src/main/res/drawable-hdpi/onboarding_image_no_trace.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/onboarding_image_protect_data.png b/app/src/main/res/drawable-hdpi/onboarding_image_protect_data.png deleted file mode 100644 index 463ac281ca85..000000000000 Binary files a/app/src/main/res/drawable-hdpi/onboarding_image_protect_data.png and /dev/null differ diff --git a/app/src/main/res/drawable-hdpi/set_as_default_browser_illustration.png b/app/src/main/res/drawable-hdpi/set_as_default_browser_illustration.png new file mode 100644 index 000000000000..b1b10dbe4b41 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/set_as_default_browser_illustration.png differ diff --git a/app/src/main/res/drawable-mdpi/icon_block_trackers_alt.png b/app/src/main/res/drawable-mdpi/icon_block_trackers_alt.png new file mode 100644 index 000000000000..1283023462c5 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/icon_block_trackers_alt.png differ diff --git a/app/src/main/res/drawable-mdpi/icon_customize.png b/app/src/main/res/drawable-mdpi/icon_customize.png new file mode 100644 index 000000000000..8589a6416243 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/icon_customize.png differ diff --git a/app/src/main/res/drawable-mdpi/icon_default_browser_illustration.png b/app/src/main/res/drawable-mdpi/icon_default_browser_illustration.png deleted file mode 100644 index 3dcbb64411f0..000000000000 Binary files a/app/src/main/res/drawable-mdpi/icon_default_browser_illustration.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/icon_flame.png b/app/src/main/res/drawable-mdpi/icon_flame.png new file mode 100644 index 000000000000..9c5f3e6a5dfc Binary files /dev/null and b/app/src/main/res/drawable-mdpi/icon_flame.png differ diff --git a/app/src/main/res/drawable-mdpi/icon_search_privately.png b/app/src/main/res/drawable-mdpi/icon_search_privately.png new file mode 100644 index 000000000000..5c72327640bd Binary files /dev/null and b/app/src/main/res/drawable-mdpi/icon_search_privately.png differ diff --git a/app/src/main/res/drawable-mdpi/onboarding_image_default_browser.png b/app/src/main/res/drawable-mdpi/onboarding_image_default_browser.png deleted file mode 100644 index 80bc1cc57445..000000000000 Binary files a/app/src/main/res/drawable-mdpi/onboarding_image_default_browser.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/onboarding_image_no_trace.png b/app/src/main/res/drawable-mdpi/onboarding_image_no_trace.png deleted file mode 100644 index ae4c537eddd4..000000000000 Binary files a/app/src/main/res/drawable-mdpi/onboarding_image_no_trace.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/onboarding_image_protect_data.png b/app/src/main/res/drawable-mdpi/onboarding_image_protect_data.png deleted file mode 100644 index be60abecae4b..000000000000 Binary files a/app/src/main/res/drawable-mdpi/onboarding_image_protect_data.png and /dev/null differ diff --git a/app/src/main/res/drawable-mdpi/set_as_default_browser_illustration.png b/app/src/main/res/drawable-mdpi/set_as_default_browser_illustration.png new file mode 100644 index 000000000000..e0b0f0603584 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/set_as_default_browser_illustration.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_block_trackers_alt.png b/app/src/main/res/drawable-xhdpi/icon_block_trackers_alt.png new file mode 100644 index 000000000000..f888af7df1de Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_block_trackers_alt.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_customize.png b/app/src/main/res/drawable-xhdpi/icon_customize.png new file mode 100644 index 000000000000..9ece0138214f Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_customize.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_default_browser_illustration.png b/app/src/main/res/drawable-xhdpi/icon_default_browser_illustration.png deleted file mode 100644 index ace31a23d8ac..000000000000 Binary files a/app/src/main/res/drawable-xhdpi/icon_default_browser_illustration.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/icon_flame.png b/app/src/main/res/drawable-xhdpi/icon_flame.png new file mode 100644 index 000000000000..d26a5ea5e7dc Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_flame.png differ diff --git a/app/src/main/res/drawable-xhdpi/icon_search_privately.png b/app/src/main/res/drawable-xhdpi/icon_search_privately.png new file mode 100644 index 000000000000..a267ab071003 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/icon_search_privately.png differ diff --git a/app/src/main/res/drawable-xhdpi/onboarding_image_default_browser.png b/app/src/main/res/drawable-xhdpi/onboarding_image_default_browser.png deleted file mode 100644 index cfb8d6989707..000000000000 Binary files a/app/src/main/res/drawable-xhdpi/onboarding_image_default_browser.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/onboarding_image_no_trace.png b/app/src/main/res/drawable-xhdpi/onboarding_image_no_trace.png deleted file mode 100644 index 289ca38cde33..000000000000 Binary files a/app/src/main/res/drawable-xhdpi/onboarding_image_no_trace.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/onboarding_image_protect_data.png b/app/src/main/res/drawable-xhdpi/onboarding_image_protect_data.png deleted file mode 100644 index 42e0ef33486c..000000000000 Binary files a/app/src/main/res/drawable-xhdpi/onboarding_image_protect_data.png and /dev/null differ diff --git a/app/src/main/res/drawable-xhdpi/set_as_default_browser_illustration.png b/app/src/main/res/drawable-xhdpi/set_as_default_browser_illustration.png new file mode 100644 index 000000000000..6ce3c42e1e03 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/set_as_default_browser_illustration.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_block_trackers_alt.png b/app/src/main/res/drawable-xxhdpi/icon_block_trackers_alt.png new file mode 100644 index 000000000000..ba543a6f2245 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_block_trackers_alt.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_customize.png b/app/src/main/res/drawable-xxhdpi/icon_customize.png new file mode 100644 index 000000000000..c083618701fa Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_customize.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_default_browser_illustration.png b/app/src/main/res/drawable-xxhdpi/icon_default_browser_illustration.png deleted file mode 100644 index ce3e3aeaa847..000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/icon_default_browser_illustration.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_flame.png b/app/src/main/res/drawable-xxhdpi/icon_flame.png new file mode 100644 index 000000000000..ad9368220c6c Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_flame.png differ diff --git a/app/src/main/res/drawable-xxhdpi/icon_search_privately.png b/app/src/main/res/drawable-xxhdpi/icon_search_privately.png new file mode 100644 index 000000000000..7510abe39e40 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/icon_search_privately.png differ diff --git a/app/src/main/res/drawable-xxhdpi/onboarding_image_default_browser.png b/app/src/main/res/drawable-xxhdpi/onboarding_image_default_browser.png deleted file mode 100644 index 73b43c16522a..000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/onboarding_image_default_browser.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/onboarding_image_no_trace.png b/app/src/main/res/drawable-xxhdpi/onboarding_image_no_trace.png deleted file mode 100644 index 2f849e103d4d..000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/onboarding_image_no_trace.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/onboarding_image_protect_data.png b/app/src/main/res/drawable-xxhdpi/onboarding_image_protect_data.png deleted file mode 100644 index 52339e691467..000000000000 Binary files a/app/src/main/res/drawable-xxhdpi/onboarding_image_protect_data.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxhdpi/set_as_default_browser_illustration.png b/app/src/main/res/drawable-xxhdpi/set_as_default_browser_illustration.png new file mode 100644 index 000000000000..aa2df32a4d02 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/set_as_default_browser_illustration.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_block_trackers_alt.png b/app/src/main/res/drawable-xxxhdpi/icon_block_trackers_alt.png new file mode 100644 index 000000000000..ffeba436e7c6 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_block_trackers_alt.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_customize.png b/app/src/main/res/drawable-xxxhdpi/icon_customize.png new file mode 100644 index 000000000000..9a33dd45e811 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_customize.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_default_browser_illustration.png b/app/src/main/res/drawable-xxxhdpi/icon_default_browser_illustration.png deleted file mode 100644 index 6cdb78ec1fc6..000000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/icon_default_browser_illustration.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_flame.png b/app/src/main/res/drawable-xxxhdpi/icon_flame.png new file mode 100644 index 000000000000..50baa0108a65 Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_flame.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_search_privately.png b/app/src/main/res/drawable-xxxhdpi/icon_search_privately.png new file mode 100644 index 000000000000..02cc7123f36b Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_search_privately.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/onboarding_image_default_browser.png b/app/src/main/res/drawable-xxxhdpi/onboarding_image_default_browser.png deleted file mode 100644 index dd1af736e028..000000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/onboarding_image_default_browser.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/onboarding_image_no_trace.png b/app/src/main/res/drawable-xxxhdpi/onboarding_image_no_trace.png deleted file mode 100644 index 528e234990bc..000000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/onboarding_image_no_trace.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/onboarding_image_protect_data.png b/app/src/main/res/drawable-xxxhdpi/onboarding_image_protect_data.png deleted file mode 100644 index 3706fa22a777..000000000000 Binary files a/app/src/main/res/drawable-xxxhdpi/onboarding_image_protect_data.png and /dev/null differ diff --git a/app/src/main/res/drawable-xxxhdpi/set_as_default_browser_illustration.png b/app/src/main/res/drawable-xxxhdpi/set_as_default_browser_illustration.png new file mode 100644 index 000000000000..075169aeb34d Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/set_as_default_browser_illustration.png differ diff --git a/app/src/main/res/drawable/onboarding_secondary_cta_button_outlined_bg.xml b/app/src/main/res/drawable/onboarding_secondary_cta_button_outlined_bg.xml new file mode 100644 index 000000000000..26b97c88d245 --- /dev/null +++ b/app/src/main/res/drawable/onboarding_secondary_cta_button_outlined_bg.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_default_browser_info.xml b/app/src/main/res/layout-land/activity_default_browser_info.xml deleted file mode 100644 index e456c1e3f4e0..000000000000 --- a/app/src/main/res/layout-land/activity_default_browser_info.xml +++ /dev/null @@ -1,136 +0,0 @@ - - - - - - - - - - - - - - - - -