Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,18 @@
import androidx.navigation.ui.NavigationUI;
import androidx.preference.PreferenceManager;

import com.d4rk.androidtutorials.java.BuildConfig;
import com.d4rk.androidtutorials.java.R;
import com.d4rk.androidtutorials.java.databinding.ActivityMainBinding;
import com.d4rk.androidtutorials.java.notifications.managers.AppUpdateNotificationsManager;
import com.d4rk.androidtutorials.java.notifications.managers.AppUsageNotificationsManager;
import com.d4rk.androidtutorials.java.ui.components.navigation.BottomSheetMenuFragment;
import com.d4rk.androidtutorials.java.ui.screens.startup.StartupActivity;
import com.d4rk.androidtutorials.java.ui.screens.startup.StartupViewModel;
import com.d4rk.androidtutorials.java.ui.screens.support.SupportActivity;
import com.d4rk.androidtutorials.java.utils.ConsentUtils;
import com.d4rk.androidtutorials.java.utils.EdgeToEdgeDelegate;
import com.d4rk.androidtutorials.java.utils.ReviewHelper;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.MobileAds;
import com.google.android.material.navigation.NavigationBarView;
Expand All @@ -48,6 +52,7 @@
import com.google.android.play.core.install.InstallStateUpdatedListener;
import com.google.android.play.core.install.model.AppUpdateType;
import com.google.android.play.core.install.model.InstallStatus;
import com.google.android.play.core.install.model.UpdateAvailability;
import com.google.android.ump.ConsentInformation;
import com.google.android.ump.ConsentRequestParameters;
import com.google.android.ump.UserMessagingPlatform;
Expand Down Expand Up @@ -92,6 +97,7 @@ public void onResume(@NonNull LifecycleOwner owner) {
private NavController navController;
private int currentNavIndex;
private AppUpdateManager appUpdateManager;
private AppUpdateNotificationsManager appUpdateNotificationsManager;
private InstallStateUpdatedListener installStateUpdatedListener;
private long backPressedTime;

Expand Down Expand Up @@ -134,6 +140,7 @@ protected void onCreate(Bundle savedInstanceState) {
}

this.appUpdateManager = mainViewModel.getAppUpdateManager();
setupUpdateNotifications();

registerInstallStateListener();
getLifecycle().addObserver(lifecycleObserver);
Expand All @@ -150,6 +157,8 @@ public void handleOnBackPressed() {
}
}
});

checkInAppReview();
}

private void setupActionBar() {
Expand Down Expand Up @@ -238,17 +247,19 @@ private void observeViewModel() {
.build();

if (useRail) {
NavigationUI.setupWithNavController(mBinding.navRail, navController);
mBinding.navRail.setOnItemSelectedListener(item -> {
if (item.getItemId() == navController.getCurrentDestination().getId()) {
if (mBinding.navRail != null) {
NavigationUI.setupWithNavController(mBinding.navRail, navController);
mBinding.navRail.setOnItemSelectedListener(item -> {
if (item.getItemId() == navController.getCurrentDestination().getId()) {
return true;
}
int newIndex = navOrder.get(item.getItemId());
NavOptions options = newIndex > currentNavIndex ? forwardOptions : backwardOptions;
navController.navigate(item.getItemId(), null, options);
currentNavIndex = newIndex;
return true;
}
int newIndex = navOrder.get(item.getItemId());
NavOptions options = newIndex > currentNavIndex ? forwardOptions : backwardOptions;
navController.navigate(item.getItemId(), null, options);
currentNavIndex = newIndex;
return true;
});
});
}
} else {
NavigationUI.setupWithNavController(navBarView, navController);
navBarView.setOnItemSelectedListener(item -> {
Expand Down Expand Up @@ -299,12 +310,64 @@ public boolean onOptionsItemSelected(android.view.MenuItem item) {
return super.onOptionsItemSelected(item);
}

private void startImmediateUpdate(AppUpdateInfo appUpdateInfo) {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
updateActivityResultLauncher,
AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build()
@Override
protected void onResume() {
super.onResume();
AppUsageNotificationsManager appUsageNotificationsManager = new AppUsageNotificationsManager(this);
appUsageNotificationsManager.scheduleAppUsageCheck();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
appUpdateNotificationsManager.checkAndSendUpdateNotification();
}
checkForFlexibleOrImmediateUpdate();
}

private void checkForFlexibleOrImmediateUpdate() {
appUpdateManager.getAppUpdateInfo().addOnSuccessListener(appUpdateInfo -> {
boolean updateAvailable = appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE;
if (updateAvailable) {
startImmediateUpdate(appUpdateInfo);
}
})
.addOnFailureListener(e -> {
if (!BuildConfig.DEBUG) {
Snackbar.make(
findViewById(android.R.id.content),
getString(R.string.snack_general_error),
Snackbar.LENGTH_LONG
).show();
}
});
}

private void checkInAppReview() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int sessionCount = prefs.getInt(getString(R.string.key_session_count), 0);
boolean hasPrompted = prefs.getBoolean(getString(R.string.key_has_prompted_review), false);

ReviewHelper.launchInAppReviewIfEligible(
this,
sessionCount,
hasPrompted,
() -> prefs.edit().putBoolean(getString(R.string.key_has_prompted_review), true).apply()
);

prefs.edit().putInt(getString(R.string.key_session_count), sessionCount + 1).apply();
}

private void startImmediateUpdate(AppUpdateInfo appUpdateInfo) {
try {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
updateActivityResultLauncher,
AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build()
);
} catch (Exception e) {
Log.e("MainActivity", "Error starting in-app update", e);
}
}

private void setupUpdateNotifications() {
appUpdateNotificationsManager = new AppUpdateNotificationsManager(this);
}

private void registerInstallStateListener() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.d4rk.androidtutorials.java.utils;

import android.app.Activity;

import com.google.android.play.core.review.ReviewInfo;
import com.google.android.play.core.review.ReviewManager;
import com.google.android.play.core.review.ReviewManagerFactory;

/**
* Utility class for launching Google Play in-app reviews.
*/
public final class ReviewHelper {

private ReviewHelper() {
// Utility class
}

public static void launchInAppReviewIfEligible(Activity activity,
int sessionCount,
boolean hasPromptedBefore,
Runnable onReviewLaunched) {
if (sessionCount < 3 || hasPromptedBefore) {
return;
}
launchReview(activity, onReviewLaunched);
}

public static void forceLaunchInAppReview(Activity activity) {
launchReview(activity, null);
}

private static void launchReview(Activity activity, Runnable onReviewLaunched) {
ReviewManager reviewManager = ReviewManagerFactory.create(activity);
reviewManager.requestReviewFlow()
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
ReviewInfo reviewInfo = task.getResult();
reviewManager.launchReviewFlow(activity, reviewInfo)
.addOnCompleteListener(flow -> {
if (onReviewLaunched != null) {
onReviewLaunched.run();
}
});
}
});
}
}
2 changes: 2 additions & 0 deletions app/src/main/res/values/keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@
<string name="key_consent_ad_user_data" translatable="false">consent_ad_user_data</string>
<string name="key_consent_ad_personalization" translatable="false">consent_ad_personalization</string>
<string name="key_onboarding_complete" translatable="false">onboarding_complete</string>
<string name="key_session_count" translatable="false">session_count</string>
<string name="key_has_prompted_review" translatable="false">has_prompted_review</string>
</resources>