Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add settings migration, improve share dialog and minimize to background by default #4259

Merged
merged 3 commits into from
Sep 27, 2020
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
61 changes: 45 additions & 16 deletions app/src/main/java/org/schabi/newpipe/RouterActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
Expand Down Expand Up @@ -278,6 +279,7 @@ private void showDialog(final List<AdapterChoiceItem> choices) {

handleChoice(choice.key);

// open future streams always like this one, because "always" button was used by user
if (which == DialogInterface.BUTTON_POSITIVE) {
preferences.edit()
.putString(getString(R.string.preferred_open_action_key), choice.key)
Expand Down Expand Up @@ -377,23 +379,50 @@ private List<AdapterChoiceItem> getChoicesForService(final StreamingService serv
final boolean isExtAudioEnabled = preferences.getBoolean(
getString(R.string.use_external_audio_player_key), false);

returnList.add(new AdapterChoiceItem(getString(R.string.show_info_key),
getString(R.string.show_info),
resolveResourceIdFromAttr(context, R.attr.ic_info_outline)));

if (capabilities.contains(VIDEO) && !(isExtVideoEnabled && linkType != LinkType.STREAM)) {
returnList.add(new AdapterChoiceItem(getString(R.string.video_player_key),
getString(R.string.video_player),
resolveResourceIdFromAttr(context, R.attr.ic_play_arrow)));
returnList.add(new AdapterChoiceItem(getString(R.string.popup_player_key),
getString(R.string.popup_player),
resolveResourceIdFromAttr(context, R.attr.ic_popup)));
}
final AdapterChoiceItem videoPlayer = new AdapterChoiceItem(
getString(R.string.video_player_key), getString(R.string.video_player),
resolveResourceIdFromAttr(context, R.attr.ic_play_arrow));
final AdapterChoiceItem showInfo = new AdapterChoiceItem(
getString(R.string.show_info_key), getString(R.string.show_info),
resolveResourceIdFromAttr(context, R.attr.ic_info_outline));
final AdapterChoiceItem popupPlayer = new AdapterChoiceItem(
getString(R.string.popup_player_key), getString(R.string.popup_player),
resolveResourceIdFromAttr(context, R.attr.ic_popup));
final AdapterChoiceItem backgroundPlayer = new AdapterChoiceItem(
getString(R.string.background_player_key), getString(R.string.background_player),
resolveResourceIdFromAttr(context, R.attr.ic_headset));

if (linkType == LinkType.STREAM) {
if (isExtVideoEnabled) {
// show both "show info" and "video player", they are two different activities
returnList.add(showInfo);
returnList.add(videoPlayer);
} else if (capabilities.contains(VIDEO)
&& PlayerHelper.isAutoplayAllowedByUser(context)) {
// show only "video player" since the details activity will be opened and the video
// will be autoplayed there and "show info" would do the exact same thing
returnList.add(videoPlayer);
} else {
// show only "show info" if video player is not applicable or autoplay is disabled
returnList.add(showInfo);
}

if (capabilities.contains(AUDIO) && !(isExtAudioEnabled && linkType != LinkType.STREAM)) {
returnList.add(new AdapterChoiceItem(getString(R.string.background_player_key),
getString(R.string.background_player),
resolveResourceIdFromAttr(context, R.attr.ic_headset)));
if (capabilities.contains(VIDEO)) {
returnList.add(popupPlayer);
}
if (capabilities.contains(AUDIO)) {
returnList.add(backgroundPlayer);
}

} else {
returnList.add(showInfo);
if (capabilities.contains(VIDEO) && !isExtVideoEnabled) {
returnList.add(videoPlayer);
returnList.add(popupPlayer);
}
if (capabilities.contains(AUDIO) && !isExtAudioEnabled) {
returnList.add(backgroundPlayer);
}
}

returnList.add(new AdapterChoiceItem(getString(R.string.download_key),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1236,7 +1236,7 @@ private void startOnExternalPlayer(@NonNull final Context context,
}

private boolean isExternalPlayerEnabled() {
return PreferenceManager.getDefaultSharedPreferences(getContext())
return PreferenceManager.getDefaultSharedPreferences(requireContext())
.getBoolean(getString(R.string.use_external_video_player_key), false);
}

Expand All @@ -1247,23 +1247,7 @@ private boolean isAutoplayEnabled() {
&& !isExternalPlayerEnabled()
&& (player == null || player.videoPlayerSelected())
&& bottomSheetState != BottomSheetBehavior.STATE_HIDDEN
&& isAutoplayAllowedByUser();
}

private boolean isAutoplayAllowedByUser() {
if (activity == null) {
return false;
}

switch (PlayerHelper.getAutoplayType(activity)) {
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER:
return false;
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI:
return !ListHelper.isMeteredNetwork(activity);
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS:
default:
return true;
}
&& PlayerHelper.isAutoplayAllowedByUser(requireContext());
}

private void addVideoPlayerView() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.util.ListHelper;

import java.lang.annotation.Retention;
import java.text.DecimalFormat;
Expand Down Expand Up @@ -248,6 +249,18 @@ public static int getAutoplayType(@NonNull final Context context) {
}
}

public static boolean isAutoplayAllowedByUser(@NonNull final Context context) {
switch (PlayerHelper.getAutoplayType(context)) {
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_NEVER:
return false;
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_WIFI:
return !ListHelper.isMeteredNetwork(context);
case PlayerHelper.AutoplayType.AUTOPLAY_TYPE_ALWAYS:
default:
return true;
}
}

@NonNull
public static SeekParameters getSeekParameters(@NonNull final Context context) {
return isUsingInexactSeek(context) ? SeekParameters.CLOSEST_SYNC : SeekParameters.EXACT;
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/java/org/schabi/newpipe/report/UserAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public enum UserAction {
DELETE_FROM_HISTORY("delete from history"),
PLAY_STREAM("Play stream"),
DOWNLOAD_POSTPROCESSING("download post-processing"),
DOWNLOAD_FAILED("download failed");
DOWNLOAD_FAILED("download failed"),
PREFERENCES_MIGRATION("migration of preferences");


private final String message;
Expand Down
19 changes: 19 additions & 0 deletions app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.schabi.newpipe.R;

import java.io.File;
import java.util.Set;

/*
* Created by k3b on 07.01.2016.
Expand Down Expand Up @@ -38,6 +39,22 @@ public final class NewPipeSettings {
private NewPipeSettings() { }

public static void initSettings(final Context context) {
// check if there are entries in the prefs to determine whether this is the first app run
Boolean isFirstRun = null;
final Set<String> prefsKeys = PreferenceManager.getDefaultSharedPreferences(context)
.getAll().keySet();
for (final String key: prefsKeys) {
// ACRA stores some info in the prefs during app initialization
// which happens before this method is called. Therefore ignore ACRA-related keys.
if (!key.toLowerCase().startsWith("acra")) {
isFirstRun = false;
break;
}
}
if (isFirstRun == null) {
isFirstRun = true;
}

PreferenceManager.setDefaultValues(context, R.xml.appearance_settings, true);
PreferenceManager.setDefaultValues(context, R.xml.content_settings, true);
PreferenceManager.setDefaultValues(context, R.xml.download_settings, true);
Expand All @@ -48,6 +65,8 @@ public static void initSettings(final Context context) {

getVideoDownloadFolder(context);
getAudioDownloadFolder(context);

SettingMigrations.initMigrations(context, isFirstRun);
}

private static void getVideoDownloadFolder(final Context context) {
Expand Down
140 changes: 140 additions & 0 deletions app/src/main/java/org/schabi/newpipe/settings/SettingMigrations.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package org.schabi.newpipe.settings;

import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

import androidx.preference.PreferenceManager;

import org.schabi.newpipe.R;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.ErrorActivity.ErrorInfo;
import org.schabi.newpipe.report.UserAction;

import static org.schabi.newpipe.MainActivity.DEBUG;

public final class SettingMigrations {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in this PR, but we may consider adding junit tests for migrations, using some kind of mocked shared preferences

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely agree with that.

private static final String TAG = SettingMigrations.class.toString();
/**
* Version number for preferences. Must be incremented every time a migration is necessary.
*/
public static final int VERSION = 2;
private static SharedPreferences sp;

public static final Migration MIGRATION_0_1 = new Migration(0, 1) {
@Override
public void migrate(final Context context) {
// We changed the content of the dialog which opens when sharing a link to NewPipe
// by removing the "open detail page" option.
// Therefore, show the dialog once again to ensure users need to choose again and are
// aware of the changed dialog.
final SharedPreferences.Editor editor = sp.edit();
editor.putString(context.getString(R.string.preferred_open_action_key),
context.getString(R.string.always_ask_open_action_key));
editor.apply();
}
};

public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
protected void migrate(final Context context) {
// The new application workflow introduced in #2907 allows minimizing videos
// while playing to do other stuff within the app.
// For an even better workflow, we minimize a stream when switching the app to play in
// background.
// Therefore, set default value to background, if it has not been changed yet.
final String minimizeOnExitKey = context.getString(R.string.minimize_on_exit_key);
if (sp.getString(minimizeOnExitKey, "")
.equals(context.getString(R.string.minimize_on_exit_none_key))) {
final SharedPreferences.Editor editor = sp.edit();
editor.putString(minimizeOnExitKey,
context.getString(R.string.minimize_on_exit_background_key));
editor.apply();
}
}
};

/**
* List of all implemented migrations.
* <p>
* <b>Append new migrations to the end of the list</b> to keep it sorted ascending.
* If not sorted correctly, migrations which depend on each other, may fail.
*/
private static final Migration[] SETTING_MIGRATIONS = {
MIGRATION_0_1,
MIGRATION_1_2
};


public static void initMigrations(final Context context, final boolean isFirstRun) {
// 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) {
sp.edit().putInt(lastPrefVersionKey, VERSION).apply();
return;
} else if (lastPrefVersion == VERSION) {
Stypox marked this conversation as resolved.
Show resolved Hide resolved
return;
}

// run migrations
int currentVersion = lastPrefVersion;
for (final Migration currentMigration : SETTING_MIGRATIONS) {
try {
if (currentMigration.shouldMigrate(currentVersion)) {
if (DEBUG) {
Log.d(TAG, "Migrating preferences from version "
+ currentVersion + " to " + currentMigration.newVersion);
}
currentMigration.migrate(context);
currentVersion = currentMigration.newVersion;
}
} catch (final Exception e) {
// save the version with the last successful migration and report the error
sp.edit().putInt(lastPrefVersionKey, currentVersion).apply();
final ErrorInfo errorInfo = ErrorInfo.make(
UserAction.PREFERENCES_MIGRATION,
"none",
"Migrating preferences from version " + lastPrefVersion + " to "
+ VERSION + ". "
+ "Error at " + currentVersion + " => " + ++currentVersion,
0
);
ErrorActivity.reportError(context, e, SettingMigrations.class, null, errorInfo);
return;
}
}

// store the current preferences version
sp.edit().putInt(lastPrefVersionKey, currentVersion).apply();
}

private SettingMigrations() { }

abstract static class Migration {
public final int oldVersion;
public final int newVersion;

protected Migration(final int oldVersion, final int newVersion) {
this.oldVersion = oldVersion;
this.newVersion = newVersion;
}

/**
* @param currentVersion current settings version
* @return Returns whether this migration should be run.
* A migration is necessary if the old version of this migration is lower than or equal to
* the current settings version.
*/
private boolean shouldMigrate(final int currentVersion) {
return oldVersion >= currentVersion;
}

protected abstract void migrate(Context context);

}

}
6 changes: 5 additions & 1 deletion app/src/main/res/values/settings_keys.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources translatable="false">
<!-- App versioning -->
<string name="last_used_version" translatable="false">last_used_version</string>
<string name="last_used_preferences_version" translatable="false">last_used_preferences_version</string>

<!-- Service -->
<string-array name="service_list" translatable="false">
<item>@string/youtube</item>
Expand Down Expand Up @@ -52,7 +56,7 @@
</string-array>

<string name="minimize_on_exit_key" translatable="false">minimize_on_exit_key</string>
<string name="minimize_on_exit_value" translatable="false">@string/minimize_on_exit_none_key</string>
<string name="minimize_on_exit_value" translatable="false">@string/minimize_on_exit_background_key</string>
<string name="minimize_on_exit_none_key" translatable="false">minimize_on_exit_none_key</string>
<string name="minimize_on_exit_background_key" translatable="false">minimize_on_exit_background_key</string>
<string name="minimize_on_exit_popup_key" translatable="false">minimize_on_exit_popup_key</string>
Expand Down