diff --git a/android/brave_java_sources.gni b/android/brave_java_sources.gni index ef1aa285cb39..0032163f4d7c 100644 --- a/android/brave_java_sources.gni +++ b/android/brave_java_sources.gni @@ -210,6 +210,7 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/notifications/BraveNotificationWarningDialog.java", "../../brave/android/java/org/chromium/chrome/browser/notifications/BraveOnboardingNotification.java", "../../brave/android/java/org/chromium/chrome/browser/notifications/BravePermissionUtils.java", + "../../brave/android/java/org/chromium/chrome/browser/notifications/permissions/BraveNotificationPermissionRationaleDialog.java", "../../brave/android/java/org/chromium/chrome/browser/notifications/permissions/BraveNotificationPermissionRationaleDialogController.java", "../../brave/android/java/org/chromium/chrome/browser/notifications/retention/RetentionNotification.java", "../../brave/android/java/org/chromium/chrome/browser/notifications/retention/RetentionNotificationPublisher.java", diff --git a/android/java/org/chromium/chrome/browser/app/BraveActivity.java b/android/java/org/chromium/chrome/browser/app/BraveActivity.java index 49df0d51cabe..199c02dbe5ab 100644 --- a/android/java/org/chromium/chrome/browser/app/BraveActivity.java +++ b/android/java/org/chromium/chrome/browser/app/BraveActivity.java @@ -1279,10 +1279,16 @@ public void onDismiss() { }; private void checkAndshowNotificationWarningDialog() { - if (BraveNotificationWarningDialog.shouldShowNotificationWarningDialog(this) + OnboardingPrefManager.getInstance().updateLaunchCount(); + if (OnboardingPrefManager.getInstance().launchCount() >= 3 + && BraveNotificationWarningDialog.shouldShowNotificationWarningDialog(this) && !OnboardingPrefManager.getInstance() .isNotificationPermissionEnablingDialogShown()) { - showNotificationWarningDialog(); + if (BravePermissionUtils.hasNotificationPermission(this)) { + showNotificationWarningDialog(); + } else { + maybeShowNotificationPermissionRetionale(); + } OnboardingPrefManager.getInstance().setNotificationPermissionEnablingDialogShown(true); } else { checkForNotificationData(); diff --git a/android/java/org/chromium/chrome/browser/notifications/BraveNotificationWarningDialog.java b/android/java/org/chromium/chrome/browser/notifications/BraveNotificationWarningDialog.java index db5388b8f9ee..75063f17741d 100644 --- a/android/java/org/chromium/chrome/browser/notifications/BraveNotificationWarningDialog.java +++ b/android/java/org/chromium/chrome/browser/notifications/BraveNotificationWarningDialog.java @@ -22,15 +22,15 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.core.app.ActivityCompat; import androidx.core.content.res.ResourcesCompat; -import org.chromium.base.BuildInfo; import org.chromium.base.Log; import org.chromium.chrome.R; +import org.chromium.chrome.browser.BraveAdsNativeHelper; import org.chromium.chrome.browser.BraveDialogFragment; import org.chromium.chrome.browser.notifications.BravePermissionUtils; import org.chromium.chrome.browser.onboarding.OnboardingPrefManager; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.ui.permissions.PermissionConstants; /** @@ -74,17 +74,39 @@ public static BraveNotificationWarningDialog newInstance(int launchedFrom) { } /** - * If no notification permission and if any privacy or rewards state is on then return true + * Should show dialog if any one is true + * 1. No notification permission + * 2. Notification permission is there but general or ads group is blocked + * + * if above any case is there and rewards / privacy / both enabled. * */ public static boolean shouldShowNotificationWarningDialog(Context context) { - if (!BravePermissionUtils.hasPermission( - context, PermissionConstants.NOTIFICATION_PERMISSION)) { - return OnboardingPrefManager.getInstance().isBraveStatsEnabled() - || OnboardingPrefManager.getInstance().isBraveAdsEnabled(); + if (!BravePermissionUtils.hasNotificationPermission(context)) { + return true; + } else if (shouldShowRewardWarningDialog(context) + || shouldShowPrivacyWarningDialog(context)) { + return true; } return false; } + private static boolean shouldShowRewardWarningDialog(Context context) { + return BravePermissionUtils.isBraveAdsNotificationPermissionBlocked(context) + && isBraveRewardsEnabled(); + } + + private static boolean shouldShowPrivacyWarningDialog(Context context) { + return BravePermissionUtils.isGeneralNotificationPermissionBlocked(context) + && isPrivacyReportsEnabled(); + } + + private static boolean shouldShowBothWarningDialog(Context context) { + if (!BravePermissionUtils.hasNotificationPermission(context)) { + return true; + } + return shouldShowRewardWarningDialog(context) && shouldShowPrivacyWarningDialog(context); + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -117,11 +139,11 @@ private void init(View view) { clickOnNotNow(view); } - public boolean isBraveRewardsEnabled() { - return OnboardingPrefManager.getInstance().isBraveAdsEnabled(); + public static boolean isBraveRewardsEnabled() { + return BraveAdsNativeHelper.nativeIsBraveAdsEnabled(Profile.getLastUsedRegularProfile()); } - public boolean isPrivacyReportsEnabled() { + public static boolean isPrivacyReportsEnabled() { return OnboardingPrefManager.getInstance().isBraveStatsEnabled(); } @@ -155,14 +177,14 @@ private void launchedFromBravePanel(View view) { private void launchedFromBraveActivity(View view) { mPrimaryButton.setText(R.string.turn_on_brave_notifications); - if (isBraveRewardsEnabled() && isPrivacyReportsEnabled()) { + if (shouldShowBothWarningDialog(getContext())) { mTitleTextView.setText(R.string.notification_os_dialog_header_both_rewards_privacy); mDescriptionTextView.setText( R.string.notification_os_dialog_description_both_rewards_privacy); - } else if (isBraveRewardsEnabled()) { + } else if (shouldShowRewardWarningDialog(getContext())) { mTitleTextView.setText(R.string.notification_os_dialog_header_only_rewards); mDescriptionTextView.setText(R.string.notification_os_dialog_description_only_rewards); - } else if (isPrivacyReportsEnabled()) { + } else if (shouldShowPrivacyWarningDialog(getContext())) { mTitleTextView.setText(R.string.notification_os_dialog_header_only_privacy); mDescriptionTextView.setText(R.string.notification_os_dialog_description_only_privacy); } @@ -171,15 +193,15 @@ private void launchedFromBraveActivity(View view) { private void launchedFromBraveSettings(View view) { mPrimaryButton.setText(R.string.got_it); - if (isBraveRewardsEnabled() && isPrivacyReportsEnabled()) { + if (shouldShowBothWarningDialog(getContext())) { mTitleTextView.setText(R.string.notification_brave_dialog_header_both_rewards_privacy); mDescriptionTextView.setText( R.string.notification_brave_dialog_description_both_rewards_privacy); - } else if (isBraveRewardsEnabled()) { + } else if (shouldShowRewardWarningDialog(getContext())) { mTitleTextView.setText(R.string.notification_brave_dialog_header_only_rewards); mDescriptionTextView.setText( R.string.notification_brave_dialog_description_only_rewards); - } else if (isPrivacyReportsEnabled()) { + } else if (shouldShowPrivacyWarningDialog(getContext())) { mTitleTextView.setText(R.string.notification_brave_dialog_header_only_privacy); mDescriptionTextView.setText( R.string.notification_brave_dialog_description_only_privacy); @@ -190,18 +212,7 @@ private void clickOnPrimaryButton(View view) { Button primaryButton = view.findViewById(R.id.notification_warning_primary_button); primaryButton.setOnClickListener(v -> { dismiss(); - if (getActivity().shouldShowRequestPermissionRationale( - PermissionConstants.NOTIFICATION_PERMISSION) - || (!BuildInfo.isAtLeastT() || !BuildInfo.targetsAtLeastT())) { - // other than android 13 redirect to - // setting page and for android 13 Last time don't allow selected in permission - // dialog, then enable through setting - BravePermissionUtils.notificationSettingPage(getContext()); - } else { - // 1st time request permission - ActivityCompat.requestPermissions(getActivity(), - new String[] {PermissionConstants.NOTIFICATION_PERMISSION}, 1); - } + BravePermissionUtils.requestPermission(getActivity()); }); } diff --git a/android/java/org/chromium/chrome/browser/notifications/BravePermissionUtils.java b/android/java/org/chromium/chrome/browser/notifications/BravePermissionUtils.java index 059141b2c575..1a406be0ba7d 100644 --- a/android/java/org/chromium/chrome/browser/notifications/BravePermissionUtils.java +++ b/android/java/org/chromium/chrome/browser/notifications/BravePermissionUtils.java @@ -7,13 +7,23 @@ package org.chromium.chrome.browser.notifications; +import android.app.Activity; +import android.app.NotificationChannelGroup; +import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.os.Build; import android.provider.Settings; +import androidx.core.app.ActivityCompat; +import androidx.core.app.NotificationManagerCompat; import androidx.core.content.ContextCompat; +import org.chromium.base.BuildInfo; +import org.chromium.chrome.browser.notifications.channels.BraveChannelDefinitions; +import org.chromium.ui.permissions.PermissionConstants; + /** * This class is for settings permission related checks */ @@ -21,6 +31,10 @@ public class BravePermissionUtils { private static final String APP_PACKAGE = "app_package"; private static final String APP_UID = "app_uid"; + public static boolean hasNotificationPermission(Context context) { + return hasPermission(context, PermissionConstants.NOTIFICATION_PERMISSION); + } + public static Boolean hasPermission(Context context, String permission) { return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED; @@ -40,4 +54,40 @@ public static void notificationSettingPage(Context context) { context.startActivity(intent); } + + // When in OS notification permission particular group switch is off means that group is blocked + public static boolean channeGroupIsBlocked(Context context, String channelGroupName) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + NotificationManager notificationManager = + (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + NotificationChannelGroup notificationChannelGroup = + notificationManager.getNotificationChannelGroup(channelGroupName); + return notificationChannelGroup.isBlocked(); + } else { + return NotificationManagerCompat.from(context).areNotificationsEnabled(); + } + } + + public static boolean isBraveAdsNotificationPermissionBlocked(Context context) { + return channeGroupIsBlocked(context, BraveChannelDefinitions.ChannelGroupId.BRAVE_ADS); + } + + public static boolean isGeneralNotificationPermissionBlocked(Context context) { + return channeGroupIsBlocked(context, BraveChannelDefinitions.ChannelGroupId.GENERAL); + } + + public static void requestPermission(Activity activity) { + if (activity.shouldShowRequestPermissionRationale( + PermissionConstants.NOTIFICATION_PERMISSION) + || (!BuildInfo.isAtLeastT() || !BuildInfo.targetsAtLeastT())) { + // other than android 13 redirect to + // setting page and for android 13 Last time don't allow selected in permission + // dialog, then enable through setting + BravePermissionUtils.notificationSettingPage(activity); + } else { + // 1st time request permission + ActivityCompat.requestPermissions( + activity, new String[] {PermissionConstants.NOTIFICATION_PERMISSION}, 1); + } + } } diff --git a/android/java/org/chromium/chrome/browser/notifications/permissions/BraveNotificationPermissionRationaleDialog.java b/android/java/org/chromium/chrome/browser/notifications/permissions/BraveNotificationPermissionRationaleDialog.java new file mode 100644 index 000000000000..24a1537b1bf2 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/notifications/permissions/BraveNotificationPermissionRationaleDialog.java @@ -0,0 +1,60 @@ +package org.chromium.chrome.browser.notifications.permissions; + +import org.chromium.chrome.browser.BraveDialogFragment; +import android.os.Bundle; +import android.view.View; +import android.view.LayoutInflater; +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import org.chromium.chrome.R; +import android.graphics.drawable.ColorDrawable; +import android.graphics.Color; +import android.view.Window; +import android.widget.Button; +import org.chromium.chrome.browser.notifications.BravePermissionUtils; + + +public class BraveNotificationPermissionRationaleDialog extends BraveDialogFragment { + + public static BraveNotificationPermissionRationaleDialog newInstance() { + BraveNotificationPermissionRationaleDialog fragment = new BraveNotificationPermissionRationaleDialog(); + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.brave_notification_permission_rationale_dialog, container, false); + if (getDialog() != null && getDialog().getWindow() != null) { + getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); + } + return view; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + clickOnContinueButton(view); + clickOnNotNow(view); + } + + private void clickOnContinueButton(View view) { + Button primaryButton = view.findViewById(R.id.notification_continue_button); + primaryButton.setOnClickListener(v -> { + dismiss(); + BravePermissionUtils.requestPermission(getActivity()); + }); + } + + private void clickOnNotNow(View view) { + Button notNowButton = view.findViewById(R.id.notification_not_now_button); + notNowButton.setOnClickListener(v -> { dismiss(); }); + } +} diff --git a/android/java/org/chromium/chrome/browser/onboarding/OnboardingPrefManager.java b/android/java/org/chromium/chrome/browser/onboarding/OnboardingPrefManager.java index 5099bd3f20c1..a4004e13f2ae 100644 --- a/android/java/org/chromium/chrome/browser/onboarding/OnboardingPrefManager.java +++ b/android/java/org/chromium/chrome/browser/onboarding/OnboardingPrefManager.java @@ -59,6 +59,11 @@ public class OnboardingPrefManager { private static final String PREF_NOTIFICATION_PERMISSION_ENABLING_DIALOG = "notification_permission_enabling_dialog"; + private static final String PREF_NOTIFICATION_PERMISSION_ENABLING_DIALOG_FROM_SETTING = + "notification_permission_enabling_dialog_from_setting"; + + private static final String PREF_APP_LAUNCH_COUNT = "APP_LAUNCH_COUNT"; + private static OnboardingPrefManager sInstance; private final SharedPreferences mSharedPreferences; @@ -359,4 +364,40 @@ public void setNotificationPermissionEnablingDialogShown(boolean isShown) { sharedPreferencesEditor.putBoolean(PREF_NOTIFICATION_PERMISSION_ENABLING_DIALOG, isShown); sharedPreferencesEditor.apply(); } + + /** + * Returns the user preference for whether the Notification Permission Enabling dialog is shown + * From setting. + */ + public boolean isNotificationPermissionEnablingDialogShownFromSetting() { + return mSharedPreferences.getBoolean( + PREF_NOTIFICATION_PERMISSION_ENABLING_DIALOG_FROM_SETTING, false); + } + + /** + * Sets the user preference for whether the Notification Permission Enabling dialog is shown + * From setting. + */ + public void setNotificationPermissionEnablingDialogShownFromSetting(boolean isShown) { + SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); + sharedPreferencesEditor.putBoolean( + PREF_NOTIFICATION_PERMISSION_ENABLING_DIALOG_FROM_SETTING, isShown); + sharedPreferencesEditor.apply(); + } + + /** + * Returns the user preference for application launch count + */ + public int launchCount() { + return mSharedPreferences.getInt(PREF_APP_LAUNCH_COUNT, 0); + } + + /** + * Sets the user preference for application launch count + */ + public void updateLaunchCount() { + SharedPreferences.Editor sharedPreferencesEditor = mSharedPreferences.edit(); + sharedPreferencesEditor.putInt(PREF_APP_LAUNCH_COUNT, launchCount() + 1); + sharedPreferencesEditor.apply(); + } } diff --git a/android/java/org/chromium/chrome/browser/settings/BraveMainPreferencesBase.java b/android/java/org/chromium/chrome/browser/settings/BraveMainPreferencesBase.java index ef3300ab3bfd..622d004b3a95 100644 --- a/android/java/org/chromium/chrome/browser/settings/BraveMainPreferencesBase.java +++ b/android/java/org/chromium/chrome/browser/settings/BraveMainPreferencesBase.java @@ -28,8 +28,11 @@ import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.homepage.settings.BraveHomepageSettings; import org.chromium.chrome.browser.notifications.BraveNotificationWarningDialog; +import org.chromium.chrome.browser.notifications.BravePermissionUtils; +import org.chromium.chrome.browser.notifications.permissions.BraveNotificationPermissionRationaleDialog; import org.chromium.chrome.browser.ntp_background_images.NTPBackgroundImagesBridge; import org.chromium.chrome.browser.ntp_background_images.util.NTPUtil; +import org.chromium.chrome.browser.onboarding.OnboardingPrefManager; import org.chromium.chrome.browser.partnercustomizations.CloseBraveManager; import org.chromium.chrome.browser.preferences.BravePrefServiceBridge; import org.chromium.chrome.browser.privacy.settings.BravePrivacySettings; @@ -126,13 +129,28 @@ public void onResume() { // Otherwise, some prefs could be added after finishing updateBravePreferences(). new Handler().post(() -> updateBravePreferences()); if (mNotificationClicked - && BraveNotificationWarningDialog.shouldShowNotificationWarningDialog( - getActivity())) { + && BraveNotificationWarningDialog.shouldShowNotificationWarningDialog(getActivity()) + && !OnboardingPrefManager.getInstance() + .isNotificationPermissionEnablingDialogShownFromSetting()) { mNotificationClicked = false; - showNotificationWarningDialog(); + if (BravePermissionUtils.hasNotificationPermission(getActivity())) { + showNotificationWarningDialog(); + } else { + showNotificationRationale(); + } + OnboardingPrefManager.getInstance() + .setNotificationPermissionEnablingDialogShownFromSetting(true); } } + private void showNotificationRationale() { + BraveNotificationPermissionRationaleDialog notificationWarningDialog = + BraveNotificationPermissionRationaleDialog.newInstance(); + notificationWarningDialog.setCancelable(false); + notificationWarningDialog.show(getChildFragmentManager(), + BraveNotificationWarningDialog.NOTIFICATION_WARNING_DIALOG_TAG); + } + private void showNotificationWarningDialog() { BraveNotificationWarningDialog notificationWarningDialog = BraveNotificationWarningDialog.newInstance( diff --git a/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/BraveChannelDefinitions.java b/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/BraveChannelDefinitions.java index dc838edb7383..e3c2b29f518f 100644 --- a/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/BraveChannelDefinitions.java +++ b/browser/notifications/android/java/src/org/chromium/chrome/browser/notifications/channels/BraveChannelDefinitions.java @@ -26,6 +26,7 @@ public class ChannelId { public class ChannelGroupId { public static final String BRAVE_ADS = "com.brave.browser.ads"; + public static final String GENERAL = "general"; } @SuppressLint("NewApi")