From d63db94477aa61973f4558f2ce34b4c3b79c12f9 Mon Sep 17 00:00:00 2001 From: VougJo23 Date: Thu, 24 Apr 2025 02:01:56 +0300 Subject: [PATCH] fix: only ask for Notification permission once on first startup This seems to be the only reliable way of making sure we only ever bother the user once. If they accept, from then on the permission check will be successful. If they deny or swipe away, we never ask again at startup and the user has to manually change it in the settings or go to our settings and re-do the prompt by activating notifications. --- .../java/org/schabi/newpipe/MainActivity.java | 17 +++-- .../schabi/newpipe/util/PermissionHelper.java | 71 ++++++++++++++++--- app/src/main/res/values/settings_keys.xml | 1 + 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index f74e8b7a7..783a19c0d 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -179,12 +179,17 @@ public class MainActivity extends AppCompatActivity { } openMiniPlayerUponPlayerStarted(); - if (PermissionHelper.checkPostNotificationsPermission(this, - PermissionHelper.POST_NOTIFICATIONS_REQUEST_CODE)) { - // Schedule worker for checking for new streams and creating corresponding notifications - // if this is enabled by the user. - NotificationWorker.initialize(this); - } + PermissionHelper.checkPostNotificationsPermissionOnStartup( + this, + notificationAllowed -> { + // Schedule worker for checking for new streams and creating corresponding + // notifications if this is enabled by the user. + if (Boolean.TRUE.equals(notificationAllowed)) { + NotificationWorker.initialize(this); + } + } + ); + if (!UpdateSettingsFragment.wasUserAskedForConsent(this) && !App.getApp().isFirstRun() && ReleaseVersionUtil.INSTANCE.isReleaseApk()) { diff --git a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java index 55193599e..8bfd81395 100644 --- a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java @@ -1,23 +1,32 @@ package org.schabi.newpipe.util; import android.Manifest; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.provider.Settings; import android.widget.Toast; +import androidx.activity.ComponentActivity; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; +import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; import org.schabi.newpipe.settings.NewPipeSettings; +import java.util.function.Consumer; + public final class PermissionHelper { public static final int POST_NOTIFICATIONS_REQUEST_CODE = 779; public static final int DOWNLOAD_DIALOG_REQUEST_CODE = 778; @@ -81,17 +90,59 @@ public final class PermissionHelper { return true; } - public static boolean checkPostNotificationsPermission(final Activity activity, - final int requestCode) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU - && ContextCompat.checkSelfPermission(activity, - Manifest.permission.POST_NOTIFICATIONS) - != PackageManager.PERMISSION_GRANTED) { - ActivityCompat.requestPermissions(activity, - new String[] {Manifest.permission.POST_NOTIFICATIONS}, requestCode); - return false; + + /** + * Check that we have the notification permission or ask the user for permission. + * + * @param activity main activity + * @param userChoice a callback that gets called with the user choice + */ + public static void checkPostNotificationsPermissionOnStartup( + final ComponentActivity activity, + final Consumer userChoice) { + + // On Android before TIRAMISU, notifications are always allowed to be sent + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + userChoice.accept(true); + return; } - return true; + + // if we have the permission already, continue + if (ContextCompat.checkSelfPermission(activity, Manifest.permission.POST_NOTIFICATIONS) + == PackageManager.PERMISSION_GRANTED) { + userChoice.accept(true); + return; + } + + // if we already asked the user, don’t ask again + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); + final String wasAskedKey = activity.getString( + R.string.user_was_asked_notification_permission_on_startup_key); + if (prefs.getBoolean(wasAskedKey, false)) { + userChoice.accept(false); + return; + } + + // else let’s ask the user for permission + @SuppressLint("ApplySharedPref") + final ActivityResultCallback cb = isGranted -> { + // first make sure that we only ever ask the user once on startup + final SharedPreferences prefs2 = + PreferenceManager.getDefaultSharedPreferences(activity); + // commit setting before doing anything else + prefs2.edit().putBoolean(wasAskedKey, true).commit(); + + // forward the user choice + userChoice.accept(isGranted); + }; + + final ActivityResultLauncher notificationRequestReference = + activity.registerForActivityResult( + new ActivityResultContracts.RequestPermission(), + cb + ); + + notificationRequestReference.launch(Manifest.permission.POST_NOTIFICATIONS); } /** diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 61125c47f..245263a90 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -1405,6 +1405,7 @@ recaptcha_cookies_key + user_was_asked_notification_permission_on_startup enable_streams_notifications streams_notifications_interval 14400