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