From a3bbbf03b411be091c85b01ba3317d7d613f38fd Mon Sep 17 00:00:00 2001 From: Tobi Date: Wed, 27 Mar 2024 21:27:20 +0100 Subject: [PATCH] Ask for consent before starting update checks NewPipe is contacting its servers without asking for the users' consent. This is categorized as "tracking" by F-Droid (see https://github.com/TeamNewPipe/NewPipe/discussions/10785). This commit disables checking for udpates by default and adds a dialog asking for the user's consent to automatically check for updates if the app version is eligible for them. After upgrading to a version containing this commit the user is asked directly on the first app start. On fresh installs however, showing it on the first app start contributes to a bad onboarding an welcoming experience. Therefore, the dialog is shown at the second app start. Co-authored-by: Stypox --- app/src/main/java/org/schabi/newpipe/App.java | 13 ++++++- .../java/org/schabi/newpipe/MainActivity.java | 7 ++++ .../newpipe/settings/NewPipeSettings.java | 16 +++----- .../newpipe/settings/SettingMigrations.java | 6 +-- .../settings/UpdateSettingsFragment.java | 37 +++++++++++++++++++ app/src/main/res/values/settings_keys.xml | 1 + app/src/main/res/values/strings.xml | 4 ++ app/src/main/res/xml/update_settings.xml | 2 +- 8 files changed, 70 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index ee352ae4a..d92425d20 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -60,6 +60,8 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins; public class App extends Application { public static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID; private static final String TAG = App.class.toString(); + + private boolean isFirstRun = false; private static App app; @NonNull @@ -85,7 +87,13 @@ public class App extends Application { return; } - // Initialize settings first because others inits can use its values + // check if the last used preference version is set + // to determine whether this is the first app run + final int lastUsedPrefVersion = PreferenceManager.getDefaultSharedPreferences(this) + .getInt(getString(R.string.last_used_preferences_version), -1); + isFirstRun = lastUsedPrefVersion == -1; + + // Initialize settings first because other initializations can use its values NewPipeSettings.initSettings(this); NewPipe.init(getDownloader(), @@ -255,4 +263,7 @@ public class App extends Application { return false; } + public boolean isFirstRun() { + return isFirstRun; + } } diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index a096e7eaf..346084b62 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -79,6 +79,7 @@ import org.schabi.newpipe.player.Player; import org.schabi.newpipe.player.event.OnKeyDownListener; import org.schabi.newpipe.player.helper.PlayerHolder; import org.schabi.newpipe.player.playqueue.PlayQueue; +import org.schabi.newpipe.settings.UpdateSettingsFragment; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.DeviceUtils; import org.schabi.newpipe.util.KioskTranslator; @@ -86,6 +87,7 @@ import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.PeertubeHelper; import org.schabi.newpipe.util.PermissionHelper; +import org.schabi.newpipe.util.ReleaseVersionUtil; import org.schabi.newpipe.util.SerializedCache; import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.StateSaver; @@ -167,6 +169,11 @@ public class MainActivity extends AppCompatActivity { // if this is enabled by the user. NotificationWorker.initialize(this); } + if (!UpdateSettingsFragment.wasUserAskedForConsent(this) + && ReleaseVersionUtil.INSTANCE.isReleaseApk() + && !App.getApp().isFirstRun()) { + UpdateSettingsFragment.askForConsentToUpdateChecks(this); + } } @Override diff --git a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java index f280324cf..421440ea7 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java +++ b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java @@ -11,6 +11,7 @@ import androidx.annotation.NonNull; import androidx.annotation.StringRes; import androidx.preference.PreferenceManager; +import org.schabi.newpipe.App; import org.schabi.newpipe.R; import org.schabi.newpipe.util.DeviceUtils; @@ -44,14 +45,8 @@ public final class NewPipeSettings { private NewPipeSettings() { } public static void initSettings(final Context context) { - // check if the last used preference version is set - // to determine whether this is the first app run - final int lastUsedPrefVersion = PreferenceManager.getDefaultSharedPreferences(context) - .getInt(context.getString(R.string.last_used_preferences_version), -1); - final boolean isFirstRun = lastUsedPrefVersion == -1; - // first run migrations, then setDefaultValues, since the latter requires the correct types - SettingMigrations.runMigrationsIfNeeded(context, isFirstRun); + SettingMigrations.runMigrationsIfNeeded(context); // readAgain is true so that if new settings are added their default value is set PreferenceManager.setDefaultValues(context, R.xml.main_settings, true); @@ -68,7 +63,7 @@ public final class NewPipeSettings { saveDefaultVideoDownloadDirectory(context); saveDefaultAudioDownloadDirectory(context); - disableMediaTunnelingIfNecessary(context, isFirstRun); + disableMediaTunnelingIfNecessary(context); } static void saveDefaultVideoDownloadDirectory(final Context context) { @@ -146,8 +141,7 @@ public final class NewPipeSettings { R.string.show_remote_search_suggestions_key); } - private static void disableMediaTunnelingIfNecessary(@NonNull final Context context, - final boolean isFirstRun) { + private static void disableMediaTunnelingIfNecessary(@NonNull final Context context) { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); final String disabledTunnelingKey = context.getString(R.string.disable_media_tunneling_key); final String disabledTunnelingAutomaticallyKey = @@ -162,7 +156,7 @@ public final class NewPipeSettings { prefs.getInt(disabledTunnelingAutomaticallyKey, -1) == 0 && !prefs.getBoolean(disabledTunnelingKey, false); - if (Boolean.TRUE.equals(isFirstRun) + if (App.getApp().isFirstRun() || (wasDeviceBlacklistUpdated && !wasMediaTunnelingEnabledByUser)) { setMediaTunneling(context); } diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java b/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java index b7bafde75..d731f2f5e 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java +++ b/app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java @@ -7,6 +7,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.preference.PreferenceManager; +import org.schabi.newpipe.App; import org.schabi.newpipe.R; import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.ErrorUtil; @@ -163,15 +164,14 @@ public final class SettingMigrations { private static final int VERSION = 6; - public static void runMigrationsIfNeeded(@NonNull final Context context, - final boolean isFirstRun) { + public static void runMigrationsIfNeeded(@NonNull final Context context) { // setup migrations and check if there is something to do sp = PreferenceManager.getDefaultSharedPreferences(context); final String lastPrefVersionKey = context.getString(R.string.last_used_preferences_version); final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0); // no migration to run, already up to date - if (isFirstRun) { + if (App.getApp().isFirstRun()) { sp.edit().putInt(lastPrefVersionKey, VERSION).apply(); return; } else if (lastPrefVersion == VERSION) { diff --git a/app/src/main/java/org/schabi/newpipe/settings/UpdateSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/UpdateSettingsFragment.java index d1a379e66..b8d0aa556 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/UpdateSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/UpdateSettingsFragment.java @@ -1,9 +1,12 @@ package org.schabi.newpipe.settings; +import android.app.AlertDialog; +import android.content.Context; import android.os.Bundle; import android.widget.Toast; import androidx.preference.Preference; +import androidx.preference.PreferenceManager; import org.schabi.newpipe.NewVersionWorker; import org.schabi.newpipe.R; @@ -36,4 +39,38 @@ public class UpdateSettingsFragment extends BasePreferenceFragment { findPreference(getString(R.string.manual_update_key)) .setOnPreferenceClickListener(manualUpdateClick); } + + public static void askForConsentToUpdateChecks(final Context context) { + new AlertDialog.Builder(context) + .setTitle(context.getString(R.string.check_for_updates)) + .setMessage(context.getString(R.string.auto_update_check_description)) + .setPositiveButton(context.getString(R.string.yes), (d, w) -> { + d.dismiss(); + setAutoUpdateCheckEnabled(context, true); + }) + .setNegativeButton(R.string.no, (d, w) -> { + d.dismiss(); + // set explicitly to false, since the default is true on previous versions + setAutoUpdateCheckEnabled(context, false); + }) + .show(); + } + + private static void setAutoUpdateCheckEnabled(final Context context, final boolean enabled) { + PreferenceManager.getDefaultSharedPreferences(context) + .edit() + .putBoolean(context.getString(R.string.update_app_key), enabled) + .putBoolean(context.getString(R.string.update_check_consent_key), true) + .apply(); + } + + /** + * Whether the user was asked for consent to automatically check for app updates. + * @param context + * @return true if the user was asked for consent, false otherwise + */ + public static boolean wasUserAskedForConsent(final Context context) { + return PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(context.getString(R.string.update_check_consent_key), false); + } } diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 3087d1fc2..fb68a464d 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -494,6 +494,7 @@ + update_check_consent_key update_app_key manual_update_key update_pref_screen_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5433c88c7..c4ad8b1d9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7,6 +7,8 @@ Install Cancel OK + Yes + No Open in browser Mark as watched Open in popup mode @@ -557,8 +559,10 @@ Updates Show a notification to prompt app update when a new version is available Check for updates + NewPipe can automatically check for new versions from time to time and notify you once they are available.\nDo you want to enable this? @string/check_for_updates Manually check for new versions + Minimize on app switch Action when switching to other app from main video player — %s diff --git a/app/src/main/res/xml/update_settings.xml b/app/src/main/res/xml/update_settings.xml index a44555edf..becd5c5c9 100644 --- a/app/src/main/res/xml/update_settings.xml +++ b/app/src/main/res/xml/update_settings.xml @@ -4,7 +4,7 @@ android:title="@string/settings_category_updates_title">