100 Commits
Author SHA1 Message Date
Serg b369d9a8d9 [Android][Origin] Flush pending prefs before restart so settings survive an immediate relaunch (#37046)
Changing a setting and immediately restarting (e.g. "Restart now" on the
Brave Origin screen) could discard the change; waiting a few seconds avoided
it.

Pref writes are batched behind a timer and flushed to disk later. The Android
restart path SIGKILLs the browser process from a sibling process
(BrowserRestartActivity) with no graceful shutdown, so pending prefs are never
flushed. Whether a change survived depended on an unrelated write happening to
flush the store first, hence the intermittent, single-device reports.

Flush local_state and each loaded profile's prefs via CommitPendingWrite()
before AttemptRestart(). It is async-to-disk, a no-op when nothing is pending,
and the write is atomic.

Resolves: https://github.com/brave/brave-browser/issues/56075
2026-06-06 00:03:48 +02:00
Serg ff016732ec [Android] Prompt restart when an Origin Play Store purchase is auto-restored (#37036)
On a fresh profile with a prior Play Store Origin purchase, BraveActivity
auto-restores it at startup via verifyPurchase(). This enforces the Origin
policies (e.g. disabling Brave Wallet) live in the running session, but
unlike the in-settings purchase and the native web-purchase flows it never
prompted a restart. The browser then honours the freshly enforced policy
per navigation while already-configured renderers do not, which can leave
the two out of sync (e.g. the renderer keeps injecting window.ethereum and
requests a binder the browser no longer registers).

Open the Origin settings screen when a Play Store purchase is auto-restored,
reusing the existing fetching-spinner/restart snackbar, so the user restarts
and the policies take effect cleanly at boot. The prompt fires only on the
auto-restore transition (the subscription pref is inactive when verifyPurchase
runs); the in-settings first purchase keeps its own snackbar.

Resolves: https://github.com/brave/brave-browser/issues/56078
2026-06-05 21:45:57 +02:00
Serg 3c40cb1d47 [Android][Origin] Reclaim toolbar space when the rewards icon is hidden on tablet (#36975)
On tablet the rewards (BAT) icon lives in the brave_toolbar row, a
wrap_content LinearLayout that caches its measured width. When the icon
is hidden from onMeasure (e.g. when Brave Origin disables rewards), the
implicit requestLayout() from setVisibility() is dropped because the
toolbar is already mid-layout, so the row keeps its old width and the
weighted location bar never reclaims the freed space, leaving a gap
until a device rotation forces a fresh layout.

Route all rewards-slot visibility changes through a helper that, on an
actual change on tablet, re-requests layout on the rewards view itself
(so its row re-measures) off the measure pass, and refreshes the cached
tablet toolbar snapshot.

Resolves: https://github.com/brave/brave-browser/issues/56036
2026-06-03 19:15:36 -04:00
Serg 065cd82a2d [Android] Show restart prompt on credential-refresh Origin purchase (#36904)
When an Origin purchase is first detected via credential refresh (e.g.
linked from account.brave.com), open the Origin settings screen and show
the existing restart snackbar.

The shared first-purchase trigger in BraveOriginService::OnCredentialSummary
calls the navigation delegate, whose Android branch was previously a no-op.
It now routes through a JNI helper that opens BraveOriginPreferences with an
explicit show-restart flag, where onViewCreated shows the restart snackbar.

Play Store purchases are left to the existing Java subscription flow (which
shows the "Disabling features" spinner while credentials are fetched, then
transitions to the restart prompt). The helper skips opening when a Play
Store purchase token is present so the screen isn't opened twice.

Resolves: https://github.com/brave/brave-browser/issues/55991
2026-06-02 02:46:34 +02:00
Serg 89a6bd6f7b [Android] Surface Play in-app messages for subscription events (#36819)
Calls BillingClient.showInAppMessages on app foreground so the Play
Store can render its recovery dialog (declined payment, opt-in price
change) on top of Brave. Gated on the user having an active VPN or Leo
subscription, throttled to one call per real foreground session via an
ApplicationStatus listener that resets only on HAS_STOPPED_ACTIVITIES /
HAS_DESTROYED_ACTIVITIES — in-app navigation does not re-trigger.

Resolves: https://github.com/brave/brave-browser/issues/55735
2026-05-28 17:48:12 -04:00
Serg 2c77c7f21c [Origin] Initialize BraveOriginPolicyManager before profile builds (#36740)
`BraveOriginPolicyManager::Init` was only called lazily from
`BraveOriginServiceFactory::BuildServiceInstanceForBrowserContext`,
which runs during profile keyed-service build. Profile pref-store init
waits on `PolicyService::IsInitializationComplete`, which waits on
`BraveProfilePolicyProvider::IsInitializationComplete`, which gates on
`manager->IsInitialized()` -- and that's only flipped by the lazy call
that itself is gated on profile build. Cycle manifests as "stuck on
profile selection screen" for some users.

Initialize the manager eagerly at the end of `BraveBrowserProcessImpl::Init()`,
right next to the existing `AdBlockOnlyModePolicyManager::Init` call. The
factory's lazy `if (!IsInitialized()) Init(...)` block stays as a backstop
for tests that bypass `BraveBrowserProcessImpl`.

Resolves: https://github.com/brave/brave-browser/issues/55733
2026-05-26 19:11:06 -04:00
Serg c1241a08a7 [Origin] Brave Stats startup ping races BraveStatsPingEnabled policy (#36698)
`BraveStatsUpdater` is a browser-process singleton; its 3-second startup
timer reads `kStatsReportingEnabled` without synchronising against
`BraveOriginPolicyManager`. Make the updater observe the manager
directly and defer the timer behind a two-phase gate (referrals barrier
+ `OnBravePoliciesReady`), so the startup ping cannot fire before the
policy bundle is merged into local state.

Resolves: https://github.com/brave/brave-browser/issues/55811
2026-05-25 22:29:24 +01:00
Serg 8fa7ca42f5 [Origin] Brave News starts fetches when disabled by policy (#36661)
`BraveNewsController` is built eagerly with the profile and its ctor
immediately calls `ConditionallyStartOrStopTimer()`. The gate reads
`kBraveNewsDisabledByPolicy` before the policy bundle has been merged
into the managed pref store, so the managed value isn't visible yet and
News issues its usual feed / publisher fetches even when Brave Origin's
`BraveNewsDisabled` policy is set.

Defer the initial `ConditionallyStartOrStopTimer()` call behind a
`brave_policy::PolicyInitializationWaiter`, and tighten
`brave_news::IsEnabled()` to require `IsManagedPreference`.

Resolves: https://github.com/brave/brave-browser/issues/55759
2026-05-22 16:01:29 -05:00
Serg 4078292ec0 [Origin] Honor BraveRewardsDisabled policy when starting Rewards engine (#36629)
* [Origin] Honor BraveRewardsDisabled policy when starting Rewards engine

Defer `RewardsServiceImpl::CheckPreferences()` -- the gate that decides
whether to spin up the Rewards engine process -- behind a
`brave_policy::PolicyInitializationWaiter` so that the managed
`brave_rewards::prefs::kDisabledByPolicy` pref is visible by the time the
gate evaluates. Without this, `Init()` runs before the policy bundle has
been merged into the managed pref store and the engine starts -- pinging
`/v1/parameters` and `/v4/wallets/...` -- even when Brave Origin has
disabled Rewards via `BraveRewardsDisabled`.

Resolves: https://github.com/brave/brave-browser/issues/55696
2026-05-22 07:50:44 -04:00
Serg edb9d6dcac [CodeHealth][Android] Move BraveConstants out of deprecated util package (#36580)
Move BraveConstants.java from org.chromium.chrome.browser.util to
org.chromium.chrome.browser to align with upstream's hierarchy.
Upstream's analogous ChromeStringConstants lives directly under
org.chromium.chrome.browser, and the util package is treated as
deprecated for new top-level constants/utilities.

No behavior changes — pure refactor.

Resolves: https://github.com/brave/brave-browser/issues/55685
2026-05-20 16:58:33 -04:00
Serg eb5146d630 Updates Android best practices to prefer using Material design components versus custom (#36575) 2026-05-20 12:56:01 -04:00
Serg 0bdbd07bdf [Android] Deep link to Brave Origin payment screen for Play promo events (#36556)
Adds support for the https://brave.com/deeplink-android-origin-promo
deep link so that Google Play promotional content events for Brave
Origin can route users directly into the Origin payment screen (or
settings page for existing subscribers).

Routing happens via the existing autoVerified brave.com App Link.
BraveActivity catches the intent before upstream's URL handling in
initializeState (cold start) and onNewIntent (warm start), and the
Play Install Referrer flow continues to support deferred routing for
first-install attribution.

Resolves: https://github.com/brave/brave-browser/issues/55654
2026-05-20 08:58:35 -04:00
Serg 70d97d993e [Origin] Defer policy init signal until BraveProfilePolicyProvider refreshes (#36495)
[Origin] Gate BraveProfilePolicyProvider on BraveOriginPolicyManager init

`BraveProvider`'s first `RefreshPolicies` is triggered by
`AdBlockOnlyModePolicyManager` (initialised at process start), well before
`BraveOriginPolicyManager` (lazily initialised by `BraveOriginServiceFactory`)
is ready. The resulting bundle lacks `BraveRewardsDisabled`, but the
default `IsInitializationComplete` lets `PolicyService` report ready
anyway. `AdsServiceImpl::MaybeStartBatAdsService` then evaluates a stale
managed pref store and bat-ads starts despite the policy.

Override `IsInitializationComplete` to additionally gate on
`BraveOriginPolicyManager::IsInitialized()`. Upstream unit tests
(`ProfilePolicyConnectorTest`) bypass our factory bootstrap, so add a
`SetExpectedToBeInitialized` flag set from `BraveOriginServiceFactory`'s
ctor; the override short-circuits when unset (desktop/Android only --
iOS doesn't run those tests).

Resolves: https://github.com/brave/brave-browser/issues/54962
2026-05-20 07:22:43 -04:00
Serg 0c513a33ea Decouple PolicyService::Observer from AdsServiceImpl (#36437)
* Decouple PolicyService::Observer from AdsServiceImpl

Move the "defer ads service start until policy is initialized" pattern out
of `AdsServiceImpl` into a reusable `brave_policy::PolicyInitializationWaiter`
helper. `AdsServiceImpl` no longer inherits from `policy::PolicyService::Observer`
or takes a `policy::PolicyService*` in its constructor; `AdsServiceFactory`
builds the waiter from the profile policy connector and injects it.

Also drops the temporary `[AdsGate]` verbose logging that was added with the
original race fix; behaviour is now covered by unit tests.

The new helper lives at `brave/components/brave_policy/policy_initialization_waiter.{h,cc}`
and is reusable by any service that needs to defer initialization until
`PolicyService` has merged its policy bundle into the managed pref store.

Resolves: https://github.com/brave/brave-browser/issues/55266
2026-05-15 17:41:37 -04:00
Serg 3effe93f7d [Android] Apply IntentHandler internal-scheme guard to brave:// (#36370)
Aligns brave:// with chrome:// in IntentHandler.intentHasUnsafeInternalScheme.
The upstream guard is unaware of the Brave alias because the brave:// →
chrome:// rewrite happens after the intent layer.

BraveIntentHandlerClassAdapter redirects the upstream call site through
BraveIntentHandler.intentHasUnsafeInternalScheme. The Brave method defers to
upstream first, then additionally rejects brave:// under the same category
guard upstream uses. A new BraveIntentHandlerInternal helper holds the
bytecode stub used to back-call the (private) upstream method.

Resolves: https://github.com/brave/brave-browser/issues/55473
2026-05-12 22:07:15 +01:00
Serg 603ff3cefd [Ads][Origin] Defer ads service start until policy service is initialized (#36151)
* [Ads][Origin] Defer ads service start until policy service is initialized

The ads gate reads `kDisabledByPolicy` via `IsManagedPreference`, so if
`AdsServiceImpl` is constructed before the BraveOrigin policy bundle has
been merged into the managed pref store, the gate evaluates as unmanaged
and the service starts. NTT ads can then serve despite
`BraveRewardsDisabled` being active.

Defer the initial `MaybeStartBatAdsService()` call until
`PolicyService::IsInitializationComplete(POLICY_DOMAIN_CHROME)` is true.
Adds `[AdsGate]` diagnostics behind the existing "Verbose Logs for
Ad-Rewards" QA toggle.

Resolves: https://github.com/brave/brave-browser/issues/55228
2026-05-08 20:13:47 -04:00
Serg de7f477b75 Revert "[Origin] Apply profile policies before pref store reads (#36023)"
Reverts: https://github.com/brave/brave-core/pull/36023
This reverts commit https://github.com/brave/brave-core/commit/acaec910e9757dae29cb1d622846373966a4dd6c.
2026-05-08 00:50:27 +01:00
Serg 08de6ceebc Revert "[Origin] Wait for all policy managers before refreshing profile policies" (#36258)
Revert "[Origin] Wait for all policy managers before refreshing profile polic…"

This reverts commit a044cc5bde.
2026-05-07 16:25:06 -04:00
Serg 17dc65f718 [Android] Enforce Brave Origin policies for VPN, Leo AI and Playlist on Stable/Beta (#36251)
The policy YAMLs for BraveVPNDisabled, BraveAIChatEnabled and
BravePlaylistEnabled listed Android only under future_on:, never under
supported_on:. Codegen marks them is_future on Android, and
ConfigurationPolicyHandlerList::IsBlockedFuturePolicy drops is_future
policies from the bundle on Stable and Beta channels — so the matching
managed prefs (kManagedBraveVPNDisabled, ai_chat::prefs::kEnabledByPolicy,
playlist::kPlaylistEnabledPref) never become managed, and the Java hide
checks in BraveMainPreferencesBase.onResume() and the cross-platform
playlist::IsPlaylistAllowed() never see the policy. Nightly and local
debug builds (channel != Stable/Beta) bypass the gate, which is why this
escaped pre-release.

Move android from future_on: to supported_on: android:148- in the three
YAMLs, matching the existing pattern used for BraveWalletDisabled and
BraveNewsDisabled.

Add OriginPolicies_NotFutureOnThisPlatform unit test that walks every
entry in BraveOriginServiceFactory::GetBrowserPolicyDefinitions() and
GetProfilePolicyDefinitions() and asserts policy_details.is_future is
false. The test runs on every channel and target, so future regressions
of the same shape — Brave Origin claiming to enforce a policy that the
runtime gate will silently drop — surface in unit tests instead of in
released Stable/Beta builds.

Resolves: https://github.com/brave/brave-browser/issues/55346
2026-05-07 13:04:05 -04:00
Serg 824d5976cf [Android] Hide NTP ad settings when Rewards is disabled by policy (#36224)
Hides the "Show New Tab Page Ads" toggle and the
"Learn more about new tab page ads" link in
Settings -> New Tab Page when Brave Rewards is disabled by policy.
Both controls remain visible and functional otherwise.

Also switches BackgroundImagesPreferences to retrieve the profile via
the inherited getProfile() instead of the legacy
ProfileManager.getLastUsedRegularProfile().

Resolves: https://github.com/brave/brave-browser/issues/55312
2026-05-06 22:18:17 +01:00
Serg a044cc5bde [Origin] Wait for all policy managers before refreshing profile policies (#36193)
* [Origin] Wait for all policy managers before refreshing profile policies

`BraveProfilePolicyProvider` observes both `BraveOriginPolicyManager`
and `AdBlockOnlyModePolicyManager`. Each fires `OnBravePoliciesReady`
independently, so the first notification could call `RefreshPolicies`
before the other manager's `Init()` had run -- producing a bundle that
reflected only one source and flipping `IsFirstPolicyLoadComplete` true
on the empty load.

Introduce `BravePolicyManagerBase` with self-registration and a static
`AllInitialized()`. `OnBravePoliciesReady` early-returns until every
registered manager reports ready; `policies_ready_` is gated on the
same check so `SetProfileID` can't trigger a partial refresh either.
Future managers inheriting from the base are picked up automatically.

Resolves: https://github.com/brave/brave-browser/issues/55276
2026-05-06 11:23:42 -04:00
Serg fb40c1459b [Android] Fix shred button spacing from screen edge in tab switcher (#36065)
After switching the menu button visibility from INVISIBLE to GONE in
https://github.com/brave/brave-core/pull/35051, the shred button became
the rightmost child of menu_button_container and lost the spacing the
menu button used to contribute via its paddingEnd. Apply an end margin
equal to the toolbar's start inset when the menu button is hidden so
the icon stays clear of the screen edge and the toolbar reads
symmetrically.

Resolves: https://github.com/brave/brave-browser/issues/55012
2026-04-30 17:13:45 -04:00
Serg b0756180eb [Android] Remove subtitle from Brave Origin toggles when enabled (#36055)
Resolves: https://github.com/brave/brave-browser/issues/55142
2026-04-30 18:50:21 +01:00
Serg acaec910e9 [Origin] Apply profile policies before pref store reads (#36023)
BraveOrigin profile policies (e.g. BraveRewardsDisabled) were not landing
in the managed pref store before AdsService's CanStartBatAdsService gate
ran on Android and desktop. The race had two parts:

1. BraveOriginPolicyManager was initialized lazily from the per-profile
   keyed-service factory, which on Android's startup-data path runs after
   the profile policy connector is already built.
2. BraveProfilePolicyProvider::SetProfileID was called late (from
   BRAVE_PROFILE_IMPL_TAKE_PREFS_FROM_STARTUP_DATA), so OnBravePoliciesReady
   couldn't trigger RefreshPolicies until well after PolicyServiceImpl had
   been constructed with our empty bundle.

Two changes shift the policy push earlier in startup so the async merge
posted by PolicyServiceImpl::OnUpdatePolicy has time to propagate before
consumers read the pref store:

- BraveBrowserProcessImpl::Init eagerly initializes BraveOriginPolicyManager
  with local_state().

- BraveProfilePolicyProvider gets a thread-local profile-path stash that
  is populated by callers immediately before profile policy connector
  creation: chromium_src wrappers for both
  CreateProfilePolicyConnectorForBrowserContext (desktop) and
  StartupData::CreateServicesInternal (Android, via two new macro hooks
  in upstream chrome/browser/startup_data.cc). The
  BRAVE_PROFILE_POLICY_CONNECTOR_INIT macro consumes the stash and calls
  SetProfileID before provider->Init() runs, so OnBravePoliciesReady
  fires synchronously inside Observe() with profile_id_ already set and
  triggers RefreshPolicies in time.

Also adds an early-return in SetProfileID so legacy
SetBraveProfilePolicyProviderProfileID call sites don't re-fire
RefreshPolicies for the already-set id.

Resolves: https://github.com/brave/brave-browser/issues/54991
2026-04-29 20:03:54 -04:00
Serg 4864534b90 [Android] Migrate private NTP to Leo tokens and fix VPN icon visibility (#35905)
* [Android] Migrate private NTP to Leo tokens and fix VPN icon visibility

- Drop Brave-local duplicates of ic_product_vpn / ic_antenna /
  ic_product_private_window so the private NTP renders the Leo
  (Nala) icons via resource_overlay; tint the inner icon layer to
  primitive_private_window_60 in IncognitoNewTabPageView so the
  designed purple still wins on the fixed-dark surface.
- Remove Brave-local primitive_private_window_5/10/20/60/80/90 from
  brave_colors.xml; references now resolve through Leo's primitive
  scale (same hex for _60/80/90; slight neutral shift for _5/10/20).
- Remove the runtime setBackgroundColor on the scroll view that was
  masking the gradient drawable defined in the layout XML.
- Switch the private-tab logo to ic_social_brave_release_favicon_-
  fullheight_color (Leo) and size in dp (42 phone, 56 tablet) to
  match Figma and to stop scaling with accessibility font size.
- Resize circle drawable to 32x32 (was 32x33), constrain inner icon
  via new_tab_page_incognito_icon_inner_size (20dp / 24dp tablet),
  and grow circle to 48dp on tablets.
- Introduce per-form-factor style aliases (IncognitoNtpTitle /
  SectionTitle / SectionDescription / Cta) under values/ +
  values-sw600dp/ so phones and tablets land on the right Leo
  typography ramp without per-TextView attributes.
- Delete the now-dead ntp_bg_incognito and incognito_modern_-
  primary_color color entries.

Resolves: https://github.com/brave/brave-browser/issues/53958
2026-04-27 10:22:07 -04:00
Serg bd61cf9c46 [Android] Hide Survey Panelist setting for Brave Origin users (#35800)
The Survey Panelist toggle and its "Learn more" row remained visible
under Settings -> Brave Shields & privacy for users with an active
Brave Origin subscription.

Extend the existing BRAVE_NTP_BRANDED_WALLPAPER_SURVEY_PANELIST
feature-flag gate in BravePrivacySettings to also require
!BraveOriginSubscriptionPrefs.getIsCredentialSummaryActiveCached() for
both the preference visibility and the settings-search index entry.

Resolves: https://github.com/brave/brave-browser/issues/54853
2026-04-22 22:12:47 +01:00
Serg 2b635d9adb [Android] Fix BraveAdsAdsServiceImplTest on is_official_build x86 (#35792)
brave_rewards::features::kBraveRewards is DISABLED_BY_DEFAULT on x86/x86_64
Android official builds, so brave_rewards::IsSupported returned false via
IsDisabledByFeature. After https://github.com/brave/brave-core/pull/35698
moved the IsSupported gate into AdsServiceImpl::CanStartBatAdsService, that
path now suppresses the service in unit tests too and launch_count stays 0.
Force-enable the feature in the fixture so Android tests match the
non-Android path they were written against.

Resolves: https://github.com/brave/brave-browser/issues/54831
2026-04-22 20:52:23 +01:00
Serg 82eaeebda3 [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
2026-04-21 22:58:42 +01:00
Serg be90a732da [Android] Suppress VPN link-subscription dialog when disabled by policy (#35719)
BraveActivity shows LinkVpnSubscriptionDialogFragment when a VPN
subscription is detected on the device and the link dialog has not yet
been shown. The guard did not consult the VPN policy pref, so the dialog
was presented even to users whose VPN has been disabled by policy (e.g.
Brave Origin users with VPN turned off at the policy layer).

Add !BraveVpnPolicy.isDisabledByPolicy(mTabModelProfileSupplier.get()) to
the guard.

Resolves: https://github.com/brave/brave-browser/issues/54786
2026-04-21 18:46:54 +01:00
Serg a59d89fa21 [Android] Update Brave Origin paywall and settings copy per design feedback (#35700)
String changes in android_brave_strings.grd:
- IDS_MENU_ORIGIN: "Origin" -> "Brave Origin" (Settings menu row).
- IDS_BRAVE_ORIGIN_PREMIUM: "Origin" -> "Brave Origin" (paywall title).
- IDS_ORIGIN_LEO_AI_TOGGLE: "AI" -> "Leo AI" (toggle label
  consistency with other Leo surfaces).
- IDS_ORIGIN_DESCRIPTION_BODY: drop the trailing sentence
  "Origin will remove most other features from the browser."
- IDS_ORIGIN_CHANGING_BRAVE_FEATURES_MESSAGE_POST_PURCHASE:
  "once Origin has finished updating." ->
  "once Brave Origin has finished updating."
- IDS_ORIGIN_PAYWALL_TEXT_4: rewritten to
  "One-time purchase can be activated multiple times across all
  your devices".
- IDS_ORIGIN_DESCRIPTION_NOTE: removed entirely (Search Premium
  note no longer shown).

Layout changes:
- brave_origin_description_preference.xml: remove the
  origin_description_note TextView from the preference-screen
  description block.
- activity_brave_origin_plans.xml (portrait paywall) and
  layout-land/activity_brave_origin_plans.xml (landscape
  paywall): remove the note TextView; body description's bottom
  margin bumped from 16dp to 24dp to preserve spacing with the
  next section.

Resolves: https://github.com/brave/brave-browser/issues/54761
2026-04-21 01:14:29 +01:00
Serg 37e0eeb8f1 [Android] Hide send_web_discovery toggle when managed by policy (#35680)
BraveSearchEnginesPreferences.removePreferenceIfPresent was calling
getPreferenceScreen().removePreference(pref) unconditionally. That
only removes direct children of PreferenceScreen — when the target
preference is nested inside a PreferenceCategory (as send_web_discovery
is, inside currently_used_search_engines_category), the remove call
silently returns false and the toggle stays visible.

Users whose WebDiscoveryEnabled pref is managed by policy (e.g. Brave
Origin subscribers, enterprise admins) saw the toggle rendered and
greyed-out instead of being hidden entirely.

Fix: remove from the preference's actual parent group.
preference.getParent() returns the containing PreferenceGroup — the
PreferenceCategory for nested prefs, the PreferenceScreen itself for
top-level prefs. Works for both cases.

Other PREF_CUSTOM_SEARCH_ENGINES_CATEGORY caller is a top-level
PreferenceCategory; new behavior is equivalent for that case.

Resolves: https://github.com/brave/brave-browser/issues/54751
2026-04-20 18:28:02 +00:00
Serg 34f390c990 [Android] Honor Brave Rewards disabled-by-policy pref (#35651)
brave_rewards::IsDisabledByPolicy() was hardcoded to return false on
Android regardless of the managed kDisabledByPolicy pref, so every
native call site that gates on brave_rewards::IsSupported() failed to
suppress for Brave Origin subscribers (and enterprise admins setting
the BraveRewardsDisabled policy).

Symptoms fixed:
- Ads service kept initializing on Android for Origin profiles
  (AdsServiceFactory::GetForProfile gates on IsSupported).
- NTP sponsored background images and sponsored rich-media takeover
  rendered (downstream of the ads service via ViewCounterService).
- DAY_10 / DAY_30 / DAY_35 Rewards retention notifications fired
  (RetentionNotificationPublisher gates on rewardsNativeWorker
  .isSupported).

Java-side Rewards UI surfaces were already correctly gated via
BraveRewardsPolicy.isDisabledByPolicy(profile) and are unaffected.

Also decouples BraveVpnUtils.isRegionSupported() from
BraveRewardsNativeWorker.isSupported() — otherwise the guard flip would
cause VPN UI to hide for any profile where Rewards is policy-disabled
as a side effect. Added BraveVpnNativeWorker.isSupportedRegion that
does the OFAC region check directly via brave_l10n.

Resolves: https://github.com/brave/brave-browser/issues/54703
2026-04-20 17:08:14 +01:00
Serg 4ceefbc0b2 [Android] Fix Leo file upload using display_name for type detection (#35612)
* [Android] Fix Leo file upload using display_name for type detection

On Android, SelectFileDialog returns info.path() as a content:// URI
without a file extension, so DetermineFileType() cannot classify the
file and uploads silently fail. Use info.display_name, which carries
the real filename with extension, for the Android path.

Resolves: https://github.com/brave/brave-browser/issues/54555

* Fix android unit test
2026-04-17 09:08:37 -07:00
Serg 8b37ade21d [Android] Fix Origin paywall stuck during Play Store purchase restore (#35606)
When a user who previously purchased Brave Origin switches devices,
verifyPurchase() at startup finds the Play Store purchase and kicks off
the SKUs createOrderFromReceipt / fetchOrderCredentials chain to obtain
an order ID. Until that chain completes, requestCredentialSummary
returns inactive, so Settings -> Brave Origin launches the paywall even
though a purchase exists and is mid-restore.

Gate handleOriginPreferenceClick on isFetchingCredentials() and route
directly to BraveOriginPreferences (which renders the fetching spinner
via its existing setCredentialsFetchedCallback path) when a restore is
in flight.

Also harden setCredentialsFetchedCallback against a lost-notification
race: after registering the callback, re-check isFetchingCredentials()
and synthesize a success notification if the fetch already completed.
Order-ID-set is the only path that flips the state to false, so
synthesizing success is safe.

Resolves: https://github.com/brave/brave-browser/issues/54637
2026-04-16 23:48:12 +00:00
Serg 90fadf6259 [Android] Register Brave as Android AutofillService for address autofill (#35567)
* [Android] Register Brave as Android AutofillService for address autofill

Re-enables the Android AutofillService that was removed in
https://github.com/brave/brave-core/pull/25759 due to crashes on
split-APK installs. Uses the SplitCompat pattern
(SplitCompatAutofillService base class) so the service works correctly
when installed from the Play Store.

When the user selects Brave as their autofill provider in Android Settings,
Brave can fill saved address profiles into third-party apps and save new
addresses from manually filled forms.

Resolves: https://github.com/brave/brave-browser/issues/41334
2026-04-16 14:23:41 -04:00
Serg 40e05127bf Revert "[Android] Initialize bottom controls synchronously to fix progress bar" (#35510)
Revert "[Android] Initialize bottom controls synchronously to fix progress ba…"

This reverts commit 5ba39ce79e.
2026-04-14 22:14:36 +00:00
Serg 5ba39ce79e [Android] Initialize bottom controls synchronously to fix progress bar (#35464)
The deferred PostTask introduced to avoid ANR was causing the bottom
controls to be initialized after the progress bar, breaking it.
Revert to synchronous initialization.

Resolves: https://github.com/brave/brave-browser/issues/54458
2026-04-13 15:49:47 -04:00
Serg 8ced933b72 [Android] Fix crash in search widget when native library not loaded (#35458)
The upstream Chromium change
https://chromium-review.googlesource.com/c/chromium/src/+/7567418
("Clean up LocationBar focus and UrlBar management") in cr147 added a
setUrlBarFocus() call in SearchActivity.beginQuery(). This triggers the
omnibox suggestion pipeline (serveCachedZeroSuggest ->
buildDropdownViewInfoList) before native libraries are loaded.

BraveDropdownItemViewInfoListBuilder.isBraveLeoEnabled() and
isBraveSearchPromoBanner() both call ChromeFeatureList.isEnabled() which
requires native, causing UnsatisfiedLinkError on release builds and
AssertionError on debug builds.

Fix: reorder the && conditions to check tab != null before any native
calls. Since there's no tab in SearchActivity, the cheap null check
short-circuits and avoids the native call entirely. No functional
change - these features were never shown in the search widget context.

Resolves: https://github.com/brave/brave-browser/issues/54444
2026-04-13 18:32:16 +00:00
Serg 28138db70b [Android] Check AI Chat feature flag for Leo quick search icon (#35429)
Resolves: https://github.com/brave/brave-browser/issues/48311
2026-04-10 18:01:05 +02:00
Serg 9afe305769 [Android] Hide BAT icon on tablet when rewards disabled by policy (#35400)
The maybeHideRewardsLayout() method controls rewards icon visibility on
tablets based on width but didn't check BraveRewardsPolicy, causing it
to override the main visibility logic that correctly hides the icon when
rewards are disabled.

Resolves: https://github.com/brave/brave-browser/issues/54358
2026-04-09 19:50:14 +02:00
Serg ed743cf544 [Android] Fix Origin showing paywall and "Link Purchase" for linked desktop purchases (#35376)
Always check credentials via SKUs SDK (requestCredentialSummary) in
handleOriginPreferenceClick() instead of gating on the Play Store
purchase pref. This mirrors how Leo uses getPremiumStatus() to handle
both Play Store and desktop purchases.

Only show "Link Purchase" when there is an actual Play Store purchase
that hasn't been linked yet. Desktop purchases have no Play Store
receipt to link.

Resolves: https://github.com/brave/brave-browser/issues/54312
2026-04-08 17:14:18 +02:00
Serg e0365ec5d6 [Android] Remove unused FOREGROUND_SERVICE_CAMERA permission from Android manifest (#35178)
Upstream Chromium cr147 (https://chromium-review.googlesource.com/c/chromium/src/+/7559078)
made FOREGROUND_SERVICE_CAMERA unconditional for all Android builds by
removing the is_desktop_android guard. However, the feature that
actually uses it (kAndroidEnableBackgroundMediaCapturing) is disabled
by default and not enabled by Brave, so the permission is declared but
never used.

This blocks Play Store publishing because Google requires a declaration
with a demo video for any app using FOREGROUND_SERVICE_CAMERA.

This PR:
- Re-gates FOREGROUND_SERVICE_CAMERA behind is_desktop_android so it's
  excluded from Brave builds
- Removes AndroidManifest_user_permissions.xml since upstream now
  declares FOREGROUND_SERVICE_MICROPHONE unconditionally, making
  Brave's duplicate unnecessary

Resolves: https://github.com/brave/brave-browser/issues/54143
2026-04-02 00:06:11 +02:00
Serg 841cad239e [Android] Defer bottom toolbar ViewStub inflation to fix startup ANR (#35083)
Move the bottom controls setup (ViewStub inflation, coordinator
creation, native initialization) from synchronous execution during
finishNativeInitialization to a deferred UI task via PostTask. The
synchronous inflation was triggering HardwareRenderer.nNotifyExpensiveFrame
which blocked the main thread waiting for the GPU, causing ANR on
devices under GPU pressure during startup.

This is safe because all consumers of mBottomControlsCoordinatorSupplier
and mTabGroupUiOneshotSupplier already null-check before use, and the
bottom toolbar starts with visibility="gone" making the one-frame delay
imperceptible. The task is wrapped with mCallbackController.makeCancelable()
to auto-cancel during Activity teardown.

Resolves: https://github.com/brave/brave-browser/issues/54077
2026-03-30 17:55:32 -04:00
Serg 47521cfbf5 Android new tab at the bottom (#35051)
* [Android] Move tab switcher controls to bottom when address bar is at bottom

When the address bar is configured to show at the bottom, reposition the
entire hub toolbar (new tab, menu, pane switcher, search, shred) from
the top to the bottom of the tab switcher for one-handed accessibility.

- BraveHubManagerImpl: Add maybeRepositionToolbarToBottom() that changes
  the toolbar wrapper's FrameLayout gravity to BOTTOM and swaps the pane
  host container's top margin to bottom margin. Uses EdgeToEdge pad
  adjuster (same pattern as upstream HubBottomToolbarCoordinator) to
  handle navigation bar insets. Properly cleans up the adjuster on hub
  hide since the coordinator and views are destroyed between show/hide
  cycles.

- BraveHubManagerImplClassAdapter: Expose parent's mEdgeToEdgeSupplier
  field via deleteField/makeProtectedField bytecode pattern.

- BraveToolbarManager: Remove setLayoutStateProvider() and its
  LayoutStateObserver that toggled menu popup direction on tab switcher
  transitions. No longer needed since the hub toolbar is now at the
  bottom when address bar is at bottom.

- BraveHubToolbarView: Change INVISIBLE to GONE for hidden action/menu
  buttons when bottom navigation controls are enabled (address bar on
  top). INVISIBLE left the buttons clickable despite being hidden.

Resolves: https://github.com/brave/brave-browser/issues/53326
2026-03-27 21:57:06 +01:00
Serg e8dd714c3f [Android] Fix autofill toggle greyed out when Google is the system autofill service (#35018)
* [Android] Fix autofill toggle greyed out when Google is the system autofill service

When Google's Autofill with Google (AWG) is set as the preferred autofill
service in Android OS settings, Chromium disables the third-party autofill
toggle in Settings because Chrome has its own built-in Google-synced
autofill. Since Brave does not have built-in Google autofill, AWG should
be treated like any other third-party provider (e.g. 1Password, Bitwarden).

This fix has two parts:

Java side: Override AutofillClientProviderUtils.getAndroidAutofillFramework-
Availability() via bytecode changeMethodOwner to remap the
ANDROID_AUTOFILL_SERVICE_IS_GOOGLE status to AVAILABLE or SETTING_TURNED_OFF
based on the user's existing pref. This makes the toggle interactive in the
Settings UI.

Native side: The C++ code calls the Java method via JNI, bypassing the
bytecode redirect. To handle this, BraveAutofillClientProviderUtils is
annotated with @CalledByNative to generate its own JNI header. A chromium_src
override of autofill_client_provider.cc uses #define to redirect the original
JNI function to the Brave version, ensuring the native code also uses the
remapped availability status and doesn't reset the pref on browser startup.

Resolves: https://github.com/brave/brave-browser/issues/52960
2026-03-26 22:45:23 +01:00
Serg bfe0809ef0 [Android] Respect Brave Origin policies in settings search (#34985)
Remove policy-disabled features from the settings search index so
they don't appear in search results when disabled by Brave Origin
or enterprise policy.

Resolves: https://github.com/brave/brave-browser/issues/53530
2026-03-25 17:04:54 +01:00
Serg 62575a9e0b [Android] Show loading state in Origin preferences during post-purchase credential fetch (#34955)
* [Android] Show loading state in Origin preferences during post-purchase credential fetch

When a Brave Origin purchase is completed, there is a delay while the
receipt is passed from Play Store to the SKUs SDK via
fetchOrderCredentials. During this time, the Origin preferences screen
opens but credentials aren't ready yet.

- Disable all toggles and clickable preferences until
  fetchOrderCredentials completes
- Show a snackbar with "Disabling features" spinner instead of
  "Restart now" during the credential fetch
- On success, re-enable preferences and transition to "Restart now"
- On failure, close the preferences screen
- Always show restart snackbar on toggle change regardless of
  setPolicyValue result, since failure means a restart is needed
- Remove duplicate color definitions (schemes_primary_fixed_dim,
  schemes_on_primary_fixed, semantic_text_secondary,
  semantic_text_tertiary) that already exist in nala tokens

Resolves: https://github.com/brave/brave-browser/issues/53915
2026-03-25 15:54:01 +01:00
Serg a537c15708 [Android] Implement Origin subscription linking after purchase (#34719)
Add support for linking Brave Origin subscriptions after purchase on
Android, following the same link-order flow used by Leo (AI Chat).

- Add OriginIAPSubscription Mojo interface and C++ implementation to
  read purchase token/order ID from prefs and persist link status
- Handle product=origin in SubscriptionRenderFrameObserver: inject
  braveOrigin.receipt and braveOrigin.orderId into localStorage on
  the initial landing page, and linkResult.setStatus() callback on
  the /order-link/ result page
- Register OriginIAPSubscription Mojo binding in
  BraveContentBrowserClient
- Update LinkSubscriptionUtils to use link-order intent for Origin
- Hide Purchase section in Origin preferences when already linked
- Move subscription_render_frame_observer.h include out of
  ENABLE_BRAVE_VPN guard so it is available for all Android
  subscription products
- Generalize Leo-specific constants (kIntentParamValueLeo,
  kResultLandingPagePathLeo) since they are now shared with Origin
- Add Origin test cases to browser tests

Resolves: https://github.com/brave/brave-browser/issues/53613
2026-03-24 12:59:55 -04:00
Serg 079729bb4f [Android] Fix crash in BraveRewardsNativeWorker when profile is not ready (#34907)
BraveRewardsNativeWorker crashes when constructed before the browser is
fully initialized. This happens when an AlarmManager retention
notification (DAY_10/DAY_30/DAY_35) fires and the app process is started
by Android just to handle the broadcast — ProfileManager::
GetActiveUserProfile() dereferences a null g_browser_process in this
case.

The fix:
- Checks that GetActiveUserProfile() returns a valid profile before
  creating the native worker in JNI_BraveRewardsNativeWorker_Init. If it
  doesn't, the native object is not created.
- Resets the Java singleton when native init is skipped, so subsequent
  calls can retry once the browser is fully initialized.
- Adds null-profile guards to IsSupported, IsSupportedSkipRegionCheck,
  and IsRewardsEnabled which also call GetActiveUserProfile()
  independently.
- Adds null checks for getInstance() at all call sites since it can now
  return null.

Resolves: https://github.com/brave/brave-browser/issues/53877
2026-03-24 00:19:52 +01:00
Serg 4fcc36c117 Fixes presubmit warning in claude SKILL.md (#34896) 2026-03-23 18:47:44 +01:00
Serg 94c841cc01 [Android] Use Nala ic_search icon for dark theme support (#34679)
Remove hardcoded ic_search.xml (#495057 fill) that was shadowing the
Nala version which uses @color/icon_default for proper light/dark
theme adaptation.

Resolves: https://github.com/brave/brave-browser/issues/53297
2026-03-12 16:32:52 -04:00
Serg 25476f8d9a [Android] Hardcode Brave Search icon in Quick Search Engines (#34669)
Convert nala from copy-only targets to a proper android_resources
target so modules with their own resources_package can reference
nala icons via R.drawable at compile time. Use the nala
social-brave-release-favicon-fullheight-color icon for Brave Search
in both the Quick Search Engines view and settings adapters.

Resolves: https://github.com/brave/brave-browser/issues/51364
2026-03-12 14:21:24 -04:00
Serg 1c970aaa1a [Android] Prune stale QSE entries after browsing data is cleared (#34647)
When browsing history is cleared, TemplateUrlService removes
auto-discovered OpenSearch engines, but the QSE SharedPreferences
cache retained stale entries indefinitely. Add a pruning step in
updateSearchEngines() that removes cached entries whose keywords
no longer exist in TemplateUrlService.

Resolves: https://github.com/brave/brave-browser/issues/43104
2026-03-11 17:42:54 -04:00
Serg 12400944d6 [Android] Fix crash in BraveNewsUtils when mojo pipe is closed (#34573)
Guard mojo calls with try/catch for IllegalStateException since the
pipe can be closed by onDetachedFromWindow() or onConnectionError()
before the BEST_EFFORT task executes, and Java mojo bindings have no
non-destructive validity check.

Resolves: https://github.com/brave/brave-browser/issues/53479
2026-03-09 23:27:30 +01:00
Serg 181edb1979 [Android] Fix CustomizeBraveMenuTest exit item visibility test (#34572)
Initialize default invisible items before applying customization to
emulate the onboarding step that hides the exit menu item.

Resolves: https://github.com/brave/brave-browser/issues/53474
Resolves: https://github.com/brave/brave-browser/issues/53475
2026-03-09 19:31:59 +01:00
Serg ae69664eab [Android] Clean up Origin preferences and implement reset/link purchase (#34535)
- Remove unused "Crash reports" toggle (no policy mapping)
- Remove "Manage account" preference
- Rename "Leo AI" toggle label to "AI"
- Implement "Reset to defaults" with confirmation dialog
- Implement "Link purchase" to open Brave account linking page

Resolves: https://github.com/brave/brave-browser/issues/53435
2026-03-06 17:28:33 -05:00
Serg 3efa85704e [Android] Restore Origin purchase on app startup for device change scenario (#34495)
When a user purchases Brave Origin on one device and later switches to a
new device (or reinstalls), the local preferences are empty and the
Origin menu always shows the purchase screen instead of the settings
screen.

This adds a verifyPurchase() method to BraveOriginSubscriptionPrefs that
queries Google Play for an existing Origin purchase and restores the
local preferences (purchase token, product ID, package name) if one is
found. The query is triggered during
BraveActivity.finishNativeInitialization() only when the local
subscription pref is not already active, so it doesn't run unnecessarily
for users who already have their purchase recorded locally.

Toasts are suppressed during the startup query to avoid showing billing
error messages on devices without Google Play, and re-enabled when the
purchase screen is opened.

Resolves: https://github.com/brave/brave-browser/issues/53405
2026-03-05 16:38:37 -05:00
Serg e9ae9e7377 [Android] Fix stale verified publisher checkmark on tab switch (#34449)
The verified publisher checkmark could persist when switching tabs
because brave:// URLs were not treated as internal URLs and
OnPanelPublisherInfo silently dropped null publisher info without
notifying the Java layer.

- Treat brave:// URLs as internal alongside chrome:// so they
  clear the checkmark instead of querying getPublisherInfo.
- Notify Java with an empty publisher ID when OnPanelPublisherInfo
  receives null info, so the UI clears stale state.
- Reset the checkmark immediately in didSelectTab as a safety net
  before the async publisher query completes.

Resolves: https://github.com/brave/brave-browser/issues/53332
2026-03-04 20:59:29 -05:00
Serg 7246781c90 [Android] Use Leo design tokens for icons in Brave Origin settings (#34411)
Migrate Origin settings icons from custom drawables with hardcoded fill
colors to Leo design token equivalents that use @color/icon_default for
proper dark theme support. Remove manual icon tinting code that was
working around the hardcoded colors.

Resolves: https://github.com/brave/brave-browser/issues/53334
2026-03-04 01:20:01 +01:00
Serg 8c0ed68c2e [Android] Gate email aliases preference behind kEmailAliases feature flag (#34403)
The email aliases toggle in Brave Origin settings was always visible
regardless of whether the feature flag is enabled. Since the feature is
disabled by default, users would see a non-functional toggle.

Expose kEmailAliases to Java via ChromeFeatureList and hide the
preference when the flag is disabled.

Resolves: https://github.com/brave/brave-browser/issues/53323
2026-03-03 21:36:30 +00:00
Serg e7fa442510 DayZeroBrowserUIExptManager crashes when P3A is toggled off-on-off (#34370)
fix: DayZeroBrowserUIExptManager crashes when P3A is toggled off-on-off

ResetBrowserUIStateForAllProfiles() was resetting observation_ when P3A
was disabled, but SetDayZeroBrowserUIForAllProfiles() never re-established
it when P3A was re-enabled. Toggling P3A off a second time hit the
CHECK(observation_.IsObserving()) because the observation was already reset.

Remove the observation_.Reset() from ResetBrowserUIStateForAllProfiles().
It's unnecessary because OnProfileAdded() already guards on IsP3AEnabled(),
making it a no-op when P3A is off.

Also destroy the p3a_enabled_ pref subscription in
OnProfileManagerDestroying() to prevent the callback from firing after
the ProfileManager is gone.

Resolves: https://github.com/brave/brave-browser/issues/53294
2026-03-03 15:30:10 +00:00
Serg cb5b0a007d [Android] fix: handle Mojo BadMessageException gracefully (#34360)
Chromium 146 introduced BadMessageException in the Java Mojo bindings
(crbug.com/469861566, https://github.com/chromium/chromium/commit/c04b8552deeef)
to surface malformed or unexpected messages (invalid headers, unknown methods,
deserialization errors, responses for already-cancelled requests). However, the
default ExceptionHandler simply re-throws the exception as unchecked, causing
crashes instead of gracefully closing the pipe.

This differs from the C++ Mojo bindings behavior where
Connector::DispatchMessage (mojo/public/cpp/bindings/lib/connector.cc) handles
dispatch failures by calling HandleError() which resets the pipe cleanly.

Set a delegate on ExceptionHandler.DefaultExceptionHandler that catches
BadMessageException and returns false (closing the pipe), while re-throwing
all other exceptions to preserve existing behavior.

Resolves: https://github.com/brave/brave-browser/issues/53290
2026-03-02 21:44:20 +01:00
Serg aa2fcc5c1f [Android] Fix in-app review flow crash on Play Store split APK installs (#34229)
PlayCoreDialogWrapperActivity (from core-common) lives in base.apk
but deserializes a Parcelable (review.zzc) from split_chrome.apk.
The base split's ClassLoader can't see chrome split classes, causing
ClassNotFoundException. Chromium fixes this for its own activities
via BundleUtils.checkContextClassLoader(), but PlayCoreDialogWrapperActivity
extends plain Activity and is not covered.

Fix by registering an ActivityLifecycleCallbacks that sets the
Application's ClassLoader on the Intent extras Bundle before onCreate().

Also adds a QA preference to force the in-app review flow from settings
for easier testing.

Resolves: https://github.com/brave/brave-browser/issues/53179
2026-02-26 23:19:42 +00:00
Serg c405b65020 [Android] Always show download location dialog when user opts in (#34186)
Override DownloadLocationDialogCoordinator to force the download
location dialog even on single-directory devices (no SD card).
Upstream skips the dialog when only one storage directory is
available; the Brave override intercepts that skip and re-triggers
the dialog display. Also transitions SHOW_INITIAL to SHOW_PREFERENCE
so the "Don't show again" checkbox starts unchecked, preventing the
feature from silently disabling itself after the first use.

Resolves: https://github.com/brave/brave-browser/issues/52737
2026-02-25 20:05:42 +00:00
Serg 109249d429 Android txservice null fix (#34156)
* [Android] Fix NPE in PendingTxHelper when TxService is null

Add null guard for mTxService in fetchTransactions() and null it out
in destroy(). The observer callback can fire after the service is gone
(e.g., wallet service shutdown), causing an NPE at getAllTransactionInfo.
Rename non-public non-static fields to follow the m-prefix convention
required by Chromium's Java style. No functional changes.

Resolves: https://github.com/brave/brave-browser/issues/53102
2026-02-24 18:29:57 +00:00
Serg 4939f3c098 [Android] Fix NPE in HomeSurfaceTracker on activity resume (#34114)
Pass a temporary no-op HomeSurfaceTracker when mHomeSurfaceTracker is
null during warm startup to prevent the NPE in upstream's
setInitialOverviewStateOnResumeWithNtp. This can happen on activity
recreate (rotation, process death, foldable transitions) where
onResumeWithNative fires before the tracker is initialized.

Resolves: https://github.com/brave/brave-browser/issues/53071
2026-02-23 22:05:42 +00:00
Serg 148c069b2f [Android] Add UTM parameters to subscription account URLs (#34084)
Append campaign query parameters to account.brave.com URLs used in
Android subscription linking and credential recovery flows.

Resolves: https://github.com/brave/brave-browser/issues/53025
2026-02-20 19:35:25 +00:00
Serg 7b3ef42db3 [Android] Switch Origin billing from subscription to one-time purchase (#34070)
Brave Origin on Android was scaffolded as a subscription (monthly/yearly)
but never shipped. This switches it to a one-time perpetual purchase
using BillingClient.ProductType.INAPP instead of SUBS.

Changes:
- Replace Origin subscription product IDs (monthly/yearly) with perpetual
  IDs: brave.origin.perpetual, beta.origin.perpetual,
  nightly.origin.perpetual
- Add dedicated INAPP query (queryOriginProductDetailsAsync), purchase
  initiation (initiatePurchaseInApp), and price formatting methods for
  one-time purchases which don't use offer tokens or subscription phases
- Update queryPurchases to use ProductType.INAPP when querying Origin
- Wire up BraveOriginPlansActivity billing flow: product details loading,
  price display, and Buy Now button
- Add "Consume Origin Purchase" option in QA Developer Preferences to
  allow testers to clear the Play Store entitlement for re-testing
- Clean up BraveQAPreferences: migrate from android.app.AlertDialog to
  androidx.appcompat.app.AlertDialog and from SharedPreferences to
  ChromeSharedPreferences

Resolves: https://github.com/brave/brave-browser/issues/53006
2026-02-19 22:35:34 +00:00
Serg c353c9b70d [Android] Fix shred animation crash when app is backgrounded during playback (#34017)
Use dismissAllowingStateLoss() instead of dismiss() to avoid
IllegalStateException after onSaveInstanceState has been called.

Resolves: https://github.com/brave/brave-browser/issues/52940
2026-02-18 12:46:45 +01:00
Serg 88a3dd68f5 Fix BodySnifferURLLoader::Cancel() crash on invalid WeakPtr dereference (#34003)
Add a null check for throttle_ before dereferencing in Cancel(),
consistent with existing guards in OnComplete() and CompleteSniffing().

Resolves: https://github.com/brave/brave-browser/issues/52931
2026-02-18 12:59:01 +07:00
Serg 5a32bc88c0 Update Android Origin payment UI from subscription to one-time purchase (#33950)
Update Android Origin paywall from subscription to one-time purchase

- Replace monthly/yearly subscription plan selectors with single "One Time Purchase" plan row
- Add 4th feature benefit: one-time purchase, no subscription cost
- Add Origin description and Brave Search Premium note sections
- Replace "Try 7 days free" with "Buy now" button
- Replace "Refresh your credentials" with "Get a login code" button
- Remove "Learn more about Origin" button and unused resources
- Update text styles per design spec
- Comment out billing integration for later hookup

Resolves: https://github.com/brave/brave-browser/issues/52855
2026-02-14 04:20:39 +00:00
Serg fc1c6e3181 [Android Origin] Update Android preferences UI and add restart snackbar (#33867)
Redesign the Origin preferences screen: add a custom restart
snackbar with dismiss button shown on toggle changes, split then
description into styled title/body/note sections, and rename
the bottom section from Subscription to Purchase.

Resolves: https://github.com/brave/brave-browser/issues/52774
2026-02-12 00:36:30 +00:00
Serg a756a49988 [Android] Fix for NTP idle snackbar shows when opening external links from other apps. (#33847)
[Android] Fix for NTP idle snackbar shows when opening external links
from other apps. When the NTP idle experiment (variants B/C) is active
and the inactivity threshold has been reached, opening a link from an
external app should not show an NTP+snackbar.

Resolves: https://github.com/brave/brave-browser/issues/52746
2026-02-10 21:24:58 +00:00
Serg 461d66e02c [Android] Shows Brave Wallet UI based on policy. (#33630)
* [Android] Shows Brave Wallet UI based on policy.

Resolves: https://github.com/brave/brave-browser/issues/52496
2026-02-04 10:08:30 -05:00
Serg bd7950d53a [Android] Fixes a crash in FaviconUtils.getIconDrawableWithFilter when an icon is not available for a particular URL by falling back to the default globe icon. (#33569)
[Android] Fixes a crash in FaviconUtils.getIconDrawableWithFilter
when an icon is not available for a particular URL by falling back
to the default globe icon.

Resolves: https://github.com/brave/brave-browser/issues/52458
2026-02-02 23:49:25 +00:00
Serg 4ab77b35ea [Android] Shows Brave VPN UI based on policy. (#33467)
Resolves: https://github.com/brave/brave-browser/issues/52355
2026-01-28 18:56:10 +00:00
Serg 49c34d0a46 [Android] Fixes a crash inside ReturnToChromeUtil.showHomeSurfaceUiOnNtp when HomeSurfaceTracker object is null. (#33408)
[Android] Fixes a crash inside ReturnToChromeUtil.showHomeSurfaceUiOnNtp
when HomeSurfaceTracker object is null.

Resolves: https://github.com/brave/brave-browser/issues/52283
2026-01-26 19:13:05 +00:00
Serg e68153b672 [Android] Checks origin pref policies directly for Leo AI and Rewards. (#33392)
Currently there is an async mojo call to check policies for Leo and
Rewards, that is an overhead and not needed, in fact it could be wrong
if the policies controlled by something else that is not Origin.
Resolves: https://github.com/brave/brave-browser/issues/52244
2026-01-23 20:59:10 +00:00
Serg ec99d6c72e [Android] Shows Brave News UI based on policy. (#33342)
Resolves: https://github.com/brave/brave-browser/issues/52170
2026-01-21 21:48:09 +00:00
Serg 083d518099 [Android] Fixes a crash on VPN service stop. (#33291)
Resolves: https://github.com/brave/brave-browser/issues/52102
2026-01-19 22:52:37 +00:00
Serg 0d070296e3 [Android] Show AI chat UI elements based on policy. (#33256)
Resolves: https://github.com/brave/brave-browser/issues/51974
2026-01-16 23:32:38 +00:00
Serg 25c9a56cbe [CodeHealth][Android] Adjusts policy const generator to respect acronyms. (#33188)
[CodeHealth][Android] Adjusts policy const generator to respect
acronyms.

Resolves: https://github.com/brave/brave-browser/issues/51950
2026-01-13 20:50:38 +00:00
Serg ca943bf511 [Android] Fixes snackbar is not shown on the tablet after closing and relaunching Brave on NTP recent tab. (#33177)
[Android] Fixes snackbar is not shown on the tablet after closing and
relaunching Brave on NTP recent tab.

Resolves: https://github.com/brave/brave-browser/issues/51940
2026-01-13 12:58:50 -05:00
Serg 9f56dd13e4 Revert "add basic save flow of unapproved polkadot tx" (#33165)
Revert "[Polkadot] [Wallet] add basic save flow of unapproved polkadot tx (#3…"

This reverts commit 6804bea343.
2026-01-12 22:27:15 -05:00
Serg 89c10da5b7 [Android] Dismisses Get back to your most recent tab on favorite and on private tab open. (#33162)
[Android] Dismisses Get back to your most recent tab on favorite
and on private tab open.

Resolves: https://github.com/brave/brave-browser/issues/51937
2026-01-13 00:56:10 +00:00
Serg 0a7ac78d6e [Android] Hide Brave Rewards UI elements when disabled by policy (#33116)
[Android] Hide Brave Rewards UI elements when disabled by policy

Implements policy-based visibility control for Brave Rewards across
Android UI. When BRAVE_REWARDS_DISABLED policy is active via Brave
Origin subscription settings, all rewards-related UI elements are
now properly hidden.

Resolves: https://github.com/brave/brave-browser/issues/51826
2026-01-12 20:24:01 +00:00
Serg 0f6f22ecf4 [Android] Places Get back to your most recent tab on top of favicon and the rest of the text on NTP snackbar. (#33145)
[Android] Places Get back to your most recent tab on top of favicon
and the rest of the text on NTP snackbar.

Resolves: https://github.com/brave/brave-browser/issues/51928
2026-01-12 17:35:56 +00:00
Serg 0705dc6245 [Android] Dismisses Get back to your most recent tab on tab switch and on NTP open. (#33141)
[Android] Dismisses Get back to your most recent tab on tab switch
and on NTP open.

Resolves: https://github.com/brave/brave-browser/issues/51927
2026-01-12 16:48:59 +00:00
Serg 87a9a830c0 [cr144][Android] Crash in quick search engines (#32990)
Fixes a crash on quick search engines when default search engine
lookup returns null.
Resolves: https://github.com/brave/brave-browser/issues/51724
2025-12-31 18:33:09 +00:00
Serg 81387558a0 [Android] Crash on app reviews (#32973)
Fixes a crash on app reviews in certain cases.
Resolves: https://github.com/brave/brave-browser/issues/51708
2025-12-30 13:26:49 -05:00
Serg fc9a2eefc0 [Android] Crash on app reviews (#32860)
Fixes a crash on app reviews on certain devices.
Resolves: https://github.com/brave/brave-browser/issues/51518
2025-12-16 18:06:07 -05:00
Serg 3bfcccda7e [Android] Brave Origin policies load fail for Android (#32804)
Patches profile_impl.cc to load Brave Origin policies on Android.
Resolves: https://github.com/brave/brave-browser/issues/51412
2025-12-13 00:23:03 +09:00
Serg 7a06a92381 [Android] Android origin policies
Creates origin policies constants for Android
Adds BraveOriginServiceFactory and connect preferences with BraveOriginSettingsHandler
Resolves https://github.com/brave/brave-browser/issues/51333
2025-12-10 07:14:19 +09:00
Serg a7554c1c74 [Android] Enable in-app updates for Android 14+ devices (#32648)
- Migrate in-app reviews to `com.google.android.play:review:2.0.1`
- Migrate in-app updates to `com.google.android.play:app-update:2.1.0`
- Turn on in-app updates for all supported devices
- Remove `com.google.android.play:core` dependency

Resolves https://github.com/brave/brave-browser/issues/51187
2025-12-05 14:01:39 -05:00
Serg a5bc626771 [Android]Renames kBraveFreshNtpAfterIdleExpirementVariant to kBraveFreshNtpAfterIdleExperimentVariant (#32499)
[Android]Renames kBraveFreshNtpAfterIdleExpirementVariant to
kBraveFreshNtpAfterIdleExperimentVariant.

Resolves: https://github.com/brave/brave-browser/issues/51045
2025-11-24 21:29:50 +01:00
Serg 86a4887089 Android new tab page ab test (#32464)
* [Android] Fresh NTP after idle experiment.

Introduces 4 different variants whether to show NTP or not when Brave
is foregrounded.
Resolves: https://github.com/brave/brave-browser/issues/50989
2025-11-21 17:32:50 -05:00
Serg d1c604c508 Android fresh ntp after idle (#32132)
[Android] Adds kBraveFreshNtpAfterIdleExpirement experiment flag.

That commit adds the flag with parameters and a functionality
to use cached flags on Android.
Resolves: https://github.com/brave/brave-browser/issues/50567
2025-10-31 09:35:04 -04:00
Serg d04fd96056 [CodeHealth] Applies NullMarked to InAppPurchaseWrapper.java. (#31982)
Resolves: https://github.com/brave/brave-browser/issues/49649
2025-10-22 23:08:50 +01:00
Serg ba3e1d8232 Android origin settings screen (#31877)
* [Android] Brave Origin Settings screen

Exposes Brave Origin feature flag to Java.
Implements Brave Origin Settings screen.
Resolves: https://github.com/brave/brave-browser/issues/50270
2025-10-21 20:53:59 +01:00
Serg 81afec5ffb [Android] Top sites text needs to have bottom padding (#31680)
Adds bottom padding for top sites text on NTP.
Resolves: https://github.com/brave/brave-browser/issues/49500
2025-10-07 23:09:49 +01:00