[Android] Suppress engagement notifications and promos for Origin users (#35737)
Brave Origin subscribers on Android currently receive general-engagement notifications and unbidden promo dialogs that are not tied to any Origin-disabled feature. Suppress them under the product stance that Origin users get a cleaner, promo-free experience. Surfaces gated: - RetentionNotificationPublisher: HOUR_3, HOUR_24, DAY_6, EVERY_SUNDAY, and DORMANT_USERS_DAY_14/25/40 notification fire-time. - BraveActivity: showDormantUsersEngagementDialog (cold-start and in-foreground tap paths), India ad-free callout, YouTube-in-Brave dialog. The existing getIsSubscriptionActive() pref only reflects Play Store purchases, so it misses desktop-linked subscribers. Introduce a new Java-side cached boolean BRAVE_ORIGIN_CREDENTIAL_SUMMARY_CACHED, written from two authoritative any-source signals: - fetchOrderCredentials success (primes the cache immediately on a successful Play Store purchase). - requestCredentialSummary callback (covers Play Store and desktop-linked paths; the Skus service resolves both internally). BraveActivity.finishNativeInitialization now calls requestCredentialSummary on every app start to keep the cache fresh. Resolves: https://github.com/brave/brave-browser/issues/54791
This commit is contained in:
@@ -121,6 +121,9 @@ public final class BravePreferenceKeys {
|
||||
|
||||
public static final String SEARCH_CHOICE_SCREEN_INSTALL = "search_choice_screen_install";
|
||||
|
||||
public static final String BRAVE_ORIGIN_CREDENTIAL_SUMMARY_CACHED =
|
||||
"brave_origin_credential_summary_cached";
|
||||
|
||||
/*
|
||||
* Checks if preference key is used in Brave.
|
||||
* It's no op currently. We might reconsider
|
||||
|
||||
@@ -1371,6 +1371,13 @@ public abstract class BraveActivity extends ChromeActivity
|
||||
&& !BraveVpnPolicy.isDisabledByPolicy(mTabModelProfileSupplier.get())) {
|
||||
showLinkVpnSubscriptionDialog();
|
||||
}
|
||||
if (ChromeFeatureList.isEnabled(BraveFeatureList.BRAVE_ORIGIN)) {
|
||||
// Refresh the cached Skus credential summary so sync "is Origin active" readers
|
||||
// (promo/engagement gates) see up-to-date status. Local-first; only hits the
|
||||
// backend when credentials are past their expiry window.
|
||||
BraveOriginSubscriptionPrefs.requestCredentialSummary(
|
||||
mTabModelProfileSupplier.get(), null);
|
||||
}
|
||||
if (isFirstInstall
|
||||
&& (OnboardingPrefManager.getInstance().isDormantUsersEngagementEnabled()
|
||||
|| getPackageName().equals(BraveConstants.BRAVE_PRODUCTION_PACKAGE_NAME))) {
|
||||
@@ -1394,7 +1401,8 @@ public abstract class BraveActivity extends ChromeActivity
|
||||
.readBoolean(BravePreferenceKeys.BRAVE_OPENED_YOUTUBE, false)
|
||||
|| ChromeSharedPreferences.getInstance()
|
||||
.readInt(BravePreferenceKeys.BRAVE_APP_OPEN_COUNT)
|
||||
>= 7)) {
|
||||
>= 7)
|
||||
&& !BraveOriginSubscriptionPrefs.getIsCredentialSummaryActiveCached()) {
|
||||
showAdFreeCalloutDialog();
|
||||
}
|
||||
|
||||
@@ -1455,7 +1463,8 @@ public abstract class BraveActivity extends ChromeActivity
|
||||
if (!isFirstInstall
|
||||
&& !BravePrefServiceBridge.getInstance().getPlayYTVideoInBrowserEnabled()
|
||||
&& ChromeSharedPreferences.getInstance()
|
||||
.readBoolean(BravePreferenceKeys.OPEN_YT_IN_BRAVE_DIALOG, true)) {
|
||||
.readBoolean(BravePreferenceKeys.OPEN_YT_IN_BRAVE_DIALOG, true)
|
||||
&& !BraveOriginSubscriptionPrefs.getIsCredentialSummaryActiveCached()) {
|
||||
openYtInBraveDialog();
|
||||
ChromeSharedPreferences.getInstance()
|
||||
.writeBoolean(BravePreferenceKeys.OPEN_YT_IN_BRAVE_DIALOG, false);
|
||||
@@ -2272,6 +2281,9 @@ public abstract class BraveActivity extends ChromeActivity
|
||||
}
|
||||
|
||||
public void showDormantUsersEngagementDialog(String notificationType) {
|
||||
if (BraveOriginSubscriptionPrefs.getIsCredentialSummaryActiveCached()) {
|
||||
return;
|
||||
}
|
||||
if (!BraveSetDefaultBrowserUtils.isBraveSetAsDefaultBrowser(BraveActivity.this)) {
|
||||
DormantUsersEngagementDialogFragment dormantUsersEngagementDialogFragment =
|
||||
new DormantUsersEngagementDialogFragment();
|
||||
|
||||
+40
-2
@@ -15,6 +15,7 @@ import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import org.chromium.base.BraveFeatureList;
|
||||
import org.chromium.base.BravePreferenceKeys;
|
||||
import org.chromium.base.Callback;
|
||||
import org.chromium.base.ContextUtils;
|
||||
import org.chromium.base.Log;
|
||||
@@ -32,6 +33,7 @@ import org.chromium.chrome.browser.billing.PurchaseModel;
|
||||
import org.chromium.chrome.browser.flags.ChromeFeatureList;
|
||||
import org.chromium.chrome.browser.policy.BravePolicyConstants;
|
||||
import org.chromium.chrome.browser.preferences.BravePref;
|
||||
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
|
||||
import org.chromium.chrome.browser.profiles.Profile;
|
||||
import org.chromium.chrome.browser.settings.BraveOriginPreferences;
|
||||
import org.chromium.chrome.browser.settings.SettingsNavigationFactory;
|
||||
@@ -166,10 +168,17 @@ public class BraveOriginSubscriptionPrefs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Origin subscription active status for the given profile.
|
||||
* Gets the Play Store Origin subscription active status for the given profile.
|
||||
*
|
||||
* <p>Note: this only reflects Play Store purchases recorded in {@code
|
||||
* BRAVE_ORIGIN_SUBSCRIPTION_ACTIVE_ANDROID} by the in-app billing callback. Users whose Origin
|
||||
* subscription was purchased on desktop and linked via their Brave account will read as
|
||||
* inactive here. For an any-source sync check suitable for UI gating, call {@link
|
||||
* #getIsCredentialSummaryActiveCached}. For the authoritative fresh value, call {@link
|
||||
* #requestCredentialSummary} (async, via the Skus mojo service).
|
||||
*
|
||||
* @param profile The profile to use for preference retrieval
|
||||
* @return The subscription active status, or false if profile is null
|
||||
* @return The Play Store subscription active status, or false if profile is null
|
||||
*/
|
||||
public static boolean getIsSubscriptionActive(@Nullable Profile profile) {
|
||||
if (profile == null) {
|
||||
@@ -379,6 +388,10 @@ public class BraveOriginSubscriptionPrefs {
|
||||
// Store the order ID
|
||||
UserPrefs.get(profile)
|
||||
.setString(BravePref.BRAVE_ORIGIN_ORDER_ID_ANDROID, orderId);
|
||||
// A successful Play Store order fetch is an authoritative "Origin is
|
||||
// active" signal; prime the sync cache immediately so promo gates honor
|
||||
// it without waiting for the next credential summary refresh.
|
||||
setIsCredentialSummaryActiveCached(true);
|
||||
success = true;
|
||||
} finally {
|
||||
skusService.close();
|
||||
@@ -429,6 +442,7 @@ public class BraveOriginSubscriptionPrefs {
|
||||
PostTask.postTask(
|
||||
TaskTraits.UI_DEFAULT,
|
||||
() -> {
|
||||
setIsCredentialSummaryActiveCached(isActive);
|
||||
if (callback != null) {
|
||||
callback.onResult(isActive);
|
||||
}
|
||||
@@ -440,6 +454,30 @@ public class BraveOriginSubscriptionPrefs {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the authoritative any-source Origin active status returned by the most recent {@link
|
||||
* #requestCredentialSummary} callback. Unlike the Play-Store-only {@link
|
||||
* #getIsSubscriptionActive}, the Skus credential summary covers both Play Store purchases and
|
||||
* desktop-linked subscriptions, so this cache is the correct source for sync "is Origin active"
|
||||
* gating on Android.
|
||||
*/
|
||||
private static void setIsCredentialSummaryActiveCached(boolean value) {
|
||||
ChromeSharedPreferences.getInstance()
|
||||
.writeBoolean(BravePreferenceKeys.BRAVE_ORIGIN_CREDENTIAL_SUMMARY_CACHED, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous "is Origin effectively active" check for UI-thread gating of promo surfaces.
|
||||
* Returns the value written by the most recent {@link #requestCredentialSummary} callback, or
|
||||
* false if no refresh has run yet. Callers that need the authoritative fresh value should call
|
||||
* {@link #requestCredentialSummary} directly; this getter is intended for hot paths that need a
|
||||
* cheap sync answer and tolerate state as of the last refresh.
|
||||
*/
|
||||
public static boolean getIsCredentialSummaryActiveCached() {
|
||||
return ChromeSharedPreferences.getInstance()
|
||||
.readBoolean(BravePreferenceKeys.BRAVE_ORIGIN_CREDENTIAL_SUMMARY_CACHED, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the credential summary result on a background thread. This avoids potential UI
|
||||
* blocking for JSON parsing operations.
|
||||
|
||||
+10
-2
@@ -17,6 +17,7 @@ import org.chromium.base.ThreadUtils;
|
||||
import org.chromium.base.task.AsyncTask;
|
||||
import org.chromium.chrome.browser.BraveRewardsNativeWorker;
|
||||
import org.chromium.chrome.browser.app.BraveActivity;
|
||||
import org.chromium.chrome.browser.brave_origin.BraveOriginSubscriptionPrefs;
|
||||
import org.chromium.chrome.browser.onboarding.OnboardingPrefManager;
|
||||
import org.chromium.chrome.browser.set_default_browser.BraveSetDefaultBrowserUtils;
|
||||
import org.chromium.chrome.browser.tab.TabLaunchType;
|
||||
@@ -84,7 +85,9 @@ public class RetentionNotificationPublisher extends BroadcastReceiver {
|
||||
case RetentionNotificationUtil.HOUR_3:
|
||||
case RetentionNotificationUtil.HOUR_24:
|
||||
case RetentionNotificationUtil.DAY_6:
|
||||
createNotification(context, intent);
|
||||
if (!BraveOriginSubscriptionPrefs.getIsCredentialSummaryActiveCached()) {
|
||||
createNotification(context, intent);
|
||||
}
|
||||
break;
|
||||
case RetentionNotificationUtil.DAY_10:
|
||||
case RetentionNotificationUtil.DAY_30:
|
||||
@@ -107,13 +110,18 @@ public class RetentionNotificationPublisher extends BroadcastReceiver {
|
||||
}
|
||||
break;
|
||||
case RetentionNotificationUtil.EVERY_SUNDAY:
|
||||
if (OnboardingPrefManager.getInstance().isBraveStatsNotificationEnabled()) {
|
||||
if (OnboardingPrefManager.getInstance().isBraveStatsNotificationEnabled()
|
||||
&& !BraveOriginSubscriptionPrefs
|
||||
.getIsCredentialSummaryActiveCached()) {
|
||||
createNotification(context, intent);
|
||||
}
|
||||
break;
|
||||
case RetentionNotificationUtil.DORMANT_USERS_DAY_14:
|
||||
case RetentionNotificationUtil.DORMANT_USERS_DAY_25:
|
||||
case RetentionNotificationUtil.DORMANT_USERS_DAY_40:
|
||||
if (BraveOriginSubscriptionPrefs.getIsCredentialSummaryActiveCached()) {
|
||||
break;
|
||||
}
|
||||
if (System.currentTimeMillis()
|
||||
> OnboardingPrefManager.getInstance()
|
||||
.getDormantUsersNotificationTime(notificationType)
|
||||
|
||||
Reference in New Issue
Block a user