From 39cfa8c52ed95ef1c550c3fb895bbfd854d58050 Mon Sep 17 00:00:00 2001 From: androidacy-user Date: Sun, 27 Nov 2022 11:50:31 -0500 Subject: [PATCH] Allow user to permanently dismiss notifications request Also handles pre-13 devices that have blocked notifications Signed-off-by: androidacy-user --- app/build.gradle | 6 +- .../java/com/fox2code/mmm/MainActivity.java | 206 +++++++++--------- .../mmm/settings/SettingsActivity.java | 25 ++- app/src/main/res/layout/dialog_checkbox.xml | 16 ++ app/src/main/res/values/arrays.xml | 1 + app/src/main/res/values/strings.xml | 1 + 6 files changed, 145 insertions(+), 110 deletions(-) create mode 100644 app/src/main/res/layout/dialog_checkbox.xml diff --git a/app/build.gradle b/app/build.gradle index 5ff7f84..da2dc7e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -29,9 +29,9 @@ android { applicationIdSuffix '.debug' debuggable true // ONLY FOR TESTING SENTRY - minifyEnabled true - shrinkResources true - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + // minifyEnabled true + // shrinkResources true + // proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),'proguard-rules.pro' } } diff --git a/app/src/main/java/com/fox2code/mmm/MainActivity.java b/app/src/main/java/com/fox2code/mmm/MainActivity.java index 3641747..1ac0f20 100644 --- a/app/src/main/java/com/fox2code/mmm/MainActivity.java +++ b/app/src/main/java/com/fox2code/mmm/MainActivity.java @@ -1,24 +1,31 @@ package com.fox2code.mmm; import android.Manifest; +import android.annotation.SuppressLint; +import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; +import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.provider.Settings; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.WindowManager; import android.view.inputmethod.EditorInfo; +import android.widget.CheckBox; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.SearchView; import androidx.cardview.widget.CardView; +import androidx.core.app.NotificationManagerCompat; import androidx.core.content.ContextCompat; import androidx.core.graphics.ColorUtils; import androidx.preference.PreferenceManager; @@ -46,9 +53,7 @@ import com.google.android.material.progressindicator.LinearProgressIndicator; import eightbitlab.com.blurview.BlurView; -public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRefreshListener, - SearchView.OnQueryTextListener, SearchView.OnCloseListener, - OverScrollManager.OverScrollHelper { +public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRefreshListener, SearchView.OnQueryTextListener, SearchView.OnCloseListener, OverScrollManager.OverScrollHelper { private static final String TAG = "MainActivity"; private static final int PRECISION = 10000; public static boolean noodleDebugState = BuildConfig.DEBUG; @@ -93,9 +98,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe }, R.string.pref_category_settings); setContentView(R.layout.activity_main); this.setTitle(R.string.app_name); - this.getWindow().setFlags( - WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, - WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); + this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); setActionBarBackground(null); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { WindowManager.LayoutParams layoutParams = this.getWindow().getAttributes(); @@ -108,10 +111,8 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe this.actionBarBackground = new ColorDrawable(Color.TRANSPARENT); this.progressIndicator = findViewById(R.id.progress_bar); this.swipeRefreshLayout = findViewById(R.id.swipe_refresh); - this.swipeRefreshLayoutOrigStartOffset = - this.swipeRefreshLayout.getProgressViewStartOffset(); - this.swipeRefreshLayoutOrigEndOffset = - this.swipeRefreshLayout.getProgressViewEndOffset(); + this.swipeRefreshLayoutOrigStartOffset = this.swipeRefreshLayout.getProgressViewStartOffset(); + this.swipeRefreshLayoutOrigEndOffset = this.swipeRefreshLayout.getProgressViewEndOffset(); this.swipeRefreshBlocker = Long.MAX_VALUE; this.moduleList = findViewById(R.id.module_list); this.searchCard = findViewById(R.id.search_card); @@ -134,8 +135,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe }); this.searchCard.setRadius(this.searchCard.getHeight() / 2F); this.searchView.setMinimumHeight(FoxDisplay.dpToPixel(16)); - this.searchView.setImeOptions(EditorInfo.IME_ACTION_SEARCH | - EditorInfo.IME_FLAG_NO_FULLSCREEN); + this.searchView.setImeOptions(EditorInfo.IME_ACTION_SEARCH | EditorInfo.IME_FLAG_NO_FULLSCREEN); this.searchView.setOnQueryTextListener(this); this.searchView.setOnCloseListener(this); this.searchView.setOnQueryTextFocusChangeListener((v, h) -> { @@ -155,8 +155,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe @Override public void onPathReceived(String path) { Log.i(TAG, "Got magisk path: " + path); - if (InstallerInitializer.peekMagiskVersion() < - Constants.MAGISK_VER_CODE_INSTALL_COMMAND) + if (InstallerInitializer.peekMagiskVersion() < Constants.MAGISK_VER_CODE_INSTALL_COMMAND) moduleViewListBuilder.addNotification(NotificationType.MAGISK_OUTDATED); if (!MainApplication.isShowcaseMode()) moduleViewListBuilder.addNotification(NotificationType.INSTALL_FROM_STORAGE); @@ -166,8 +165,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe ensurePermissions(); noodleDebug.pop(); ModuleManager.getINSTANCE().scan(); - ModuleManager.getINSTANCE().runAfterScan( - moduleViewListBuilder::appendInstalledModules); + ModuleManager.getINSTANCE().runAfterScan(moduleViewListBuilder::appendInstalledModules); this.commonNext(); } @@ -176,8 +174,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe Log.i(TAG, "Failed to get magisk path!"); noodleDebug.setEnabled(noodleDebugState); noodleDebug.bind(); - moduleViewListBuilder.addNotification( - InstallerInitializer.getErrorNotification()); + moduleViewListBuilder.addNotification(InstallerInitializer.getErrorNotification()); this.commonNext(); } @@ -206,11 +203,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe noodleDebug.replace("Check Update Compat"); AppUpdateManager.getAppUpdateManager().checkUpdateCompat(); noodleDebug.replace("Check Update"); - RepoManager.getINSTANCE().update(value -> runOnUiThread(max == 0 ? () -> - progressIndicator.setProgressCompat( - (int) (value * PRECISION), true) : () -> - progressIndicator.setProgressCompat( - (int) (value * PRECISION * 0.75F), true))); + RepoManager.getINSTANCE().update(value -> runOnUiThread(max == 0 ? () -> progressIndicator.setProgressCompat((int) (value * PRECISION), true) : () -> progressIndicator.setProgressCompat((int) (value * PRECISION * 0.75F), true))); NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder); if (!NotificationType.NO_INTERNET.shouldRemove()) { moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET); @@ -224,21 +217,17 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe if (max != 0) { int current = 0; noodleDebug.push(""); - for (LocalModuleInfo localModuleInfo : - ModuleManager.getINSTANCE().getModules().values()) { + for (LocalModuleInfo localModuleInfo : ModuleManager.getINSTANCE().getModules().values()) { if (localModuleInfo.updateJson != null) { noodleDebug.replace(localModuleInfo.id); try { localModuleInfo.checkModuleUpdate(); } catch (Exception e) { - Log.e("MainActivity", "Failed to fetch update of: " - + localModuleInfo.id, e); + Log.e("MainActivity", "Failed to fetch update of: " + localModuleInfo.id, e); } current++; final int currentTmp = current; - runOnUiThread(() -> progressIndicator.setProgressCompat( - (int) ((1F * currentTmp / max) * PRECISION * 0.25F - + (PRECISION * 0.75F)), true)); + runOnUiThread(() -> progressIndicator.setProgressCompat((int) ((1F * currentTmp / max) * PRECISION * 0.25F + (PRECISION * 0.75F)), true)); } } noodleDebug.pop(); @@ -252,8 +241,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe updateScreenInsets(getResources().getConfiguration()); }); noodleDebug.replace("Apply"); - RepoManager.getINSTANCE().runAfterUpdate( - moduleViewListBuilder::appendRemoteModules); + RepoManager.getINSTANCE().runAfterUpdate(moduleViewListBuilder::appendRemoteModules); moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter); noodleDebug.pop(); Log.i(TAG, "Finished app opening state!"); @@ -266,8 +254,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe private void cardIconifyUpdate() { boolean iconified = this.searchView.isIconified(); - int backgroundAttr = iconified ? MainApplication.isMonetEnabled() ? - R.attr.colorSecondaryContainer : // Monet is special... + int backgroundAttr = iconified ? MainApplication.isMonetEnabled() ? R.attr.colorSecondaryContainer : // Monet is special... R.attr.colorSecondary : R.attr.colorPrimarySurface; Resources.Theme theme = this.searchCard.getContext().getTheme(); TypedValue value = new TypedValue(); @@ -277,48 +264,38 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe } private void updateScreenInsets() { - this.runOnUiThread(() -> this.updateScreenInsets( - this.getResources().getConfiguration())); + this.runOnUiThread(() -> this.updateScreenInsets(this.getResources().getConfiguration())); } private void updateScreenInsets(Configuration configuration) { - boolean landscape = configuration.orientation == - Configuration.ORIENTATION_LANDSCAPE; + boolean landscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE; int bottomInset = (landscape ? 0 : this.getNavigationBarHeight()); int statusBarHeight = getStatusBarHeight(); int actionBarHeight = getActionBarHeight(); int combinedBarsHeight = statusBarHeight + actionBarHeight; this.actionBarPadding.setMinHeight(combinedBarsHeight); - this.swipeRefreshLayout.setProgressViewOffset(false, - swipeRefreshLayoutOrigStartOffset + combinedBarsHeight, - swipeRefreshLayoutOrigEndOffset + combinedBarsHeight); - this.moduleViewListBuilder.setHeaderPx(Math.max(statusBarHeight, - combinedBarsHeight - FoxDisplay.dpToPixel(4))); - this.moduleViewListBuilder.setFooterPx(FoxDisplay.dpToPixel(4) + - bottomInset + this.searchCard.getHeight()); + this.swipeRefreshLayout.setProgressViewOffset(false, swipeRefreshLayoutOrigStartOffset + combinedBarsHeight, swipeRefreshLayoutOrigEndOffset + combinedBarsHeight); + this.moduleViewListBuilder.setHeaderPx(Math.max(statusBarHeight, combinedBarsHeight - FoxDisplay.dpToPixel(4))); + this.moduleViewListBuilder.setFooterPx(FoxDisplay.dpToPixel(4) + bottomInset + this.searchCard.getHeight()); this.searchCard.setRadius(this.searchCard.getHeight() / 2F); this.moduleViewListBuilder.updateInsets(); //this.actionBarBlur.invalidate(); this.overScrollInsetTop = combinedBarsHeight; this.overScrollInsetBottom = bottomInset; - Log.d(TAG, "( " + bottomInset + ", " + - this.searchCard.getHeight() + ")"); + Log.d(TAG, "( " + bottomInset + ", " + this.searchCard.getHeight() + ")"); } private void updateBlurState() { boolean isLightMode = this.isLightTheme(); int colorBackground; try { - colorBackground = this.getColorCompat( - android.R.attr.windowBackground); + colorBackground = this.getColorCompat(android.R.attr.windowBackground); } catch (Resources.NotFoundException e) { - colorBackground = this.getColorCompat(isLightMode ? - R.color.white : R.color.black); + colorBackground = this.getColorCompat(isLightMode ? R.color.white : R.color.black); } if (MainApplication.isBlurEnabled()) { this.actionBarBlur.setBlurEnabled(true); - this.actionBarBackground.setColor(ColorUtils - .setAlphaComponent(colorBackground, 0x02)); + this.actionBarBackground.setColor(ColorUtils.setAlphaComponent(colorBackground, 0x02)); this.actionBarBackground.setColor(Color.TRANSPARENT); } else { this.actionBarBlur.setBlurEnabled(false); @@ -346,23 +323,20 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe InstallerInitializer.tryGetMagiskPathAsync(new InstallerInitializer.Callback() { @Override public void onPathReceived(String path) { - if (InstallerInitializer.peekMagiskVersion() < - Constants.MAGISK_VER_CODE_INSTALL_COMMAND) + if (InstallerInitializer.peekMagiskVersion() < Constants.MAGISK_VER_CODE_INSTALL_COMMAND) moduleViewListBuilder.addNotification(NotificationType.MAGISK_OUTDATED); if (!MainApplication.isShowcaseMode()) moduleViewListBuilder.addNotification(NotificationType.INSTALL_FROM_STORAGE); noodleDebug.setEnabled(noodleDebugState); noodleDebug.bind(); ModuleManager.getINSTANCE().scan(); - ModuleManager.getINSTANCE().runAfterScan( - moduleViewListBuilder::appendInstalledModules); + ModuleManager.getINSTANCE().runAfterScan(moduleViewListBuilder::appendInstalledModules); this.commonNext(); } @Override public void onFailure(int error) { - moduleViewListBuilder.addNotification( - InstallerInitializer.getErrorNotification()); + moduleViewListBuilder.addNotification(InstallerInitializer.getErrorNotification()); noodleDebug.setEnabled(noodleDebugState); noodleDebug.bind(); this.commonNext(); @@ -386,17 +360,14 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe progressIndicator.setMax(PRECISION); }); noodleDebug.replace("Check Update"); - RepoManager.getINSTANCE().update(value -> runOnUiThread(() -> - progressIndicator.setProgressCompat( - (int) (value * PRECISION), true))); + RepoManager.getINSTANCE().update(value -> runOnUiThread(() -> progressIndicator.setProgressCompat((int) (value * PRECISION), true))); runOnUiThread(() -> { progressIndicator.setProgressCompat(PRECISION, true); progressIndicator.setVisibility(View.GONE); }); } noodleDebug.replace("Apply"); - RepoManager.getINSTANCE().runAfterUpdate( - moduleViewListBuilder::appendRemoteModules); + RepoManager.getINSTANCE().runAfterUpdate(moduleViewListBuilder::appendRemoteModules); Log.i(TAG, "Common Before applyTo"); moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter); noodleDebug.pop(); @@ -414,9 +385,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe @Override public void onRefresh() { - if (this.swipeRefreshBlocker > System.currentTimeMillis() || - this.initMode || this.progressIndicator == null || - this.progressIndicator.getVisibility() == View.VISIBLE) { + if (this.swipeRefreshBlocker > System.currentTimeMillis() || this.initMode || this.progressIndicator == null || this.progressIndicator.getVisibility() == View.VISIBLE) { this.swipeRefreshLayout.setRefreshing(false); return; // Do not double scan } @@ -430,11 +399,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe Http.cleanDnsCache(); // Allow DNS reload from network noodleDebug.push("Check Update"); final int max = ModuleManager.getINSTANCE().getUpdatableModuleCount(); - RepoManager.getINSTANCE().update(value -> runOnUiThread(max == 0 ? () -> - progressIndicator.setProgressCompat( - (int) (value * PRECISION), true) : () -> - progressIndicator.setProgressCompat( - (int) (value * PRECISION * 0.75F), true))); + RepoManager.getINSTANCE().update(value -> runOnUiThread(max == 0 ? () -> progressIndicator.setProgressCompat((int) (value * PRECISION), true) : () -> progressIndicator.setProgressCompat((int) (value * PRECISION * 0.75F), true))); NotificationType.NEED_CAPTCHA_ANDROIDACY.autoAdd(moduleViewListBuilder); if (!NotificationType.NO_INTERNET.shouldRemove()) { moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET); @@ -448,21 +413,17 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe if (max != 0) { int current = 0; noodleDebug.push(""); - for (LocalModuleInfo localModuleInfo : - ModuleManager.getINSTANCE().getModules().values()) { + for (LocalModuleInfo localModuleInfo : ModuleManager.getINSTANCE().getModules().values()) { if (localModuleInfo.updateJson != null) { noodleDebug.replace(localModuleInfo.id); try { localModuleInfo.checkModuleUpdate(); } catch (Exception e) { - Log.e("MainActivity", "Failed to fetch update of: " - + localModuleInfo.id, e); + Log.e("MainActivity", "Failed to fetch update of: " + localModuleInfo.id, e); } current++; final int currentTmp = current; - runOnUiThread(() -> progressIndicator.setProgressCompat( - (int) ((1F * currentTmp / max) * PRECISION * 0.25F - + (PRECISION * 0.75F)), true)); + runOnUiThread(() -> progressIndicator.setProgressCompat((int) ((1F * currentTmp / max) * PRECISION * 0.25F + (PRECISION * 0.75F)), true)); } } noodleDebug.pop(); @@ -478,8 +439,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe this.moduleViewListBuilder.addNotification(NotificationType.NO_INTERNET); } RepoManager.getINSTANCE().updateEnabledStates(); - RepoManager.getINSTANCE().runAfterUpdate( - moduleViewListBuilder::appendRemoteModules); + RepoManager.getINSTANCE().runAfterUpdate(moduleViewListBuilder::appendRemoteModules); this.moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter); noodleDebug.pop(); noodleDebug.unbind(); @@ -491,8 +451,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe this.searchView.clearFocus(); if (this.initMode) return false; if (this.moduleViewListBuilder.setQueryChange(query)) { - new Thread(() -> this.moduleViewListBuilder.applyTo( - moduleList, moduleViewAdapter), "Query update thread").start(); + new Thread(() -> this.moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter), "Query update thread").start(); } return true; } @@ -501,8 +460,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe public boolean onQueryTextChange(String query) { if (this.initMode) return false; if (this.moduleViewListBuilder.setQueryChange(query)) { - new Thread(() -> this.moduleViewListBuilder.applyTo( - moduleList, moduleViewAdapter), "Query update thread").start(); + new Thread(() -> this.moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter), "Query update thread").start(); } return false; } @@ -511,8 +469,7 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe public boolean onClose() { if (this.initMode) return false; if (this.moduleViewListBuilder.setQueryChange(null)) { - new Thread(() -> this.moduleViewListBuilder.applyTo( - moduleList, moduleViewAdapter), "Query update thread").start(); + new Thread(() -> this.moduleViewListBuilder.applyTo(moduleList, moduleViewAdapter), "Query update thread").start(); } return false; } @@ -527,27 +484,64 @@ public class MainActivity extends FoxActivity implements SwipeRefreshLayout.OnRe return this.overScrollInsetBottom; } + @SuppressLint("RestrictedApi") private void ensurePermissions() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && - ContextCompat.checkSelfPermission(this, - Manifest.permission.POST_NOTIFICATIONS) != - PackageManager.PERMISSION_GRANTED) { - // Show a dialog explaining why we need this permission, which is to show - // notifications for updates - runOnUiThread(() -> { - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); - builder.setTitle(R.string.permission_notification_title); - builder.setMessage(R.string.permission_notification_message); - builder.setPositiveButton(R.string.permission_notification_grant, (dialog, which) -> this.requestPermissions(new String[]{ - Manifest.permission.POST_NOTIFICATIONS}, 0)); - builder.setNegativeButton(R.string.cancel, (dialog, which) -> { - // Set pref_background_update_check to false and dismiss dialog - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - prefs.edit().putBoolean("pref_background_update_check", false).apply(); - dialog.dismiss(); + // First, check if user has said don't ask again by checking if pref_dont_ask_again_notification_permission is true + if (!PreferenceManager.getDefaultSharedPreferences(this).getBoolean("pref_dont_ask_again_notification_permission", false)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + // Show a dialog explaining why we need this permission, which is to show + // notifications for updates + runOnUiThread(() -> { + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); + builder.setTitle(R.string.permission_notification_title); + builder.setMessage(R.string.permission_notification_message); + // Don't ask again checkbox + View view = getLayoutInflater().inflate(R.layout.dialog_checkbox, null); + CheckBox checkBox = view.findViewById(R.id.checkbox); + checkBox.setText(R.string.dont_ask_again); + checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean("pref_dont_ask_again_notification_permission", isChecked).apply()); + builder.setView(view); + builder.setPositiveButton(R.string.permission_notification_grant, (dialog, which) -> { + // Request the permission + this.requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, 0); + }); + builder.setNegativeButton(R.string.cancel, (dialog, which) -> { + // Set pref_background_update_check to false and dismiss dialog + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + prefs.edit().putBoolean("pref_background_update_check", false).apply(); + dialog.dismiss(); + }); + builder.show(); }); - builder.show(); - }); + // Next branch is for < android 13 and user has blocked notifications + } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU && !NotificationManagerCompat.from(this).areNotificationsEnabled()) { + runOnUiThread(() -> { + MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); + builder.setTitle(R.string.permission_notification_title); + builder.setMessage(R.string.permission_notification_message); + // Don't ask again checkbox + View view = getLayoutInflater().inflate(R.layout.dialog_checkbox, null); + CheckBox checkBox = view.findViewById(R.id.checkbox); + checkBox.setText(R.string.dont_ask_again); + checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean("pref_dont_ask_again_notification_permission", isChecked).apply()); + builder.setView(view); + builder.setPositiveButton(R.string.permission_notification_grant, (dialog, which) -> { + // Open notification settings + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", getPackageName(), null); + intent.setData(uri); + startActivity(intent); + }); + builder.setNegativeButton(R.string.cancel, (dialog, which) -> { + // Set pref_background_update_check to false and dismiss dialog + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + prefs.edit().putBoolean("pref_background_update_check", false).apply(); + dialog.dismiss(); + }); + builder.show(); + }); + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java index 15dfcd8..8942565 100644 --- a/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java +++ b/app/src/main/java/com/fox2code/mmm/settings/SettingsActivity.java @@ -9,10 +9,12 @@ import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.provider.Settings; import android.util.Log; import android.view.inputmethod.EditorInfo; import android.widget.AutoCompleteTextView; @@ -271,8 +273,29 @@ public class SettingsActivity extends FoxActivity implements LanguageActivity { backgroundUpdateCheck.setVisible(!MainApplication.isWrapped()); // Make uncheckable if POST_NOTIFICATIONS permission is not granted if (!MainApplication.isNotificationPermissionGranted()) { + // Instead of disabling the preference, we make it uncheckable and when the user + // clicks on it, we show a dialog explaining why the permission is needed + backgroundUpdateCheck.setOnPreferenceClickListener(preference -> { + // set the box to unchecked + ((SwitchPreferenceCompat) backgroundUpdateCheck).setChecked(false); + // ensure that the preference is false + MainApplication.getSharedPreferences().edit().putBoolean("pref_background_update_check", false).apply(); + new MaterialAlertDialogBuilder(this.requireContext()) + .setTitle(R.string.permission_notification_title) + .setMessage(R.string.permission_notification_message) + .setPositiveButton(R.string.ok, (dialog, which) -> { + // Open the app settings + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", this.requireContext().getPackageName(), null); + intent.setData(uri); + this.startActivity(intent); + }) + .setNegativeButton(R.string.cancel, (dialog, which) -> {}) + .show(); + return true; + }); backgroundUpdateCheck.setSummary(R.string.background_update_check_permission_required); - backgroundUpdateCheck.setEnabled(false); } backgroundUpdateCheck.setOnPreferenceChangeListener((preference, newValue) -> { boolean enabled = Boolean.parseBoolean(String.valueOf(newValue)); diff --git a/app/src/main/res/layout/dialog_checkbox.xml b/app/src/main/res/layout/dialog_checkbox.xml new file mode 100644 index 0000000..a50699f --- /dev/null +++ b/app/src/main/res/layout/dialog_checkbox.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 26011f6..198916c 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -11,4 +11,5 @@ Dark Light + Don't prompt again \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c41ad95..cb7c4f5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -187,4 +187,5 @@ We need the notifications permission to notify you on app and module updates. If you don\'t grant this permission, background update checks will not run. Grant permission Please enable notifications to enable this option. + Don\'t ask again