From ffa0fdf6002ec2ecb1b4a725292541adc0cb5f24 Mon Sep 17 00:00:00 2001 From: iorgamgabriel Date: Thu, 15 Sep 2022 13:48:15 +0300 Subject: [PATCH] For #7506 promote search widget dialog --- .experimenter.yaml | 9 +- app/metrics.yaml | 50 +++++ .../EnhancedTrackingProtectionSettingsTest.kt | 1 + .../focus/activity/EraseBrowsingDataTest.kt | 2 + .../focus/activity/SafeBrowsingTest.kt | 1 + .../org/mozilla/focus/activity/SearchTest.kt | 1 + .../focus/activity/SettingsAdvancedTest.kt | 1 + .../mozilla/focus/activity/ShortcutsTest.kt | 1 + .../focus/activity/SitePermissionsTest.kt | 1 + .../mozilla/focus/activity/WebControlsTest.kt | 1 + .../focus/helpers/FeatureSettingsHelper.kt | 8 + .../focus/privacy/LocalSessionStorageTest.kt | 1 + .../focus/fragment/UrlInputFragment.kt | 9 +- .../navigation/MainActivityNavigation.kt | 46 +++- .../PromoteSearchWidgetDialogCompose.kt | 201 ++++++++++++++++++ .../searchwidget/SearchWidgetProvider.kt | 8 + .../focus/searchwidget/SearchWidgetUtils.kt | 68 ++++++ .../java/org/mozilla/focus/state/AppAction.kt | 5 + .../org/mozilla/focus/state/AppReducer.kt | 8 + .../java/org/mozilla/focus/state/AppState.kt | 2 + .../org/mozilla/focus/ui/theme/FocusColors.kt | 1 + .../org/mozilla/focus/ui/theme/FocusTheme.kt | 2 + .../mozilla/focus/ui/theme/FocusTypography.kt | 6 + .../java/org/mozilla/focus/utils/Settings.kt | 17 ++ .../focus_search_widget_promote_dialog.png | Bin 0 -> 29857 bytes .../focus_search_widget_promote_dialog.png | Bin 0 -> 29279 bytes app/src/main/res/values-night/colors.xml | 5 + app/src/main/res/values/colors.xml | 4 + app/src/main/res/values/preference_keys.xml | 1 + app/src/main/res/values/strings.xml | 37 +++- nimbus.fml.yaml | 11 + 31 files changed, 488 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/org/mozilla/focus/searchwidget/PromoteSearchWidgetDialogCompose.kt create mode 100644 app/src/main/java/org/mozilla/focus/searchwidget/SearchWidgetUtils.kt create mode 100644 app/src/main/res/drawable-hdpi/focus_search_widget_promote_dialog.png create mode 100644 app/src/main/res/drawable-night-hdpi/focus_search_widget_promote_dialog.png diff --git a/.experimenter.yaml b/.experimenter.yaml index 7b7ec1f3902..b6f673e38d4 100644 --- a/.experimenter.yaml +++ b/.experimenter.yaml @@ -10,11 +10,6 @@ onboarding: is-enabled: type: boolean description: "If `true`, the app will show the new onboarding screen" -tabs: - description: Nimbus feature name intended to control the multiple tabs feature in the app. - hasExposure: true - exposureDescription: "" - variables: - is_multi_tab: + is-promote-search-widget-dialog-enabled: type: boolean - description: "Nimbus variable of [FEATURE_TABS] allowing outside control of whether the multiple tabs feature should be enabled or not." + description: "If `true`, the app will show the new dialog for promote search widget" diff --git a/app/metrics.yaml b/app/metrics.yaml index 36b2c9008b0..7116c2922b2 100644 --- a/app/metrics.yaml +++ b/app/metrics.yaml @@ -1997,3 +1997,53 @@ search_widget: metadata: tags: - Search + promote_dialog_shown: + type: event + description: | + Promote search widget dialog is shown to the user. + bugs: + - https://github.com/mozilla-mobile/focus-android/issues/7506 + data_reviews: + - https://github.com/mozilla-mobile/focus-android/pull/ + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 119 + metadata: + tags: + - Search + add_to_home_screen_button: + type: event + description: | + The user has pressed on add search widget + to home screen button from promote dialog. + bugs: + - https://github.com/mozilla-mobile/focus-android/issues/7506 + data_reviews: + - https://github.com/mozilla-mobile/focus-android/pull/ + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 119 + metadata: + tags: + - Search + widget_was_added: + type: event + description: | + The user has added successfully the search widget from + promote search widget dialog. + bugs: + - https://github.com/mozilla-mobile/focus-android/issues/7506 + data_reviews: + - https://github.com/mozilla-mobile/focus-android/pull/ + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 119 + metadata: + tags: + - Search diff --git a/app/src/androidTest/java/org/mozilla/focus/activity/EnhancedTrackingProtectionSettingsTest.kt b/app/src/androidTest/java/org/mozilla/focus/activity/EnhancedTrackingProtectionSettingsTest.kt index e0f2db69580..d6f46c62d92 100644 --- a/app/src/androidTest/java/org/mozilla/focus/activity/EnhancedTrackingProtectionSettingsTest.kt +++ b/app/src/androidTest/java/org/mozilla/focus/activity/EnhancedTrackingProtectionSettingsTest.kt @@ -46,6 +46,7 @@ class EnhancedTrackingProtectionSettingsTest { dispatcher = MockWebServerHelper.AndroidAssetDispatcher() start() } + featureSettingsHelper.setSearchWidgetDialogEnabled(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/focus/activity/EraseBrowsingDataTest.kt b/app/src/androidTest/java/org/mozilla/focus/activity/EraseBrowsingDataTest.kt index 0492a3bafc1..931beb2cdfe 100644 --- a/app/src/androidTest/java/org/mozilla/focus/activity/EraseBrowsingDataTest.kt +++ b/app/src/androidTest/java/org/mozilla/focus/activity/EraseBrowsingDataTest.kt @@ -52,6 +52,7 @@ class EraseBrowsingDataTest { start() } featureSettingsHelper.setCfrForTrackingProtectionEnabled(false) + featureSettingsHelper.setSearchWidgetDialogEnabled(false) } @After @@ -60,6 +61,7 @@ class EraseBrowsingDataTest { featureSettingsHelper.resetAllFeatureFlags() } + @Ignore("https://github.com/mozilla-mobile/focus-android/issues/7695") @SmokeTest @Test fun trashButtonTest() { diff --git a/app/src/androidTest/java/org/mozilla/focus/activity/SafeBrowsingTest.kt b/app/src/androidTest/java/org/mozilla/focus/activity/SafeBrowsingTest.kt index 1daa8d4f7df..4843da7d242 100644 --- a/app/src/androidTest/java/org/mozilla/focus/activity/SafeBrowsingTest.kt +++ b/app/src/androidTest/java/org/mozilla/focus/activity/SafeBrowsingTest.kt @@ -35,6 +35,7 @@ class SafeBrowsingTest { @Before fun setUp() { featureSettingsHelper.setCfrForTrackingProtectionEnabled(false) + featureSettingsHelper.setSearchWidgetDialogEnabled(false) webServer = MockWebServer().apply { dispatcher = MockWebServerHelper.AndroidAssetDispatcher() start() diff --git a/app/src/androidTest/java/org/mozilla/focus/activity/SearchTest.kt b/app/src/androidTest/java/org/mozilla/focus/activity/SearchTest.kt index 1d6434c3662..b58756521ba 100644 --- a/app/src/androidTest/java/org/mozilla/focus/activity/SearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/focus/activity/SearchTest.kt @@ -29,6 +29,7 @@ class SearchTest { @Before fun setUp() { featureSettingsHelper.setCfrForTrackingProtectionEnabled(false) + featureSettingsHelper.setSearchWidgetDialogEnabled(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/focus/activity/SettingsAdvancedTest.kt b/app/src/androidTest/java/org/mozilla/focus/activity/SettingsAdvancedTest.kt index f9b8cc83276..d0cedb10cf1 100644 --- a/app/src/androidTest/java/org/mozilla/focus/activity/SettingsAdvancedTest.kt +++ b/app/src/androidTest/java/org/mozilla/focus/activity/SettingsAdvancedTest.kt @@ -36,6 +36,7 @@ class SettingsAdvancedTest { start() } featureSettingsHelper.setCfrForTrackingProtectionEnabled(false) + featureSettingsHelper.setSearchWidgetDialogEnabled(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/focus/activity/ShortcutsTest.kt b/app/src/androidTest/java/org/mozilla/focus/activity/ShortcutsTest.kt index 81c9d55b049..e8b30d09544 100644 --- a/app/src/androidTest/java/org/mozilla/focus/activity/ShortcutsTest.kt +++ b/app/src/androidTest/java/org/mozilla/focus/activity/ShortcutsTest.kt @@ -30,6 +30,7 @@ class ShortcutsTest { @Before fun setUp() { featureSettingsHelper.setCfrForTrackingProtectionEnabled(false) + featureSettingsHelper.setSearchWidgetDialogEnabled(false) webServer = MockWebServer().apply { dispatcher = MockWebServerHelper.AndroidAssetDispatcher() start() diff --git a/app/src/androidTest/java/org/mozilla/focus/activity/SitePermissionsTest.kt b/app/src/androidTest/java/org/mozilla/focus/activity/SitePermissionsTest.kt index ab75730c4d8..79345cc3766 100644 --- a/app/src/androidTest/java/org/mozilla/focus/activity/SitePermissionsTest.kt +++ b/app/src/androidTest/java/org/mozilla/focus/activity/SitePermissionsTest.kt @@ -52,6 +52,7 @@ class SitePermissionsTest { @Before fun setUp() { featureSettingsHelper.setCfrForTrackingProtectionEnabled(false) + featureSettingsHelper.setSearchWidgetDialogEnabled(false) webServer = MockWebServer().apply { dispatcher = MockWebServerHelper.AndroidAssetDispatcher() start() diff --git a/app/src/androidTest/java/org/mozilla/focus/activity/WebControlsTest.kt b/app/src/androidTest/java/org/mozilla/focus/activity/WebControlsTest.kt index e1aba47ee67..373fea858ab 100644 --- a/app/src/androidTest/java/org/mozilla/focus/activity/WebControlsTest.kt +++ b/app/src/androidTest/java/org/mozilla/focus/activity/WebControlsTest.kt @@ -44,6 +44,7 @@ class WebControlsTest { start() } featureSettingsHelper.setCfrForTrackingProtectionEnabled(false) + featureSettingsHelper.setSearchWidgetDialogEnabled(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/focus/helpers/FeatureSettingsHelper.kt b/app/src/androidTest/java/org/mozilla/focus/helpers/FeatureSettingsHelper.kt index 513181a3e21..be7da05b919 100644 --- a/app/src/androidTest/java/org/mozilla/focus/helpers/FeatureSettingsHelper.kt +++ b/app/src/androidTest/java/org/mozilla/focus/helpers/FeatureSettingsHelper.kt @@ -19,6 +19,14 @@ class FeatureSettingsHelper { settings.shouldShowCfrForTrackingProtection = enabled } + fun setSearchWidgetDialogEnabled(enabled: Boolean) { + if (enabled) { + settings.addClearBrowsingSessions(4) + } else { + settings.addClearBrowsingSessions(10) + } + } + // Important: // Use this after each test if you have modified these feature settings // to make sure the app goes back to the default state diff --git a/app/src/androidTest/java/org/mozilla/focus/privacy/LocalSessionStorageTest.kt b/app/src/androidTest/java/org/mozilla/focus/privacy/LocalSessionStorageTest.kt index 36897ea51bc..839f90f9242 100644 --- a/app/src/androidTest/java/org/mozilla/focus/privacy/LocalSessionStorageTest.kt +++ b/app/src/androidTest/java/org/mozilla/focus/privacy/LocalSessionStorageTest.kt @@ -42,6 +42,7 @@ class LocalSessionStorageTest { start() } featureSettingsHelper.setCfrForTrackingProtectionEnabled(false) + featureSettingsHelper.setSearchWidgetDialogEnabled(false) } @After diff --git a/app/src/main/java/org/mozilla/focus/fragment/UrlInputFragment.kt b/app/src/main/java/org/mozilla/focus/fragment/UrlInputFragment.kt index 1cfd968ea5a..fefa19ca324 100644 --- a/app/src/main/java/org/mozilla/focus/fragment/UrlInputFragment.kt +++ b/app/src/main/java/org/mozilla/focus/fragment/UrlInputFragment.kt @@ -196,6 +196,14 @@ class UrlInputFragment : binding.browserToolbar.editMode() isInitialized = true } + + if ( + requireComponents.settings.searchWidgetInstalled && + requireComponents.appStore.state.showSearchWidgetSnackbar + ) { + ViewUtils.showBrandedSnackbar(view, R.string.promote_search_widget_snackbar_message, 0) + requireComponents.appStore.dispatch(AppAction.ShowSearchWidgetSnackBar(false)) + } } override fun onPause() { @@ -240,7 +248,6 @@ class UrlInputFragment : TopSitesOverlay() } } - return binding.root } diff --git a/app/src/main/java/org/mozilla/focus/navigation/MainActivityNavigation.kt b/app/src/main/java/org/mozilla/focus/navigation/MainActivityNavigation.kt index 1965a4cbfff..9354dfb7dc5 100644 --- a/app/src/main/java/org/mozilla/focus/navigation/MainActivityNavigation.kt +++ b/app/src/main/java/org/mozilla/focus/navigation/MainActivityNavigation.kt @@ -5,6 +5,7 @@ package org.mozilla.focus.navigation import android.os.Build +import org.mozilla.experiments.nimbus.internal.FeatureHolder import org.mozilla.focus.R import org.mozilla.focus.activity.MainActivity import org.mozilla.focus.autocomplete.AutocompleteAddFragment @@ -14,6 +15,7 @@ import org.mozilla.focus.autocomplete.AutocompleteSettingsFragment import org.mozilla.focus.biometrics.BiometricAuthenticationFragment import org.mozilla.focus.exceptions.ExceptionsListFragment import org.mozilla.focus.exceptions.ExceptionsRemoveFragment +import org.mozilla.focus.ext.components import org.mozilla.focus.fragment.BrowserFragment import org.mozilla.focus.fragment.FirstrunFragment import org.mozilla.focus.fragment.UrlInputFragment @@ -24,6 +26,8 @@ import org.mozilla.focus.fragment.onboarding.OnboardingStep import org.mozilla.focus.fragment.onboarding.OnboardingStorage import org.mozilla.focus.locale.screen.LanguageFragment import org.mozilla.focus.nimbus.FocusNimbus +import org.mozilla.focus.nimbus.Onboarding +import org.mozilla.focus.searchwidget.SearchWidgetUtils import org.mozilla.focus.settings.GeneralSettingsFragment import org.mozilla.focus.settings.InstalledSearchEnginesSettingsFragment import org.mozilla.focus.settings.ManualAddSearchEngineSettingsFragment @@ -59,12 +63,19 @@ class MainActivityNavigation( val isShowingBrowser = browserFragment != null val crashReporterIsVisible = browserFragment?.crashReporterIsVisible() ?: false + val onboardingFeature = FocusNimbus.features.onboarding + val onboardingConfig = onboardingFeature.value(activity) + if (isShowingBrowser && !crashReporterIsVisible) { - ViewUtils.showBrandedSnackbar( - activity.findViewById(android.R.id.content), - R.string.feedback_erase2, - activity.resources.getInteger(R.integer.erase_snackbar_delay), - ) + if (onboardingConfig.isPromoteSearchWidgetDialogEnabled) { + showPromoteSearchWidgetDialog(onboardingFeature) + } else { + ViewUtils.showBrandedSnackbar( + activity.findViewById(android.R.id.content), + R.string.feedback_erase2, + activity.resources.getInteger(R.integer.erase_snackbar_delay), + ) + } } // We add the url input fragment to the layout if it doesn't exist yet. @@ -88,10 +99,33 @@ class MainActivityNavigation( // Ideally we'd make it possible to pause observers while the app is in the background: // https://github.com/mozilla-mobile/android-components/issues/876 transaction - .replace(R.id.container, UrlInputFragment.createWithoutSession(), UrlInputFragment.FRAGMENT_TAG) + .replace( + R.id.container, + UrlInputFragment.createWithoutSession(), + UrlInputFragment.FRAGMENT_TAG, + ) .commitAllowingStateLoss() } + /** + * Display the widget promo at first data clearing action and if it wasn't added after 5th Focus session. + */ + @Suppress("MagicNumber") + private fun showPromoteSearchWidgetDialog(onboardingFeature: FeatureHolder) { + if (!activity.components.settings.searchWidgetInstalled) { + val clearBrowsingSessions = activity.components.settings.getClearBrowsingSessions() + activity.components.settings.addClearBrowsingSessions(1) + onboardingFeature.recordExposure() + + if ( + clearBrowsingSessions == 0 || + clearBrowsingSessions == 4 + ) { + SearchWidgetUtils.showPromoteSearchWidgetDialog(activity) + } + } + } + /** * Show browser for tab with the given [tabId]. */ diff --git a/app/src/main/java/org/mozilla/focus/searchwidget/PromoteSearchWidgetDialogCompose.kt b/app/src/main/java/org/mozilla/focus/searchwidget/PromoteSearchWidgetDialogCompose.kt new file mode 100644 index 00000000000..3a3c7af0ff1 --- /dev/null +++ b/app/src/main/java/org/mozilla/focus/searchwidget/PromoteSearchWidgetDialogCompose.kt @@ -0,0 +1,201 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.focus.searchwidget + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import androidx.constraintlayout.compose.ConstraintLayout +import mozilla.components.ui.colors.PhotonColors +import org.mozilla.focus.R +import org.mozilla.focus.ui.theme.FocusTheme +import org.mozilla.focus.ui.theme.focusColors +import org.mozilla.focus.ui.theme.focusTypography + +@Composable +@Preview +private fun PromoteSearchWidgetDialogComposePreview() { + FocusTheme { + PromoteSearchWidgetDialogCompose({}, {}) + } +} + +@Suppress("LongMethod") +@Composable +fun PromoteSearchWidgetDialogCompose( + onAddSearchWidgetButtonClick: () -> Unit, + onDismiss: () -> Unit, +) { + val openDialog = remember { mutableStateOf(true) } + if (openDialog.value) { + Dialog( + onDismissRequest = { + onDismiss() + }, + DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = false), + ) { + Column( + modifier = Modifier + .clip(RoundedCornerShape(20.dp)), + ) { + ConstraintLayout( + modifier = Modifier + .wrapContentSize() + .background( + colorResource(id = R.color.promote_search_widget_dialog_background), + ), + ) { + val (closeButton, content) = createRefs() + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(top = 8.dp, end = 16.dp) + .constrainAs(closeButton) { + top.linkTo(parent.top) + start.linkTo(parent.start) + end.linkTo(parent.end) + }, + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.End, + ) { + CloseButton(openDialog, onDismiss) + } + Column( + modifier = Modifier.constrainAs(content) { + top.linkTo(closeButton.bottom) + start.linkTo(parent.start) + end.linkTo(parent.end) + }, + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = stringResource( + id = R.string.promote_search_widget_dialog_title, + ), + modifier = Modifier + .padding(16.dp), + color = focusColors.dialogTextColor, + textAlign = TextAlign.Center, + style = focusTypography.dialogTitle, + ) + Text( + text = stringResource( + id = R.string.promote_search_widget_dialog_subtitle, + LocalContext.current.getString(R.string.onboarding_short_app_name), + ), + modifier = Modifier + .padding(top = 16.dp, start = 16.dp, end = 16.dp), + color = focusColors.dialogTextColor, + textAlign = TextAlign.Center, + style = focusTypography.dialogContent, + ) + Image( + painter = painterResource(R.drawable.focus_search_widget_promote_dialog), + contentDescription = LocalContext.current.getString( + R.string.promote_search_widget_dialog_picture_content_description, + ), + modifier = Modifier + .fillMaxWidth() + .padding(start = 10.dp, end = 10.dp) + .background( + colorResource(id = R.color.promote_search_widget_dialog_background), + ), + ) + ComponentAddWidgetButton({ onAddSearchWidgetButtonClick() }, { onDismiss() }, openDialog) + } + } + } + } + } +} + +@Composable +private fun ComponentAddWidgetButton( + onAddSearchWidgetButtonClick: () -> Unit, + onDismiss: () -> Unit, + openState: MutableState, +) { + Button( + onClick = { + openState.value = false + onAddSearchWidgetButtonClick() + onDismiss() + }, + modifier = Modifier + .fillMaxWidth() + .padding(24.dp), + shape = RoundedCornerShape(8.dp), + colors = ButtonDefaults.textButtonColors( + backgroundColor = colorResource(R.color.promote_search_widget_dialog_add_widget_button_background), + ), + ) { + Text( + text = AnnotatedString( + LocalContext.current.resources.getString( + R.string.promote_search_widget_button_text, + ), + ), + color = PhotonColors.White, + ) + } +} + +@Composable +private fun CloseButton( + openState: MutableState, + onDismiss: () -> Unit, +) { + IconButton( + onClick = { + onDismiss() + openState.value = false + }, + modifier = Modifier + .background( + colorResource(id = R.color.promote_search_widget_dialog_close_button_background), + shape = CircleShape, + ) + .size(48.dp) + .padding(10.dp), + ) { + Icon( + painter = painterResource(R.drawable.mozac_ic_close), + contentDescription = stringResource(id = R.string.promote_search_widget_dialog_content_description), + tint = focusColors.closeIcon, + ) + } +} diff --git a/app/src/main/java/org/mozilla/focus/searchwidget/SearchWidgetProvider.kt b/app/src/main/java/org/mozilla/focus/searchwidget/SearchWidgetProvider.kt index 5618b0efa2e..3f9894bac3f 100644 --- a/app/src/main/java/org/mozilla/focus/searchwidget/SearchWidgetProvider.kt +++ b/app/src/main/java/org/mozilla/focus/searchwidget/SearchWidgetProvider.kt @@ -15,11 +15,19 @@ import mozilla.components.support.utils.PendingIntentUtils import org.mozilla.focus.R import org.mozilla.focus.activity.IntentReceiverActivity import org.mozilla.focus.ext.components +import org.mozilla.focus.session.VisibilityLifeCycleCallback +import org.mozilla.focus.state.AppAction class SearchWidgetProvider : AppSearchWidgetProvider() { override fun onEnabled(context: Context) { context.components.settings.addSearchWidgetInstalled(1) + + // The snackBar that informs the user that search widget was added successfully + // should appear only if the app is in foreground + if (!VisibilityLifeCycleCallback.isInBackground(context)) { + context.components.appStore.dispatch(AppAction.ShowSearchWidgetSnackBar(true)) + } } override fun onDeleted(context: Context, appWidgetIds: IntArray) { diff --git a/app/src/main/java/org/mozilla/focus/searchwidget/SearchWidgetUtils.kt b/app/src/main/java/org/mozilla/focus/searchwidget/SearchWidgetUtils.kt new file mode 100644 index 00000000000..32d62bc3100 --- /dev/null +++ b/app/src/main/java/org/mozilla/focus/searchwidget/SearchWidgetUtils.kt @@ -0,0 +1,68 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.focus.searchwidget + +import android.app.Activity +import android.app.Dialog +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.content.ComponentName +import android.content.Intent +import android.os.Build +import android.os.Bundle +import androidx.compose.ui.platform.ComposeView +import androidx.lifecycle.ViewTreeLifecycleOwner +import androidx.savedstate.setViewTreeSavedStateRegistryOwner +import mozilla.components.support.utils.PendingIntentUtils +import org.mozilla.focus.activity.MainActivity +import org.mozilla.focus.ui.theme.FocusTheme + +object SearchWidgetUtils { + + private fun addSearchWidgetToHomeScreen(activity: Activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val appWidgetManager = AppWidgetManager.getInstance(activity) + val searchWidgetProvider = ComponentName(activity, SearchWidgetProvider::class.java) + if (appWidgetManager!!.isRequestPinAppWidgetSupported) { + val pinnedWidgetCallbackIntent = Intent(activity, SearchWidgetProvider::class.java) + val successCallback = PendingIntent.getBroadcast( + activity, + 0, + pinnedWidgetCallbackIntent, + PendingIntentUtils.defaultFlags or + PendingIntent.FLAG_UPDATE_CURRENT, + ) + appWidgetManager.requestPinAppWidget(searchWidgetProvider, Bundle(), successCallback) + } + } + } + + /** + * Shows promote search widget dialog + */ + fun showPromoteSearchWidgetDialog(activity: MainActivity) { + val promoteSearchWidgetDialog = Dialog(activity) + promoteSearchWidgetDialog.apply { + setContentView( + ComposeView(activity).apply { + ViewTreeLifecycleOwner.set(this, activity) + this.setViewTreeSavedStateRegistryOwner(activity) + setContent { + FocusTheme { + PromoteSearchWidgetDialogCompose( + onAddSearchWidgetButtonClick = { + addSearchWidgetToHomeScreen(activity) + }, + onDismiss = { + promoteSearchWidgetDialog.dismiss() + }, + ) + } + } + }, + ) + }.show() + } +} diff --git a/app/src/main/java/org/mozilla/focus/state/AppAction.kt b/app/src/main/java/org/mozilla/focus/state/AppAction.kt index 7be763242ce..8c10edf6467 100644 --- a/app/src/main/java/org/mozilla/focus/state/AppAction.kt +++ b/app/src/main/java/org/mozilla/focus/state/AppAction.kt @@ -105,4 +105,9 @@ sealed class AppAction : Action { * State of show Tracking Protection CFR has changed */ data class ShowTrackingProtectionCfrChange(val value: Map) : AppAction() + + /** + * State of Snackbar for promote search widget has changed + */ + data class ShowSearchWidgetSnackBar(val value: Boolean) : AppAction() } diff --git a/app/src/main/java/org/mozilla/focus/state/AppReducer.kt b/app/src/main/java/org/mozilla/focus/state/AppReducer.kt index e9a4d737399..6f27b018a25 100644 --- a/app/src/main/java/org/mozilla/focus/state/AppReducer.kt +++ b/app/src/main/java/org/mozilla/focus/state/AppReducer.kt @@ -39,6 +39,7 @@ object AppReducer : Reducer { is AppAction.OpenSitePermissionOptionsScreen -> openSitePermissionOptionsScreen(state, action) is AppAction.ShowHomeScreen -> showHomeScreen(state) is AppAction.ShowOnboardingSecondScreen -> showOnBoardingSecondScreen(state) + is AppAction.ShowSearchWidgetSnackBar -> showSearchWidgetSnackBarChanged(state, action) } } } @@ -186,6 +187,13 @@ private fun showEraseTabsCfrChanged(state: AppState, action: AppAction.ShowErase return state.copy(showEraseTabsCfr = action.value) } +/** + * The state of search widget snackBar changed + */ +private fun showSearchWidgetSnackBarChanged(state: AppState, action: AppAction.ShowSearchWidgetSnackBar): AppState { + return state.copy(showSearchWidgetSnackbar = action.value) +} + /** * The state of tracking protection CFR changed */ diff --git a/app/src/main/java/org/mozilla/focus/state/AppState.kt b/app/src/main/java/org/mozilla/focus/state/AppState.kt index 95d9929bab7..df8dc26df37 100644 --- a/app/src/main/java/org/mozilla/focus/state/AppState.kt +++ b/app/src/main/java/org/mozilla/focus/state/AppState.kt @@ -18,6 +18,7 @@ import java.util.UUID * whether they have been updated or not * @property secretSettingsEnabled A flag which reflects the state of debug secret settings * @property showEraseTabsCfr A flag which reflects the state erase tabs CFR + * @property showSearchWidgetSnackbar A flag which reflects the state of search widget snackbar */ data class AppState( val screen: Screen, @@ -25,6 +26,7 @@ data class AppState( val sitePermissionOptionChange: Boolean = false, val secretSettingsEnabled: Boolean = false, val showEraseTabsCfr: Boolean = false, + val showSearchWidgetSnackbar: Boolean = false, val showTrackingProtectionCfrForTab: Map = emptyMap(), ) : State diff --git a/app/src/main/java/org/mozilla/focus/ui/theme/FocusColors.kt b/app/src/main/java/org/mozilla/focus/ui/theme/FocusColors.kt index 3ecdc84cc1b..1ee24060161 100644 --- a/app/src/main/java/org/mozilla/focus/ui/theme/FocusColors.kt +++ b/app/src/main/java/org/mozilla/focus/ui/theme/FocusColors.kt @@ -31,6 +31,7 @@ data class FocusColors( val settingsTextColor: Color, val settingsTextSummaryColor: Color, val closeIcon: Color, + val dialogTextColor: Color, ) { val primary: Color get() = material.primary val primaryVariant: Color get() = material.primaryVariant diff --git a/app/src/main/java/org/mozilla/focus/ui/theme/FocusTheme.kt b/app/src/main/java/org/mozilla/focus/ui/theme/FocusTheme.kt index 85c47556471..bbc7609c16e 100644 --- a/app/src/main/java/org/mozilla/focus/ui/theme/FocusTheme.kt +++ b/app/src/main/java/org/mozilla/focus/ui/theme/FocusTheme.kt @@ -81,6 +81,7 @@ private fun darkColorPalette(): FocusColors = FocusColors( settingsTextColor = PhotonColors.White, settingsTextSummaryColor = PhotonColors.LightGrey50, closeIcon = PhotonColors.LightGrey70, + dialogTextColor = PhotonColors.White, ) private fun lightColorPalette(): FocusColors = FocusColors( @@ -103,6 +104,7 @@ private fun lightColorPalette(): FocusColors = FocusColors( onboardingSemiBoldText = PhotonColors.DarkGrey90, onboardingNormalText = PhotonColors.DarkGrey05, closeIcon = PhotonColors.LightGrey90, + dialogTextColor = PhotonColors.Black, ) /** diff --git a/app/src/main/java/org/mozilla/focus/ui/theme/FocusTypography.kt b/app/src/main/java/org/mozilla/focus/ui/theme/FocusTypography.kt index b6de757e084..055d8f4627a 100644 --- a/app/src/main/java/org/mozilla/focus/ui/theme/FocusTypography.kt +++ b/app/src/main/java/org/mozilla/focus/ui/theme/FocusTypography.kt @@ -32,6 +32,7 @@ data class FocusTypography( val links: TextStyle, val dialogTitle: TextStyle, val dialogInput: TextStyle, + val dialogContent: TextStyle, val onboardingTitle: TextStyle, val onboardingSubtitle: TextStyle, val onboardingDescription: TextStyle, @@ -79,6 +80,11 @@ val focusTypography: FocusTypography fontSize = 20.sp, color = focusColors.onPrimary, ), + dialogContent = TextStyle( + fontFamily = metropolis, + fontWeight = FontWeight.Normal, + fontSize = 14.sp, + ), onboardingTitle = TextStyle( fontFamily = metropolis, fontWeight = FontWeight.SemiBold, diff --git a/app/src/main/java/org/mozilla/focus/utils/Settings.kt b/app/src/main/java/org/mozilla/focus/utils/Settings.kt index ca47c42a8c2..b4c060516bb 100644 --- a/app/src/main/java/org/mozilla/focus/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/focus/utils/Settings.kt @@ -386,6 +386,23 @@ class Settings( 0, ) + /** + * This is used for promote search widget dialog to appear only at the first data clearing and + * at the 5th one. + */ + fun addClearBrowsingSessions(count: Int) { + val key = getPreferenceKey(R.string.pref_key_clear_browsing_sessions) + val newValue = preferences.getInt(key, 0) + count + preferences.edit() + .putInt(key, newValue) + .apply() + } + + fun getClearBrowsingSessions() = preferences.getInt( + getPreferenceKey(R.string.pref_key_clear_browsing_sessions), + 0, + ) + fun getHttpsOnlyMode(): Engine.HttpsOnlyMode { return if (preferences.getBoolean(getPreferenceKey(R.string.pref_key_https_only), true)) { Engine.HttpsOnlyMode.ENABLED diff --git a/app/src/main/res/drawable-hdpi/focus_search_widget_promote_dialog.png b/app/src/main/res/drawable-hdpi/focus_search_widget_promote_dialog.png new file mode 100644 index 0000000000000000000000000000000000000000..e785788998b4ede980529e2130cba4fb569b2faf GIT binary patch literal 29857 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�Wv&mIEWl#j{{ikl7?5lO^r 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 9c62a692028..bb95f57a28b 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -135,4 +135,9 @@ #3C286A #21163E #1D1133 + + + #2B2A33 + #3B3C3F + #7542E5 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 1ef84afce26..8dc71f8581b 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -142,4 +142,8 @@ #D9D3F5 #D6C9EB + + #FFFFFF + #F2F2F7 + #312A64 diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml index aa17d9a31ea..63e85d9463a 100644 --- a/app/src/main/res/values/preference_keys.xml +++ b/app/src/main/res/values/preference_keys.xml @@ -70,6 +70,7 @@ security_category pref_key_search_widget_installed + pref_key_clear_browsing_sessions pref_screen_exceptions diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1e54ea1fe97..0fb3142aafc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -470,7 +470,8 @@ Welcome to %1$s! - !-- Content description (not visible, for screen readers etc.): This is the description for the close button from the new onboarding flow screen one and two --> + !-- Content description (not visible, for screen readers etc.): This is the description for the + close button from the new onboarding flow screen one and two --> Close @@ -508,22 +509,22 @@ - %s is a privacy-first browser with extra-strong tracking and cookie protection built in. + %s is a privacy-first browser with extra-strong tracking and cookie protection built in. Browse like it never happened - One tap erases your browsing history and cookies — and stops ads from following you around. + One tap erases your browsing history and cookies — and stops ads from following you around. - Privacy that fits any situation + Privacy that fits any situation - If your browsing needs change, it’s easy to scale your privacy settings up or down. + If your browsing needs change, it’s easy to scale your privacy settings up or down. - Start browsing + Start browsing Power up your privacy @@ -992,4 +993,28 @@ The new line here must be kept as the second half of the string is clickable for Get rid of your personal data, browsing history and more from this session by tapping the trash button. Give it a try! Tap here to trash it all — history, cookies, everything — and start fresh on a new tab. + + + !-- Content description (not visible, for screen readers etc.): This is the description for the + close button from promote search widget dialog. --> + Close + + !-- Content description (not visible, for screen readers etc.): This is the description for + picture of search widget from promote search widget dialog. --> + Search widget + + !-- This is the title of promote search widget dialog. --> + Browsing history cleared! 🎉 + + !-- This is the subtitle of promote search widget dialog. %1$s will get replaced with the name + of the app (e.g. "Focus") --> + We’ll leave you to your private browsing, but get a quicker start next time with the %1$s widget on your Home screen. + + !-- This is te text from add search widget to home screen button .The button is located on + promote search widget dialog. --> + Add widget to home screen + + !-- This is te text of the snackbar that appears after the search widget was added successfully + to the home screen. --> + Widget added to home screen diff --git a/nimbus.fml.yaml b/nimbus.fml.yaml index bd471feb912..d0f0c3d97a5 100644 --- a/nimbus.fml.yaml +++ b/nimbus.fml.yaml @@ -20,6 +20,17 @@ features: description: If `true`, the app will show the cfrs type: Boolean default: false + is-promote-search-widget-dialog-enabled: + description: If `true`, the app will show the new dialog for promote search widget + type: Boolean + default: false + defaults: + - channel: debug + value: { + "is-enabled": true, + "is-cfr-enabled": true, + "is-promote-search-widget-dialog-enabled": true, + } types: objects: { } enums: { }