56
56
import java .util .Locale ;
57
57
58
58
/**
59
- * This is on boarding activity
60
- * */
59
+ * Activity that handles the first run onboarding experience for new Brave browser installations.
60
+ * Extends FirstRunActivityBase to provide onboarding flows for:
61
+ * - Setting Brave as default browser
62
+ * - Configuring privacy and analytics preferences (P3A and crash reporting)
63
+ * - Accepting terms of service
64
+ * The activity guides users through a series of steps using animations and clear UI elements
65
+ * to explain Brave's key features and privacy-focused approach.
66
+ */
61
67
public class WelcomeOnboardingActivity extends FirstRunActivityBase {
62
- // mInitializeViewsDone and mInvokePostWorkAtInitializeViews are accessed
63
- // from the same thread, so no need to use extra locks
64
68
private static final String P3A_URL =
65
69
"https://support.brave.com/hc/en-us/articles/9140465918093-What-is-P3A-in-Brave" ;
66
70
67
71
private static final String TAG = "WelcomeOnboarding" ;
68
72
73
+ // mInitializeViewsDone and mInvokePostWorkAtInitializeViews are accessed
74
+ // from the same thread, so no need to use extra locks
69
75
private boolean mInitializeViewsDone ;
70
76
private boolean mInvokePostWorkAtInitializeViews ;
77
+
71
78
private boolean mIsTablet ;
72
79
private BraveFirstRunFlowSequencer mFirstRunFlowSequencer ;
73
80
private int mCurrentStep = -1 ;
@@ -79,29 +86,47 @@ public class WelcomeOnboardingActivity extends FirstRunActivityBase {
79
86
private ImageView mIvBrave ;
80
87
private ImageView mIvArrowDown ;
81
88
private LinearLayout mLayoutCard ;
82
- private TextView mTvWelcome ;
83
89
private TextView mTvCard ;
84
90
private TextView mTvDefault ;
85
91
private Button mBtnPositive ;
86
92
private Button mBtnNegative ;
87
93
private CheckBox mCheckboxCrash ;
88
94
private CheckBox mCheckboxP3a ;
89
95
96
+ /**
97
+ * Initializes the views and sets up the onboarding activity UI.
98
+ * This method handles the initial setup of the welcome onboarding screen,
99
+ * including loading the layout, initializing views and click listeners,
100
+ * and performing first-run setup tasks.
101
+ */
90
102
private void initializeViews () {
103
+ // Verify initialization hasn't happened yet
91
104
assert !mInitializeViewsDone ;
105
+
106
+ // Set the content view to the welcome onboarding layout
92
107
setContentView (R .layout .activity_welcome_onboarding );
93
108
109
+ // Check if device is a tablet for layout adjustments
94
110
mIsTablet = DeviceFormFactor .isNonMultiDisplayContextOnTablet (this );
95
111
112
+ // Initialize view references and setup
96
113
initViews ();
114
+
115
+ // Setup click listeners for interactive elements
97
116
onClickViews ();
98
117
118
+ // Mark initialization as complete
99
119
mInitializeViewsDone = true ;
120
+
121
+ // If post-initialization work was queued, execute it now
100
122
if (mInvokePostWorkAtInitializeViews ) {
101
123
finishNativeInitializationPostWork ();
102
124
}
103
125
126
+ // Check install referral data
104
127
checkReferral ();
128
+
129
+ // Update any first run default values if needed
105
130
maybeUpdateFirstRunDefaultValues ();
106
131
}
107
132
@@ -162,7 +187,6 @@ private void initViews() {
162
187
mIvBrave = findViewById (R .id .iv_brave );
163
188
mIvArrowDown = findViewById (R .id .iv_arrow_down );
164
189
mLayoutCard = findViewById (R .id .layout_card );
165
- mTvWelcome = findViewById (R .id .tv_welcome );
166
190
mTvCard = findViewById (R .id .tv_card );
167
191
mTvDefault = findViewById (R .id .tv_default );
168
192
mCheckboxCrash = findViewById (R .id .checkbox_crash );
@@ -207,9 +231,12 @@ private void onClickViews() {
207
231
if (mBtnPositive != null ) {
208
232
mBtnPositive .setOnClickListener (
209
233
view -> {
210
- if (mCurrentStep == 1 && !isDefaultBrowser ()) {
234
+ // If this is the first step and Brave is not set as default browser
235
+ if (mCurrentStep == 0 && !isDefaultBrowser ()) {
236
+ // Show default browser prompt and proceed to next step
211
237
setDefaultBrowserAndProceedToNextStep ();
212
238
} else {
239
+ // Otherwise just proceed to next onboarding step
213
240
nextOnboardingStep ();
214
241
}
215
242
});
@@ -218,9 +245,13 @@ private void onClickViews() {
218
245
if (mBtnNegative != null ) {
219
246
mBtnNegative .setOnClickListener (
220
247
view -> {
248
+ // If we're on the analytics consent page, show the P3A info page
249
+ // Otherwise proceed to next onboarding step
221
250
if (mCurrentStep == getAnalyticsConsentPageStep ()) {
251
+ // Open P3A info page in a custom tab
222
252
CustomTabActivity .showInfoPage (this , P3A_URL );
223
253
} else {
254
+ // Move to next onboarding step
224
255
nextOnboardingStep ();
225
256
}
226
257
});
@@ -254,66 +285,49 @@ private void nextOnboardingStep() {
254
285
if (isActivityFinishingOrDestroyed ()) return ;
255
286
256
287
mCurrentStep ++;
288
+ // Step 0: Handle default browser setup
257
289
if (mCurrentStep == 0 ) {
258
- showIntroPage ();
259
- } else if (mCurrentStep == 1 ) {
290
+ // For devices that don't support role manager API, show browser selection page
260
291
if (!BraveSetDefaultBrowserUtils .supportsDefaultRoleManager ()) {
292
+ mIvBrave .setVisibility (View .VISIBLE );
261
293
showBrowserSelectionPage ();
262
- } else if (!isDefaultBrowser ()) {
294
+ }
295
+ // If Brave is not default browser, trigger default browser prompt
296
+ else if (!isDefaultBrowser ()) {
263
297
setDefaultBrowserAndProceedToNextStep ();
264
- } else {
298
+ }
299
+ // If already default browser, proceed to next step
300
+ else {
265
301
nextOnboardingStep ();
266
302
}
267
- } else if (mCurrentStep == getAnalyticsConsentPageStep ()) {
303
+ }
304
+ // Step 1: Show analytics consent page
305
+ else if (mCurrentStep == getAnalyticsConsentPageStep ()) {
306
+ mIvBrave .setVisibility (View .VISIBLE );
268
307
showAnalyticsConsentPage ();
269
- } else {
308
+ }
309
+ // Final step: Complete onboarding
310
+ else {
311
+ // Set onboarding preferences
270
312
OnboardingPrefManager .getInstance ().setP3aOnboardingShown (true );
271
313
OnboardingPrefManager .getInstance ().setOnboardingSearchBoxTooltip (true );
314
+
315
+ // Mark first run flow as complete
272
316
FirstRunStatus .setFirstRunFlowComplete (true );
317
+
318
+ // Accept terms of service and EULA
273
319
ChromeSharedPreferences .getInstance ()
274
320
.writeBoolean (ChromePreferenceKeys .FIRST_RUN_CACHED_TOS_ACCEPTED , true );
275
321
FirstRunUtils .setEulaAccepted ();
322
+
323
+ // Finish activity and notify completion
276
324
finish ();
277
325
sendFirstRunCompletePendingIntent ();
278
326
}
279
327
}
280
328
281
329
private int getAnalyticsConsentPageStep () {
282
- return 2 ;
283
- }
284
-
285
- private void showIntroPage () {
286
- int margin = mIsTablet ? 100 : 0 ;
287
- setLeafAnimation (mVLeafAlignTop , mIvLeafTop , 1f , margin , true );
288
- setLeafAnimation (mVLeafAlignBottom , mIvLeafBottom , 1f , margin , false );
289
- if (mTvWelcome != null ) {
290
- mTvWelcome
291
- .animate ()
292
- .alpha (1f )
293
- .setDuration (200 )
294
- .withEndAction (() -> mTvWelcome .setVisibility (View .VISIBLE ));
295
- }
296
- if (mIvBrave != null ) {
297
- mIvBrave .animate ().scaleX (0.8f ).scaleY (0.8f ).setDuration (1000 );
298
- }
299
- new Handler ()
300
- .postDelayed (
301
- new Runnable () {
302
- @ Override
303
- public void run () {
304
- if (mTvWelcome != null ) {
305
- mTvWelcome
306
- .animate ()
307
- .translationYBy (
308
- -dpToPx (WelcomeOnboardingActivity .this , 20 ))
309
- .setDuration (3000 )
310
- .start ();
311
- }
312
- }
313
- },
314
- 200 );
315
-
316
- nextOnboardingStep ();
330
+ return 1 ;
317
331
}
318
332
319
333
private void showBrowserSelectionPage () {
@@ -329,9 +343,6 @@ private void showBrowserSelectionPage() {
329
343
mBtnNegative .setVisibility (View .GONE );
330
344
}
331
345
}
332
- if (mTvWelcome != null ) {
333
- mTvWelcome .setVisibility (View .GONE );
334
- }
335
346
if (mLayoutCard != null ) {
336
347
mLayoutCard .setVisibility (View .VISIBLE );
337
348
}
@@ -375,24 +386,30 @@ private void showAnalyticsConsentPage() {
375
386
mBtnNegative .setVisibility (View .VISIBLE );
376
387
}
377
388
378
- if (PackageUtils .isFirstInstall (this )
389
+ // Handle crash reporting consent based on installation status
390
+ if (PackageUtils .isFirstInstall (this )
379
391
&& !OnboardingPrefManager .getInstance ().isP3aCrashReportingMessageShown ()) {
392
+ // For first time installs, enable crash reporting by default
380
393
if (mCheckboxCrash != null ) {
381
394
mCheckboxCrash .setChecked (true );
382
395
}
396
+ // Update metrics reporting consent
383
397
UmaSessionStats .changeMetricsReportingConsent (
384
398
true , ChangeMetricsReportingStateCalledFrom .UI_FIRST_RUN );
399
+ // Mark crash reporting message as shown
385
400
OnboardingPrefManager .getInstance ().setP3aCrashReportingMessageShown (true );
386
401
} else {
402
+ // For existing installations, restore previous crash reporting preference
387
403
boolean isCrashReporting = false ;
388
404
try {
389
- isCrashReporting =
405
+ // Get current crash reporting permission status
406
+ isCrashReporting =
390
407
PrivacyPreferencesManagerImpl .getInstance ()
391
408
.isUsageAndCrashReportingPermittedByUser ();
392
-
393
409
} catch (Exception e ) {
394
410
Log .e (TAG , "isCrashReportingOnboarding: " + e .getMessage ());
395
411
}
412
+ // Update checkbox to match current preference
396
413
if (mCheckboxCrash != null ) {
397
414
mCheckboxCrash .setChecked (isCrashReporting );
398
415
}
0 commit comments