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 <stypox@pm.me>
This commit is contained in:
parent
1d3a69a29f
commit
a3bbbf03b4
|
@ -60,6 +60,8 @@ import io.reactivex.rxjava3.plugins.RxJavaPlugins;
|
||||||
public class App extends Application {
|
public class App extends Application {
|
||||||
public static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID;
|
public static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID;
|
||||||
private static final String TAG = App.class.toString();
|
private static final String TAG = App.class.toString();
|
||||||
|
|
||||||
|
private boolean isFirstRun = false;
|
||||||
private static App app;
|
private static App app;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -85,7 +87,13 @@ public class App extends Application {
|
||||||
return;
|
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);
|
NewPipeSettings.initSettings(this);
|
||||||
|
|
||||||
NewPipe.init(getDownloader(),
|
NewPipe.init(getDownloader(),
|
||||||
|
@ -255,4 +263,7 @@ public class App extends Application {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFirstRun() {
|
||||||
|
return isFirstRun;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ import org.schabi.newpipe.player.Player;
|
||||||
import org.schabi.newpipe.player.event.OnKeyDownListener;
|
import org.schabi.newpipe.player.event.OnKeyDownListener;
|
||||||
import org.schabi.newpipe.player.helper.PlayerHolder;
|
import org.schabi.newpipe.player.helper.PlayerHolder;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
|
import org.schabi.newpipe.settings.UpdateSettingsFragment;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
import org.schabi.newpipe.util.DeviceUtils;
|
||||||
import org.schabi.newpipe.util.KioskTranslator;
|
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.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.PeertubeHelper;
|
import org.schabi.newpipe.util.PeertubeHelper;
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
|
import org.schabi.newpipe.util.ReleaseVersionUtil;
|
||||||
import org.schabi.newpipe.util.SerializedCache;
|
import org.schabi.newpipe.util.SerializedCache;
|
||||||
import org.schabi.newpipe.util.ServiceHelper;
|
import org.schabi.newpipe.util.ServiceHelper;
|
||||||
import org.schabi.newpipe.util.StateSaver;
|
import org.schabi.newpipe.util.StateSaver;
|
||||||
|
@ -167,6 +169,11 @@ public class MainActivity extends AppCompatActivity {
|
||||||
// if this is enabled by the user.
|
// if this is enabled by the user.
|
||||||
NotificationWorker.initialize(this);
|
NotificationWorker.initialize(this);
|
||||||
}
|
}
|
||||||
|
if (!UpdateSettingsFragment.wasUserAskedForConsent(this)
|
||||||
|
&& ReleaseVersionUtil.INSTANCE.isReleaseApk()
|
||||||
|
&& !App.getApp().isFirstRun()) {
|
||||||
|
UpdateSettingsFragment.askForConsentToUpdateChecks(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -11,6 +11,7 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.App;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
import org.schabi.newpipe.util.DeviceUtils;
|
||||||
|
|
||||||
|
@ -44,14 +45,8 @@ public final class NewPipeSettings {
|
||||||
private NewPipeSettings() { }
|
private NewPipeSettings() { }
|
||||||
|
|
||||||
public static void initSettings(final Context context) {
|
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
|
// 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
|
// readAgain is true so that if new settings are added their default value is set
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.main_settings, true);
|
PreferenceManager.setDefaultValues(context, R.xml.main_settings, true);
|
||||||
|
@ -68,7 +63,7 @@ public final class NewPipeSettings {
|
||||||
saveDefaultVideoDownloadDirectory(context);
|
saveDefaultVideoDownloadDirectory(context);
|
||||||
saveDefaultAudioDownloadDirectory(context);
|
saveDefaultAudioDownloadDirectory(context);
|
||||||
|
|
||||||
disableMediaTunnelingIfNecessary(context, isFirstRun);
|
disableMediaTunnelingIfNecessary(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveDefaultVideoDownloadDirectory(final Context context) {
|
static void saveDefaultVideoDownloadDirectory(final Context context) {
|
||||||
|
@ -146,8 +141,7 @@ public final class NewPipeSettings {
|
||||||
R.string.show_remote_search_suggestions_key);
|
R.string.show_remote_search_suggestions_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void disableMediaTunnelingIfNecessary(@NonNull final Context context,
|
private static void disableMediaTunnelingIfNecessary(@NonNull final Context context) {
|
||||||
final boolean isFirstRun) {
|
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
final String disabledTunnelingKey = context.getString(R.string.disable_media_tunneling_key);
|
final String disabledTunnelingKey = context.getString(R.string.disable_media_tunneling_key);
|
||||||
final String disabledTunnelingAutomaticallyKey =
|
final String disabledTunnelingAutomaticallyKey =
|
||||||
|
@ -162,7 +156,7 @@ public final class NewPipeSettings {
|
||||||
prefs.getInt(disabledTunnelingAutomaticallyKey, -1) == 0
|
prefs.getInt(disabledTunnelingAutomaticallyKey, -1) == 0
|
||||||
&& !prefs.getBoolean(disabledTunnelingKey, false);
|
&& !prefs.getBoolean(disabledTunnelingKey, false);
|
||||||
|
|
||||||
if (Boolean.TRUE.equals(isFirstRun)
|
if (App.getApp().isFirstRun()
|
||||||
|| (wasDeviceBlacklistUpdated && !wasMediaTunnelingEnabledByUser)) {
|
|| (wasDeviceBlacklistUpdated && !wasMediaTunnelingEnabledByUser)) {
|
||||||
setMediaTunneling(context);
|
setMediaTunneling(context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import android.util.Log;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.App;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
import org.schabi.newpipe.error.ErrorUtil;
|
||||||
|
@ -163,15 +164,14 @@ public final class SettingMigrations {
|
||||||
private static final int VERSION = 6;
|
private static final int VERSION = 6;
|
||||||
|
|
||||||
|
|
||||||
public static void runMigrationsIfNeeded(@NonNull final Context context,
|
public static void runMigrationsIfNeeded(@NonNull final Context context) {
|
||||||
final boolean isFirstRun) {
|
|
||||||
// setup migrations and check if there is something to do
|
// setup migrations and check if there is something to do
|
||||||
sp = PreferenceManager.getDefaultSharedPreferences(context);
|
sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
final String lastPrefVersionKey = context.getString(R.string.last_used_preferences_version);
|
final String lastPrefVersionKey = context.getString(R.string.last_used_preferences_version);
|
||||||
final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0);
|
final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0);
|
||||||
|
|
||||||
// no migration to run, already up to date
|
// no migration to run, already up to date
|
||||||
if (isFirstRun) {
|
if (App.getApp().isFirstRun()) {
|
||||||
sp.edit().putInt(lastPrefVersionKey, VERSION).apply();
|
sp.edit().putInt(lastPrefVersionKey, VERSION).apply();
|
||||||
return;
|
return;
|
||||||
} else if (lastPrefVersion == VERSION) {
|
} else if (lastPrefVersion == VERSION) {
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package org.schabi.newpipe.settings;
|
package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import org.schabi.newpipe.NewVersionWorker;
|
import org.schabi.newpipe.NewVersionWorker;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
@ -36,4 +39,38 @@ public class UpdateSettingsFragment extends BasePreferenceFragment {
|
||||||
findPreference(getString(R.string.manual_update_key))
|
findPreference(getString(R.string.manual_update_key))
|
||||||
.setOnPreferenceClickListener(manualUpdateClick);
|
.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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -494,6 +494,7 @@
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<!-- Updates -->
|
<!-- Updates -->
|
||||||
|
<string name="update_check_consent_key">update_check_consent_key</string>
|
||||||
<string name="update_app_key">update_app_key</string>
|
<string name="update_app_key">update_app_key</string>
|
||||||
<string name="manual_update_key">manual_update_key</string>
|
<string name="manual_update_key">manual_update_key</string>
|
||||||
<string name="update_pref_screen_key">update_pref_screen_key</string>
|
<string name="update_pref_screen_key">update_pref_screen_key</string>
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
<string name="install">Install</string>
|
<string name="install">Install</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
<string name="ok">OK</string>
|
<string name="ok">OK</string>
|
||||||
|
<string name="yes">Yes</string>
|
||||||
|
<string name="no">No</string>
|
||||||
<string name="open_in_browser">Open in browser</string>
|
<string name="open_in_browser">Open in browser</string>
|
||||||
<string name="mark_as_watched">Mark as watched</string>
|
<string name="mark_as_watched">Mark as watched</string>
|
||||||
<string name="open_in_popup_mode">Open in popup mode</string>
|
<string name="open_in_popup_mode">Open in popup mode</string>
|
||||||
|
@ -557,8 +559,10 @@
|
||||||
<string name="updates_setting_title">Updates</string>
|
<string name="updates_setting_title">Updates</string>
|
||||||
<string name="updates_setting_description">Show a notification to prompt app update when a new version is available</string>
|
<string name="updates_setting_description">Show a notification to prompt app update when a new version is available</string>
|
||||||
<string name="check_for_updates">Check for updates</string>
|
<string name="check_for_updates">Check for updates</string>
|
||||||
|
<string name="auto_update_check_description">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>
|
||||||
<string name="manual_update_title" translatable="false">@string/check_for_updates</string>
|
<string name="manual_update_title" translatable="false">@string/check_for_updates</string>
|
||||||
<string name="manual_update_description">Manually check for new versions</string>
|
<string name="manual_update_description">Manually check for new versions</string>
|
||||||
|
|
||||||
<!-- Minimize to exit action -->
|
<!-- Minimize to exit action -->
|
||||||
<string name="minimize_on_exit_title">Minimize on app switch</string>
|
<string name="minimize_on_exit_title">Minimize on app switch</string>
|
||||||
<string name="minimize_on_exit_summary">Action when switching to other app from main video player — %s</string>
|
<string name="minimize_on_exit_summary">Action when switching to other app from main video player — %s</string>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
android:title="@string/settings_category_updates_title">
|
android:title="@string/settings_category_updates_title">
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:defaultValue="true"
|
android:defaultValue="false"
|
||||||
android:key="@string/update_app_key"
|
android:key="@string/update_app_key"
|
||||||
android:summary="@string/updates_setting_description"
|
android:summary="@string/updates_setting_description"
|
||||||
android:title="@string/updates_setting_title"
|
android:title="@string/updates_setting_title"
|
||||||
|
|
Loading…
Reference in New Issue