3030import androidx .navigation .ui .NavigationUI ;
3131import androidx .preference .PreferenceManager ;
3232
33+ import com .d4rk .androidtutorials .java .BuildConfig ;
3334import com .d4rk .androidtutorials .java .R ;
3435import com .d4rk .androidtutorials .java .databinding .ActivityMainBinding ;
36+ import com .d4rk .androidtutorials .java .notifications .managers .AppUpdateNotificationsManager ;
37+ import com .d4rk .androidtutorials .java .notifications .managers .AppUsageNotificationsManager ;
3538import com .d4rk .androidtutorials .java .ui .components .navigation .BottomSheetMenuFragment ;
3639import com .d4rk .androidtutorials .java .ui .screens .startup .StartupActivity ;
3740import com .d4rk .androidtutorials .java .ui .screens .startup .StartupViewModel ;
3841import com .d4rk .androidtutorials .java .ui .screens .support .SupportActivity ;
3942import com .d4rk .androidtutorials .java .utils .ConsentUtils ;
4043import com .d4rk .androidtutorials .java .utils .EdgeToEdgeDelegate ;
44+ import com .d4rk .androidtutorials .java .utils .ReviewHelper ;
4145import com .google .android .gms .ads .AdRequest ;
4246import com .google .android .gms .ads .MobileAds ;
4347import com .google .android .material .navigation .NavigationBarView ;
4852import com .google .android .play .core .install .InstallStateUpdatedListener ;
4953import com .google .android .play .core .install .model .AppUpdateType ;
5054import com .google .android .play .core .install .model .InstallStatus ;
55+ import com .google .android .play .core .install .model .UpdateAvailability ;
5156import com .google .android .ump .ConsentInformation ;
5257import com .google .android .ump .ConsentRequestParameters ;
5358import com .google .android .ump .UserMessagingPlatform ;
@@ -92,6 +97,7 @@ public void onResume(@NonNull LifecycleOwner owner) {
9297 private NavController navController ;
9398 private int currentNavIndex ;
9499 private AppUpdateManager appUpdateManager ;
100+ private AppUpdateNotificationsManager appUpdateNotificationsManager ;
95101 private InstallStateUpdatedListener installStateUpdatedListener ;
96102 private long backPressedTime ;
97103
@@ -134,6 +140,7 @@ protected void onCreate(Bundle savedInstanceState) {
134140 }
135141
136142 this .appUpdateManager = mainViewModel .getAppUpdateManager ();
143+ setupUpdateNotifications ();
137144
138145 registerInstallStateListener ();
139146 getLifecycle ().addObserver (lifecycleObserver );
@@ -150,6 +157,8 @@ public void handleOnBackPressed() {
150157 }
151158 }
152159 });
160+
161+ checkInAppReview ();
153162 }
154163
155164 private void setupActionBar () {
@@ -238,17 +247,19 @@ private void observeViewModel() {
238247 .build ();
239248
240249 if (useRail ) {
241- NavigationUI .setupWithNavController (mBinding .navRail , navController );
242- mBinding .navRail .setOnItemSelectedListener (item -> {
243- if (item .getItemId () == navController .getCurrentDestination ().getId ()) {
250+ if (mBinding .navRail != null ) {
251+ NavigationUI .setupWithNavController (mBinding .navRail , navController );
252+ mBinding .navRail .setOnItemSelectedListener (item -> {
253+ if (item .getItemId () == navController .getCurrentDestination ().getId ()) {
254+ return true ;
255+ }
256+ int newIndex = navOrder .get (item .getItemId ());
257+ NavOptions options = newIndex > currentNavIndex ? forwardOptions : backwardOptions ;
258+ navController .navigate (item .getItemId (), null , options );
259+ currentNavIndex = newIndex ;
244260 return true ;
245- }
246- int newIndex = navOrder .get (item .getItemId ());
247- NavOptions options = newIndex > currentNavIndex ? forwardOptions : backwardOptions ;
248- navController .navigate (item .getItemId (), null , options );
249- currentNavIndex = newIndex ;
250- return true ;
251- });
261+ });
262+ }
252263 } else {
253264 NavigationUI .setupWithNavController (navBarView , navController );
254265 navBarView .setOnItemSelectedListener (item -> {
@@ -299,12 +310,64 @@ public boolean onOptionsItemSelected(android.view.MenuItem item) {
299310 return super .onOptionsItemSelected (item );
300311 }
301312
302- private void startImmediateUpdate (AppUpdateInfo appUpdateInfo ) {
303- appUpdateManager .startUpdateFlowForResult (
304- appUpdateInfo ,
305- updateActivityResultLauncher ,
306- AppUpdateOptions .newBuilder (AppUpdateType .IMMEDIATE ).build ()
313+ @ Override
314+ protected void onResume () {
315+ super .onResume ();
316+ AppUsageNotificationsManager appUsageNotificationsManager = new AppUsageNotificationsManager (this );
317+ appUsageNotificationsManager .scheduleAppUsageCheck ();
318+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .O ) {
319+ appUpdateNotificationsManager .checkAndSendUpdateNotification ();
320+ }
321+ checkForFlexibleOrImmediateUpdate ();
322+ }
323+
324+ private void checkForFlexibleOrImmediateUpdate () {
325+ appUpdateManager .getAppUpdateInfo ().addOnSuccessListener (appUpdateInfo -> {
326+ boolean updateAvailable = appUpdateInfo .updateAvailability () == UpdateAvailability .UPDATE_AVAILABLE ;
327+ if (updateAvailable ) {
328+ startImmediateUpdate (appUpdateInfo );
329+ }
330+ })
331+ .addOnFailureListener (e -> {
332+ if (!BuildConfig .DEBUG ) {
333+ Snackbar .make (
334+ findViewById (android .R .id .content ),
335+ getString (R .string .snack_general_error ),
336+ Snackbar .LENGTH_LONG
337+ ).show ();
338+ }
339+ });
340+ }
341+
342+ private void checkInAppReview () {
343+ SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences (this );
344+ int sessionCount = prefs .getInt (getString (R .string .key_session_count ), 0 );
345+ boolean hasPrompted = prefs .getBoolean (getString (R .string .key_has_prompted_review ), false );
346+
347+ ReviewHelper .launchInAppReviewIfEligible (
348+ this ,
349+ sessionCount ,
350+ hasPrompted ,
351+ () -> prefs .edit ().putBoolean (getString (R .string .key_has_prompted_review ), true ).apply ()
307352 );
353+
354+ prefs .edit ().putInt (getString (R .string .key_session_count ), sessionCount + 1 ).apply ();
355+ }
356+
357+ private void startImmediateUpdate (AppUpdateInfo appUpdateInfo ) {
358+ try {
359+ appUpdateManager .startUpdateFlowForResult (
360+ appUpdateInfo ,
361+ updateActivityResultLauncher ,
362+ AppUpdateOptions .newBuilder (AppUpdateType .IMMEDIATE ).build ()
363+ );
364+ } catch (Exception e ) {
365+ Log .e ("MainActivity" , "Error starting in-app update" , e );
366+ }
367+ }
368+
369+ private void setupUpdateNotifications () {
370+ appUpdateNotificationsManager = new AppUpdateNotificationsManager (this );
308371 }
309372
310373 private void registerInstallStateListener () {
0 commit comments