From 85b897c7d778ae70d837ae0c2a9e7b4252ea8945 Mon Sep 17 00:00:00 2001
From: Sebastian Zeller
Date: Tue, 20 Oct 2020 13:27:27 +0200
Subject: [PATCH 001/128] Filter the All Episodes tab via SQL Query
Fixes #4414
---
.../fragment/AllEpisodesFragment.java | 5 +-
.../fragment/EpisodesListFragment.java | 8 +++
.../antennapod/core/feed/FeedItemFilter.java | 52 +++++++++++++++++++
.../antennapod/core/storage/DBReader.java | 25 +++++++++
.../antennapod/core/storage/PodDBAdapter.java | 26 +++++++---
5 files changed, 105 insertions(+), 11 deletions(-)
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
index ae3ba3a54..08da1f8d9 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AllEpisodesFragment.java
@@ -105,13 +105,12 @@ public class AllEpisodesFragment extends EpisodesListFragment {
@NonNull
@Override
protected List loadData() {
- return feedItemFilter.filter(DBReader.getRecentlyPublishedEpisodes(0, page * EPISODES_PER_PAGE));
+ return DBReader.getRecentlyPublishedEpisodesFiltered(0, page * EPISODES_PER_PAGE, feedItemFilter);
}
@NonNull
@Override
protected List loadMoreData() {
- return feedItemFilter.filter(DBReader.getRecentlyPublishedEpisodes((page - 1) * EPISODES_PER_PAGE,
- EPISODES_PER_PAGE));
+ return DBReader.getRecentlyPublishedEpisodesFiltered((page - 1) * EPISODES_PER_PAGE, EPISODES_PER_PAGE, feedItemFilter);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
index 8dae310ba..39f935bbe 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
@@ -383,6 +383,14 @@ public abstract class EpisodesListFragment extends Fragment {
@NonNull
protected abstract List loadData();
+ /**
+ * Load a new page of data as defined by {@link #page} and {@link #EPISODES_PER_PAGE}.
+ * If the number of items returned is less than {@link #EPISODES_PER_PAGE},
+ * it will be assumed that the underlying data is exhausted
+ * and this method will not be called again.
+ *
+ * @return The items from the next page of data
+ */
@NonNull
protected abstract List loadMoreData();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java
index e8e478a86..b9d79715a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java
@@ -8,6 +8,7 @@ import java.util.Arrays;
import java.util.List;
import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.LongList;
import static de.danoeh.antennapod.core.feed.FeedItem.TAG_FAVORITE;
@@ -15,6 +16,7 @@ import static de.danoeh.antennapod.core.feed.FeedItem.TAG_FAVORITE;
public class FeedItemFilter {
private final String[] mProperties;
+ private final String mQuery;
private boolean showPlayed = false;
private boolean showUnplayed = false;
@@ -78,6 +80,45 @@ public class FeedItemFilter {
break;
}
}
+
+ mQuery = makeQuery();
+ }
+
+ private String makeQuery() {
+ // The keys used within this method, but explicitly combined with their table
+ String keyRead = PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_READ;
+ String keyPosition = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_POSITION;
+ String keyDownloaded = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_DOWNLOADED;
+ String keyMediaId = PodDBAdapter.TABLE_NAME_FEED_MEDIA + "." + PodDBAdapter.KEY_ID;
+ String keyItemId = PodDBAdapter.TABLE_NAME_FEED_ITEMS + "." + PodDBAdapter.KEY_ID;
+ String keyFeedItem = PodDBAdapter.KEY_FEEDITEM;
+ String tableQueue = PodDBAdapter.TABLE_NAME_QUEUE;
+ String tableFavorites = PodDBAdapter.TABLE_NAME_FAVORITES;
+
+ List statements = new ArrayList<>();
+ if (showPlayed) statements.add(keyRead + " = 1 ");
+ if (showUnplayed) statements.add(" NOT " + keyRead + " = 1 "); // Match "New" items (read = -1) as well
+ if (showPaused) statements.add(" (" + keyPosition + " NOT NULL AND " + keyPosition + " > 0 " + ") ");
+ if (showNotPaused) statements.add(" (" + keyPosition + " IS NULL OR " + keyPosition + " = 0 " + ") ");
+ if (showQueued) statements.add(keyItemId + " IN (SELECT " + keyFeedItem + " FROM " + tableQueue + ") ");
+ if (showNotQueued) statements.add(keyItemId + " NOT IN (SELECT " + keyFeedItem + " FROM " + tableQueue + ") ");
+ if (showDownloaded) statements.add(keyDownloaded + " = 1 ");
+ if (showNotDownloaded) statements.add(keyDownloaded + " = 0 ");
+ if (showHasMedia) statements.add(keyMediaId + " NOT NULL ");
+ if (showNoMedia) statements.add(keyMediaId + " IS NULL ");
+ if (showIsFavorite) statements.add(keyItemId + " IN (SELECT " + keyFeedItem + " FROM " + tableFavorites + ") ");
+ if (showNotFavorite) statements.add(keyItemId + " NOT IN (SELECT " + keyFeedItem + " FROM " + tableFavorites + ") ");
+
+ if (statements.isEmpty()) {
+ return "";
+ }
+ StringBuilder query = new StringBuilder(" (" + statements.get(0));
+ for (String r : statements.subList(1, statements.size())) {
+ query.append(" AND ");
+ query.append(r);
+ }
+ query.append(") ");
+ return query.toString();
}
/**
@@ -125,6 +166,17 @@ public class FeedItemFilter {
return result;
}
+ /**
+ * Express this filter using an SQL boolean statement that can be inserted into an SQL WHERE clause
+ * to yield output filtered according to the rules of this filter.
+ *
+ * @return An SQL boolean statement that matches the desired items,
+ * empty string if there is nothing to filter
+ */
+ public String getQuery() {
+ return mQuery;
+ }
+
public String[] getValues() {
return mProperties.clone();
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
index b218a73f9..2ba817b94 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
@@ -17,6 +17,7 @@ import java.util.Map;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedItemFilter;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.feed.SubscriptionsFilter;
@@ -386,6 +387,30 @@ public final class DBReader {
}
}
+ /**
+ * Loads a filtered list of FeedItems sorted by pubDate in descending order.
+ *
+ * @param offset The first episode that should be loaded.
+ * @param limit The maximum number of episodes that should be loaded.
+ * @param filter The filter describing which episodes to filter out.
+ */
+ @NonNull
+ public static List getRecentlyPublishedEpisodesFiltered(int offset, int limit,
+ FeedItemFilter filter) {
+ Log.d(TAG, "getRecentlyPublishedEpisodesFiltered() called with: "
+ + "offset = [" + offset + "]" + " limit = [" + limit + "]" + " filter = [" + filter.getQuery() + "]");
+
+ PodDBAdapter adapter = PodDBAdapter.getInstance();
+ adapter.open();
+ try (Cursor cursor = adapter.getRecentlyPublishedItemsCursorFiltered(offset, limit, filter)) {
+ List items = extractItemlistFromCursor(adapter, cursor);
+ loadAdditionalFeedItemListData(items);
+ return items;
+ } finally {
+ adapter.close();
+ }
+ }
+
/**
* Loads the playback history from the database. A FeedItem is in the playback history if playback of the correpsonding episode
* has been completed at least once.
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
index 539bedd9f..a02cce504 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
@@ -31,6 +31,7 @@ import java.util.Set;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedItemFilter;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -116,14 +117,14 @@ public class PodDBAdapter {
public static final String KEY_FEED_SKIP_ENDING = "feed_skip_ending";
// Table names
- static final String TABLE_NAME_FEEDS = "Feeds";
- static final String TABLE_NAME_FEED_ITEMS = "FeedItems";
- static final String TABLE_NAME_FEED_IMAGES = "FeedImages";
- static final String TABLE_NAME_FEED_MEDIA = "FeedMedia";
- static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog";
- static final String TABLE_NAME_QUEUE = "Queue";
- static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters";
- static final String TABLE_NAME_FAVORITES = "Favorites";
+ public static final String TABLE_NAME_FEEDS = "Feeds";
+ public static final String TABLE_NAME_FEED_ITEMS = "FeedItems";
+ public static final String TABLE_NAME_FEED_IMAGES = "FeedImages";
+ public static final String TABLE_NAME_FEED_MEDIA = "FeedMedia";
+ public static final String TABLE_NAME_DOWNLOAD_LOG = "DownloadLog";
+ public static final String TABLE_NAME_QUEUE = "Queue";
+ public static final String TABLE_NAME_SIMPLECHAPTERS = "SimpleChapters";
+ public static final String TABLE_NAME_FAVORITES = "Favorites";
// SQL Statements for creating new tables
private static final String TABLE_PRIMARY_KEY = KEY_ID
@@ -1053,6 +1054,15 @@ public class PodDBAdapter {
return db.rawQuery(query, null);
}
+ public final Cursor getRecentlyPublishedItemsCursorFiltered(int offset, int limit,
+ FeedItemFilter filter) {
+ String filterQuery = filter.getQuery();
+ String whereClause = "".equals(filterQuery) ? "" : " WHERE " + filter.getQuery();
+ final String query = SELECT_FEED_ITEMS_AND_MEDIA + whereClause
+ + " ORDER BY " + KEY_PUBDATE + " DESC LIMIT " + offset + ", " + limit;
+ return db.rawQuery(query, null);
+ }
+
public Cursor getDownloadedItemsCursor() {
final String query = SELECT_FEED_ITEMS_AND_MEDIA
+ "WHERE " + TABLE_NAME_FEED_MEDIA + "." + KEY_DOWNLOADED + " > 0";
From 7b8208a2a7a7fd81a9dd1ff547d422d08255c4e1 Mon Sep 17 00:00:00 2001
From: ByteHamster
Date: Sat, 3 Oct 2020 12:32:05 +0200
Subject: [PATCH 002/128] Simplified gpodder login process
---
app/src/main/AndroidManifest.xml | 13 -
.../GpodnetAuthenticationActivity.java | 395 ------------------
.../dialog/GpodnetSetHostnameDialog.java | 59 ---
.../GpodderAuthenticationFragment.java | 322 ++++++++++++++
.../GpodderPreferencesFragment.java | 14 +-
.../main/res/layout/gpodnetauth_activity.xml | 10 -
.../res/layout/gpodnetauth_credentials.xml | 169 ++++----
.../main/res/layout/gpodnetauth_device.xml | 130 ++----
.../res/layout/gpodnetauth_device_group.xml | 35 ++
.../main/res/layout/gpodnetauth_dialog.xml | 20 +
.../main/res/layout/gpodnetauth_finish.xml | 32 +-
app/src/main/res/layout/gpodnetauth_host.xml | 50 +++
app/src/main/res/xml/preferences_gpodder.xml | 14 +-
.../core/sync/gpoddernet/GpodnetService.java | 132 +++++-
core/src/main/res/values/strings.xml | 23 +-
15 files changed, 689 insertions(+), 729 deletions(-)
delete mode 100644 app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
delete mode 100644 app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
create mode 100644 app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java
delete mode 100644 app/src/main/res/layout/gpodnetauth_activity.xml
create mode 100644 app/src/main/res/layout/gpodnetauth_device_group.xml
create mode 100644 app/src/main/res/layout/gpodnetauth_dialog.xml
create mode 100644 app/src/main/res/layout/gpodnetauth_host.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fb205b1c3..10225f9a3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -292,19 +292,6 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
deleted file mode 100644
index cfd6ec702..000000000
--- a/app/src/main/java/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java
+++ /dev/null
@@ -1,395 +0,0 @@
-package de.danoeh.antennapod.activity.gpoddernet;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import androidx.appcompat.app.AppCompatActivity;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ProgressBar;
-import android.widget.Spinner;
-import android.widget.TextView;
-import android.widget.ViewFlipper;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import de.danoeh.antennapod.BuildConfig;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
-import de.danoeh.antennapod.core.sync.SyncService;
-import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
-import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetServiceException;
-import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetDevice;
-
-/**
- * Guides the user through the authentication process
- * Step 1: Request username and password from user
- * Step 2: Choose device from a list of available devices or create a new one
- * Step 3: Choose from a list of actions
- */
-public class GpodnetAuthenticationActivity extends AppCompatActivity {
- private static final String TAG = "GpodnetAuthActivity";
-
- private ViewFlipper viewFlipper;
-
- private static final int STEP_DEFAULT = -1;
- private static final int STEP_LOGIN = 0;
- private static final int STEP_DEVICE = 1;
- private static final int STEP_FINISH = 2;
-
- private int currentStep = -1;
-
- private GpodnetService service;
- private volatile String username;
- private volatile String password;
- private volatile GpodnetDevice selectedDevice;
-
- private View[] views;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- setTheme(UserPreferences.getTheme());
- super.onCreate(savedInstanceState);
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- setContentView(R.layout.gpodnetauth_activity);
- service = new GpodnetService(AntennapodHttpClient.getHttpClient(), GpodnetPreferences.getHostname());
-
- viewFlipper = findViewById(R.id.viewflipper);
- LayoutInflater inflater = (LayoutInflater)
- getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- views = new View[]{
- inflater.inflate(R.layout.gpodnetauth_credentials, viewFlipper, false),
- inflater.inflate(R.layout.gpodnetauth_device, viewFlipper, false),
- inflater.inflate(R.layout.gpodnetauth_finish, viewFlipper, false)
- };
- for (View view : views) {
- viewFlipper.addView(view);
- }
- advance();
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- finish();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private void setupLoginView(View view) {
- final EditText username = view.findViewById(R.id.etxtUsername);
- final EditText password = view.findViewById(R.id.etxtPassword);
- final Button login = view.findViewById(R.id.butLogin);
- final TextView txtvError = view.findViewById(R.id.txtvError);
- final ProgressBar progressBar = view.findViewById(R.id.progBarLogin);
-
- password.setOnEditorActionListener((v, actionID, event) ->
- actionID == EditorInfo.IME_ACTION_GO && login.performClick());
-
- login.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
-
- final String usernameStr = username.getText().toString();
- final String passwordStr = password.getText().toString();
-
- if (usernameHasUnwantedChars(usernameStr)) {
- txtvError.setText(R.string.gpodnetsync_username_characters_error);
- txtvError.setVisibility(View.VISIBLE);
- return;
- }
- if (BuildConfig.DEBUG) Log.d(TAG, "Checking login credentials");
- AsyncTask authTask = new AsyncTask() {
-
- volatile Exception exception;
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- login.setEnabled(false);
- progressBar.setVisibility(View.VISIBLE);
- txtvError.setVisibility(View.GONE);
- // hide the keyboard
- InputMethodManager inputManager = (InputMethodManager)
- getSystemService(Context.INPUT_METHOD_SERVICE);
- inputManager.hideSoftInputFromWindow(login.getWindowToken(),
- InputMethodManager.HIDE_NOT_ALWAYS);
-
- }
-
- @Override
- protected void onPostExecute(Void aVoid) {
- super.onPostExecute(aVoid);
- login.setEnabled(true);
- progressBar.setVisibility(View.GONE);
-
- if (exception == null) {
- advance();
- } else {
- txtvError.setText(exception.getCause().getMessage());
- txtvError.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- protected Void doInBackground(GpodnetService... params) {
- try {
- params[0].authenticate(usernameStr, passwordStr);
- GpodnetAuthenticationActivity.this.username = usernameStr;
- GpodnetAuthenticationActivity.this.password = passwordStr;
- } catch (GpodnetServiceException e) {
- e.printStackTrace();
- exception = e;
- }
- return null;
- }
- };
- authTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, service);
- }
- });
- }
-
- private void setupDeviceView(View view) {
- final EditText deviceID = view.findViewById(R.id.etxtDeviceID);
- final EditText caption = view.findViewById(R.id.etxtCaption);
- final Button createNewDevice = view.findViewById(R.id.butCreateNewDevice);
- final Button chooseDevice = view.findViewById(R.id.butChooseExistingDevice);
- final TextView txtvError = view.findViewById(R.id.txtvError);
- final ProgressBar progBarCreateDevice = view.findViewById(R.id.progbarCreateDevice);
- final Spinner spinnerDevices = view.findViewById(R.id.spinnerChooseDevice);
-
-
- // load device list
- final AtomicReference> devices = new AtomicReference<>();
- new AsyncTask>() {
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- chooseDevice.setEnabled(false);
- spinnerDevices.setEnabled(false);
- createNewDevice.setEnabled(false);
- }
-
- @Override
- protected void onPostExecute(List gpodnetDevices) {
- super.onPostExecute(gpodnetDevices);
- if (gpodnetDevices != null) {
- List deviceNames = new ArrayList<>();
- for (GpodnetDevice device : gpodnetDevices) {
- deviceNames.add(device.getCaption());
- }
- spinnerDevices.setAdapter(new ArrayAdapter<>(GpodnetAuthenticationActivity.this,
- android.R.layout.simple_spinner_dropdown_item, deviceNames));
- spinnerDevices.setEnabled(true);
- if (!deviceNames.isEmpty()) {
- chooseDevice.setEnabled(true);
- }
- devices.set(gpodnetDevices);
- deviceID.setText(generateDeviceID(gpodnetDevices));
- createNewDevice.setEnabled(true);
- }
- }
-
- @Override
- protected List doInBackground(GpodnetService... params) {
- try {
- return params[0].getDevices();
- } catch (GpodnetServiceException e) {
- e.printStackTrace();
- return null;
- }
- }
- }.execute(service);
-
-
- createNewDevice.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (checkDeviceIDText(deviceID, caption, txtvError, devices.get())) {
- final String deviceStr = deviceID.getText().toString();
- final String captionStr = caption.getText().toString();
-
- new AsyncTask() {
-
- private volatile Exception exception;
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- createNewDevice.setEnabled(false);
- chooseDevice.setEnabled(false);
- progBarCreateDevice.setVisibility(View.VISIBLE);
- txtvError.setVisibility(View.GONE);
- }
-
- @Override
- protected void onPostExecute(GpodnetDevice result) {
- super.onPostExecute(result);
- createNewDevice.setEnabled(true);
- chooseDevice.setEnabled(true);
- progBarCreateDevice.setVisibility(View.GONE);
- if (exception == null) {
- selectedDevice = result;
- advance();
- } else {
- txtvError.setText(exception.getMessage());
- txtvError.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- protected GpodnetDevice doInBackground(GpodnetService... params) {
- try {
- params[0].configureDevice(deviceStr, captionStr, GpodnetDevice.DeviceType.MOBILE);
- return new GpodnetDevice(deviceStr, captionStr, GpodnetDevice.DeviceType.MOBILE.toString(), 0);
- } catch (GpodnetServiceException e) {
- e.printStackTrace();
- exception = e;
- }
- return null;
- }
- }.execute(service);
- }
- }
- });
-
- chooseDevice.setOnClickListener(v -> {
- final int position = spinnerDevices.getSelectedItemPosition();
- if (position != AdapterView.INVALID_POSITION) {
- selectedDevice = devices.get().get(position);
- advance();
- }
- });
- }
-
-
- private String generateDeviceID(List gpodnetDevices) {
- // devices names must be of a certain form:
- // https://gpoddernet.readthedocs.org/en/latest/api/reference/general.html#devices
- // This is more restrictive than needed, but I think it makes for more readable names.
- String baseId = Build.MODEL.replaceAll("\\W", "");
- String id = baseId;
- int num = 0;
-
- while (isDeviceWithIdInList(id, gpodnetDevices)) {
- id = baseId + "_" + num;
- num++;
- }
-
- return id;
- }
-
- private boolean isDeviceWithIdInList(String id, List gpodnetDevices) {
- if (gpodnetDevices == null) {
- return false;
- }
- for (GpodnetDevice device : gpodnetDevices) {
- if (device.getId().equals(id)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean checkDeviceIDText(EditText deviceID, EditText caption, TextView txtvError, List devices) {
- String text = deviceID.getText().toString();
- if (text.length() == 0) {
- txtvError.setText(R.string.gpodnetauth_device_errorEmpty);
- txtvError.setVisibility(View.VISIBLE);
- return false;
- } else if (caption.length() == 0) {
- txtvError.setText(R.string.gpodnetauth_device_caption_errorEmpty);
- txtvError.setVisibility(View.VISIBLE);
- return false;
- } else {
- if (devices != null) {
- if (isDeviceWithIdInList(text, devices)) {
- txtvError.setText(R.string.gpodnetauth_device_errorAlreadyUsed);
- txtvError.setVisibility(View.VISIBLE);
- return false;
- }
- txtvError.setVisibility(View.GONE);
- return true;
- }
- return true;
- }
-
- }
-
- private void setupFinishView(View view) {
- final Button sync = view.findViewById(R.id.butSyncNow);
- final Button back = view.findViewById(R.id.butGoMainscreen);
-
- sync.setOnClickListener(v -> {
- finish();
- SyncService.sync(getApplicationContext());
- });
- back.setOnClickListener(v -> {
- Intent intent = new Intent(GpodnetAuthenticationActivity.this, MainActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- });
- }
-
- private void writeLoginCredentials() {
- if (BuildConfig.DEBUG) Log.d(TAG, "Writing login credentials");
- GpodnetPreferences.setUsername(username);
- GpodnetPreferences.setPassword(password);
- GpodnetPreferences.setDeviceID(selectedDevice.getId());
- }
-
- private void advance() {
- if (currentStep < STEP_FINISH) {
-
- View view = views[currentStep + 1];
- if (currentStep == STEP_DEFAULT) {
- setupLoginView(view);
- } else if (currentStep == STEP_LOGIN) {
- if (username == null || password == null) {
- throw new IllegalStateException("Username and password must not be null here");
- } else {
- setupDeviceView(view);
- }
- } else if (currentStep == STEP_DEVICE) {
- if (selectedDevice == null) {
- throw new IllegalStateException("Device must not be null here");
- } else {
- writeLoginCredentials();
- setupFinishView(view);
- }
- }
- if (currentStep != STEP_DEFAULT) {
- viewFlipper.showNext();
- }
- currentStep++;
- } else {
- finish();
- }
- }
-
- private boolean usernameHasUnwantedChars(String username) {
- Pattern special = Pattern.compile("[!@#$%&*()+=|<>?{}\\[\\]~]");
- Matcher containsUnwantedChars = special.matcher(username);
- return containsUnwantedChars.find();
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
deleted file mode 100644
index 8119dffcb..000000000
--- a/app/src/main/java/de/danoeh/antennapod/dialog/GpodnetSetHostnameDialog.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package de.danoeh.antennapod.dialog;
-
-import android.content.Context;
-import androidx.appcompat.app.AlertDialog;
-import android.text.Editable;
-import android.text.InputType;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
-import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
-
-/**
- * Creates a dialog that lets the user change the hostname for the gpodder.net service.
- */
-public class GpodnetSetHostnameDialog {
-
- private GpodnetSetHostnameDialog(){}
-
- private static final String TAG = "GpodnetSetHostnameDialog";
-
- public static AlertDialog createDialog(final Context context) {
- AlertDialog.Builder dialog = new AlertDialog.Builder(context);
- final EditText et = new EditText(context);
- et.setText(GpodnetPreferences.getHostname());
- et.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
- dialog.setTitle(R.string.pref_gpodnet_sethostname_title)
- .setView(setupContentView(context, et))
- .setPositiveButton(R.string.confirm_label, (dialog1, which) -> {
- final Editable e = et.getText();
- if (e != null) {
- GpodnetPreferences.setHostname(e.toString());
- }
- dialog1.dismiss();
- })
- .setNegativeButton(R.string.cancel_label, (dialog1, which) -> dialog1.cancel())
- .setNeutralButton(R.string.pref_gpodnet_sethostname_use_default_host, (dialog1, which) -> {
- GpodnetPreferences.setHostname(GpodnetService.DEFAULT_BASE_HOST);
- dialog1.dismiss();
- })
- .setCancelable(true);
- return dialog.show();
- }
-
- private static View setupContentView(Context context, EditText et) {
- LinearLayout ll = new LinearLayout(context);
- ll.addView(et);
- LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) et.getLayoutParams();
- if (params != null) {
- params.setMargins(8, 8, 8, 8);
- params.width = ViewGroup.LayoutParams.MATCH_PARENT;
- params.height = ViewGroup.LayoutParams.MATCH_PARENT;
- }
- return ll;
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java
new file mode 100644
index 000000000..26f090ade
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java
@@ -0,0 +1,322 @@
+package de.danoeh.antennapod.fragment.preferences;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.Paint;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.RadioGroup;
+import android.widget.TextView;
+import android.widget.ViewFlipper;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+import com.google.android.material.button.MaterialButton;
+import com.google.android.material.textfield.TextInputLayout;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
+import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
+import de.danoeh.antennapod.core.sync.SyncService;
+import de.danoeh.antennapod.core.sync.gpoddernet.GpodnetService;
+import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetDevice;
+import de.danoeh.antennapod.core.util.FileNameGenerator;
+import de.danoeh.antennapod.core.util.IntentUtils;
+import io.reactivex.Completable;
+import io.reactivex.Observable;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Guides the user through the authentication process.
+ */
+public class GpodderAuthenticationFragment extends DialogFragment {
+ public static final String TAG = "GpodnetAuthActivity";
+
+ private ViewFlipper viewFlipper;
+
+ private static final int STEP_DEFAULT = -1;
+ private static final int STEP_HOSTNAME = 0;
+ private static final int STEP_LOGIN = 1;
+ private static final int STEP_DEVICE = 2;
+ private static final int STEP_FINISH = 3;
+
+ private int currentStep = -1;
+
+ private GpodnetService service;
+ private volatile String username;
+ private volatile String password;
+ private volatile GpodnetDevice selectedDevice;
+ private List devices;
+ private List> synchronizedDevices;
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
+ dialog.setTitle(GpodnetService.DEFAULT_BASE_HOST);
+ dialog.setNegativeButton(R.string.cancel_label, null);
+ dialog.setCancelable(false);
+ this.setCancelable(false);
+
+ View root = View.inflate(getContext(), R.layout.gpodnetauth_dialog, null);
+ viewFlipper = root.findViewById(R.id.viewflipper);
+ advance();
+ dialog.setView(root);
+
+ return dialog.create();
+ }
+
+ private void setupHostView(View view) {
+ final Button selectHost = view.findViewById(R.id.chooseHostButton);
+ final RadioGroup serverRadioGroup = view.findViewById(R.id.serverRadioGroup);
+ final EditText serverUrlText = view.findViewById(R.id.serverUrlText);
+ if (!GpodnetService.DEFAULT_BASE_HOST.equals(GpodnetPreferences.getHostname())) {
+ serverUrlText.setText(GpodnetPreferences.getHostname());
+ }
+ final TextInputLayout serverUrlTextInput = view.findViewById(R.id.serverUrlTextInput);
+ serverRadioGroup.setOnCheckedChangeListener((group, checkedId) -> {
+ serverUrlTextInput.setVisibility(checkedId == R.id.customServerRadio ? View.VISIBLE : View.GONE);
+ });
+ selectHost.setOnClickListener(v -> {
+ if (serverRadioGroup.getCheckedRadioButtonId() == R.id.customServerRadio) {
+ GpodnetPreferences.setHostname(serverUrlText.getText().toString());
+ } else {
+ GpodnetPreferences.setHostname(GpodnetService.DEFAULT_BASE_HOST);
+ }
+ service = new GpodnetService(AntennapodHttpClient.getHttpClient(), GpodnetPreferences.getHostname());
+ getDialog().setTitle(GpodnetPreferences.getHostname());
+ advance();
+ });
+ }
+
+ private void setupLoginView(View view) {
+ final EditText username = view.findViewById(R.id.etxtUsername);
+ final EditText password = view.findViewById(R.id.etxtPassword);
+ final Button login = view.findViewById(R.id.butLogin);
+ final TextView txtvError = view.findViewById(R.id.credentialsError);
+ final ProgressBar progressBar = view.findViewById(R.id.progBarLogin);
+ final TextView createAccount = view.findViewById(R.id.createAccountButton);
+
+ createAccount.setPaintFlags(createAccount.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
+ createAccount.setOnClickListener(v -> IntentUtils.openInBrowser(getContext(), "https://gpodder.net/register/"));
+
+ password.setOnEditorActionListener((v, actionID, event) ->
+ actionID == EditorInfo.IME_ACTION_GO && login.performClick());
+
+ login.setOnClickListener(v -> {
+ final String usernameStr = username.getText().toString();
+ final String passwordStr = password.getText().toString();
+
+ if (usernameHasUnwantedChars(usernameStr)) {
+ txtvError.setText(R.string.gpodnetsync_username_characters_error);
+ txtvError.setVisibility(View.VISIBLE);
+ return;
+ }
+
+ login.setEnabled(false);
+ progressBar.setVisibility(View.VISIBLE);
+ txtvError.setVisibility(View.GONE);
+ InputMethodManager inputManager = (InputMethodManager) getContext()
+ .getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputManager.hideSoftInputFromWindow(login.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+
+ Completable.fromAction(() -> {
+ service.authenticate(usernameStr, passwordStr);
+ devices = service.getDevices();
+ synchronizedDevices = service.getSynchronizedDevices();
+ GpodderAuthenticationFragment.this.username = usernameStr;
+ GpodderAuthenticationFragment.this.password = passwordStr;
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(() -> {
+ login.setEnabled(true);
+ progressBar.setVisibility(View.GONE);
+ advance();
+ }, error -> {
+ login.setEnabled(true);
+ progressBar.setVisibility(View.GONE);
+ txtvError.setText(error.getCause().getMessage());
+ txtvError.setVisibility(View.VISIBLE);
+ });
+
+ });
+ }
+
+ private void setupDeviceView(View view) {
+ final EditText deviceName = view.findViewById(R.id.deviceName);
+ final LinearLayout deviceGroups = view.findViewById(R.id.deviceGroups);
+ deviceName.setText(generateDeviceName());
+
+ MaterialButton newGroupButton = view.findViewById(R.id.startNewGroupButton);
+ newGroupButton.setOnClickListener(v -> createDevice(view, null));
+
+ for (List syncGroup : synchronizedDevices) {
+ StringBuilder devicesString = new StringBuilder();
+ for (int i = 0; i < syncGroup.size(); i++) {
+ String deviceId = syncGroup.get(i);
+ devicesString.append(findDevice(deviceId).getCaption());
+ if (i != syncGroup.size() - 1) {
+ devicesString.append("\n");
+ }
+ }
+
+ View groupView = View.inflate(getContext(), R.layout.gpodnetauth_device_group, null);
+ ((TextView) groupView.findViewById(R.id.groupContents)).setText(devicesString.toString());
+ groupView.findViewById(R.id.selectGroupButton).setOnClickListener(v -> createDevice(view, syncGroup));
+ deviceGroups.addView(groupView);
+ }
+ }
+
+ private void createDevice(View view, List group) {
+ final EditText deviceName = view.findViewById(R.id.deviceName);
+ final TextView txtvError = view.findViewById(R.id.deviceSelectError);
+ final ProgressBar progBarCreateDevice = view.findViewById(R.id.progbarCreateDevice);
+ final LinearLayout deviceGroups = view.findViewById(R.id.deviceGroups);
+ final MaterialButton newGroupButton = view.findViewById(R.id.startNewGroupButton);
+
+ String deviceNameStr = deviceName.getText().toString();
+ if (isDeviceInList(deviceNameStr)) {
+ return;
+ }
+ deviceGroups.setVisibility(View.GONE);
+ progBarCreateDevice.setVisibility(View.VISIBLE);
+ txtvError.setVisibility(View.GONE);
+ newGroupButton.setVisibility(View.GONE);
+ deviceName.setEnabled(false);
+
+ Observable.fromCallable(() -> {
+ String deviceId = generateDeviceId(deviceNameStr);
+ service.configureDevice(deviceId, deviceNameStr, GpodnetDevice.DeviceType.MOBILE);
+
+ if (group != null) {
+ List newGroup = new ArrayList<>(group);
+ newGroup.add(deviceId);
+ service.linkDevices(newGroup);
+ }
+ return new GpodnetDevice(deviceId, deviceNameStr, GpodnetDevice.DeviceType.MOBILE.toString(), 0);
+ })
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(device -> {
+ progBarCreateDevice.setVisibility(View.GONE);
+ selectedDevice = device;
+ advance();
+ }, error -> {
+ deviceName.setEnabled(true);
+ newGroupButton.setVisibility(View.VISIBLE);
+ deviceGroups.setVisibility(View.VISIBLE);
+ progBarCreateDevice.setVisibility(View.GONE);
+ txtvError.setText(error.getMessage());
+ txtvError.setVisibility(View.VISIBLE);
+ });
+ }
+
+ private String generateDeviceName() {
+ String baseName = getString(R.string.gpodnetauth_device_name_default, Build.MODEL);
+ String name = baseName;
+ int num = 1;
+ while (isDeviceInList(name)) {
+ name = baseName + " (" + num + ")";
+ num++;
+ }
+ return name;
+ }
+
+ private String generateDeviceId(String name) {
+ // devices names must be of a certain form:
+ // https://gpoddernet.readthedocs.org/en/latest/api/reference/general.html#devices
+ return FileNameGenerator.generateFileName(name).replaceAll("\\W", "_").toLowerCase(Locale.US);
+ }
+
+ private boolean isDeviceInList(String name) {
+ if (devices == null) {
+ return false;
+ }
+ String id = generateDeviceId(name);
+ for (GpodnetDevice device : devices) {
+ if (device.getId().equals(id) || device.getCaption().equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private GpodnetDevice findDevice(String id) {
+ if (devices == null) {
+ return null;
+ }
+ for (GpodnetDevice device : devices) {
+ if (device.getId().equals(id)) {
+ return device;
+ }
+ }
+ return null;
+ }
+
+ private void setupFinishView(View view) {
+ final Button sync = view.findViewById(R.id.butSyncNow);
+
+ sync.setOnClickListener(v -> {
+ dismiss();
+ SyncService.sync(getContext());
+ });
+ }
+
+ private void writeLoginCredentials() {
+ GpodnetPreferences.setUsername(username);
+ GpodnetPreferences.setPassword(password);
+ GpodnetPreferences.setDeviceID(selectedDevice.getId());
+ }
+
+ private void advance() {
+ if (currentStep < STEP_FINISH) {
+
+ View view = viewFlipper.getChildAt(currentStep + 1);
+ if (currentStep == STEP_DEFAULT) {
+ setupHostView(view);
+ } else if (currentStep == STEP_HOSTNAME) {
+ setupLoginView(view);
+ } else if (currentStep == STEP_LOGIN) {
+ if (username == null || password == null) {
+ throw new IllegalStateException("Username and password must not be null here");
+ } else {
+ setupDeviceView(view);
+ }
+ } else if (currentStep == STEP_DEVICE) {
+ if (selectedDevice == null) {
+ throw new IllegalStateException("Device must not be null here");
+ } else {
+ writeLoginCredentials();
+ setupFinishView(view);
+ }
+ }
+ if (currentStep != STEP_DEFAULT) {
+ viewFlipper.showNext();
+ }
+ currentStep++;
+ } else {
+ dismiss();
+ }
+ }
+
+ private boolean usernameHasUnwantedChars(String username) {
+ Pattern special = Pattern.compile("[!@#$%&*()+=|<>?{}\\[\\]~]");
+ Matcher containsUnwantedChars = special.matcher(username);
+ return containsUnwantedChars.find();
+ }
+}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
index eb23a5eb1..4fb734e17 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderPreferencesFragment.java
@@ -14,19 +14,16 @@ import de.danoeh.antennapod.core.event.SyncServiceEvent;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.sync.SyncService;
import de.danoeh.antennapod.dialog.AuthenticationDialog;
-import de.danoeh.antennapod.dialog.GpodnetSetHostnameDialog;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
-
public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
private static final String PREF_GPODNET_LOGIN = "pref_gpodnet_authenticate";
private static final String PREF_GPODNET_SETLOGIN_INFORMATION = "pref_gpodnet_setlogin_information";
private static final String PREF_GPODNET_SYNC = "pref_gpodnet_sync";
private static final String PREF_GPODNET_FORCE_FULL_SYNC = "pref_gpodnet_force_full_sync";
private static final String PREF_GPODNET_LOGOUT = "pref_gpodnet_logout";
- private static final String PREF_GPODNET_HOSTNAME = "pref_gpodnet_hostname";
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@@ -51,6 +48,7 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void syncStatusChanged(SyncServiceEvent event) {
+ updateGpodnetPreferenceScreen();
if (!GpodnetPreferences.loggedIn()) {
return;
}
@@ -66,6 +64,10 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
private void setupGpodderScreen() {
final Activity activity = getActivity();
+ findPreference(PREF_GPODNET_LOGIN).setOnPreferenceClickListener(preference -> {
+ new GpodderAuthenticationFragment().show(getChildFragmentManager(), GpodderAuthenticationFragment.TAG);
+ return true;
+ });
findPreference(PREF_GPODNET_SETLOGIN_INFORMATION)
.setOnPreferenceClickListener(preference -> {
AuthenticationDialog dialog = new AuthenticationDialog(activity,
@@ -94,11 +96,6 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
updateGpodnetPreferenceScreen();
return true;
});
- findPreference(PREF_GPODNET_HOSTNAME).setOnPreferenceClickListener(preference -> {
- GpodnetSetHostnameDialog.createDialog(activity).setOnDismissListener(
- dialog -> updateGpodnetPreferenceScreen());
- return true;
- });
}
private void updateGpodnetPreferenceScreen() {
@@ -119,7 +116,6 @@ public class GpodderPreferencesFragment extends PreferenceFragmentCompat {
} else {
findPreference(PREF_GPODNET_LOGOUT).setSummary(null);
}
- findPreference(PREF_GPODNET_HOSTNAME).setSummary(GpodnetPreferences.getHostname());
}
private void updateLastGpodnetSyncReport(boolean successful, long lastTime) {
diff --git a/app/src/main/res/layout/gpodnetauth_activity.xml b/app/src/main/res/layout/gpodnetauth_activity.xml
deleted file mode 100644
index c096c20cf..000000000
--- a/app/src/main/res/layout/gpodnetauth_activity.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/gpodnetauth_credentials.xml b/app/src/main/res/layout/gpodnetauth_credentials.xml
index 895b0999c..291b98da3 100644
--- a/app/src/main/res/layout/gpodnetauth_credentials.xml
+++ b/app/src/main/res/layout/gpodnetauth_credentials.xml
@@ -1,96 +1,97 @@
-
-
-
+ android:orientation="vertical">
-
+
-
+
-
+
+
-
+
-
+
-
+
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/gpodnetauth_device.xml b/app/src/main/res/layout/gpodnetauth_device.xml
index 7837121e1..10ba5486f 100644
--- a/app/src/main/res/layout/gpodnetauth_device.xml
+++ b/app/src/main/res/layout/gpodnetauth_device.xml
@@ -1,114 +1,62 @@
-
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+
+
+
+
+
+ style="@style/AntennaPod.TextView.Heading"
+ android:layout_marginTop="16dp"
+ android:text="@string/gpodnetauth_sync_groups"/>
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ android:visibility="gone" />
-
-
-
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/gpodnetauth_device_group.xml b/app/src/main/res/layout/gpodnetauth_device_group.xml
new file mode 100644
index 000000000..8660779b3
--- /dev/null
+++ b/app/src/main/res/layout/gpodnetauth_device_group.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/gpodnetauth_dialog.xml b/app/src/main/res/layout/gpodnetauth_dialog.xml
new file mode 100644
index 000000000..a70b76a49
--- /dev/null
+++ b/app/src/main/res/layout/gpodnetauth_dialog.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/gpodnetauth_finish.xml b/app/src/main/res/layout/gpodnetauth_finish.xml
index fdaa0d5d0..f0bcfd4dc 100644
--- a/app/src/main/res/layout/gpodnetauth_finish.xml
+++ b/app/src/main/res/layout/gpodnetauth_finish.xml
@@ -1,46 +1,28 @@
-
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
-
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/gpodnetauth_host.xml b/app/src/main/res/layout/gpodnetauth_host.xml
new file mode 100644
index 000000000..52c5fdb5d
--- /dev/null
+++ b/app/src/main/res/layout/gpodnetauth_host.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/preferences_gpodder.xml b/app/src/main/res/xml/preferences_gpodder.xml
index 7bddbf245..a210b8e11 100644
--- a/app/src/main/res/xml/preferences_gpodder.xml
+++ b/app/src/main/res/xml/preferences_gpodder.xml
@@ -1,13 +1,14 @@
-
-
+
-
-
+ android:summary="@string/pref_gpodnet_authenticate_sum"/>
-
diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java
index 62c8ce5f3..75ac42b31 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java
@@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.sync.gpoddernet;
import android.util.Log;
import androidx.annotation.NonNull;
+import de.danoeh.antennapod.core.BuildConfig;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.sync.gpoddernet.model.GpodnetDevice;
import de.danoeh.antennapod.core.sync.model.EpisodeAction;
@@ -36,6 +37,7 @@ import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -47,6 +49,7 @@ public class GpodnetService implements ISyncService {
public static final String TAG = "GpodnetService";
public static final String DEFAULT_BASE_HOST = "gpodder.net";
private static final String BASE_SCHEME = "https";
+ private static final int PORT = 443;
private static final int UPLOAD_BULK_SIZE = 30;
private static final MediaType TEXT = MediaType.parse("plain/text; charset=utf-8");
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
@@ -71,7 +74,8 @@ public class GpodnetService implements ISyncService {
public List getTopTags(int count) throws GpodnetServiceException {
URL url;
try {
- url = new URI(BASE_SCHEME, baseHost, String.format(Locale.US, "/api/2/tags/%d.json", count), null).toURL();
+ url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format(Locale.US, "/api/2/tags/%d.json", count), null, null).toURL();
} catch (MalformedURLException | URISyntaxException e) {
e.printStackTrace();
throw new GpodnetServiceException(e);
@@ -104,8 +108,8 @@ public class GpodnetService implements ISyncService {
public List getPodcastsForTag(@NonNull GpodnetTag tag, int count)
throws GpodnetServiceException {
try {
- URL url = new URI(BASE_SCHEME, baseHost, String.format(Locale.US,
- "/api/2/tag/%s/%d.json", tag.getTag(), count), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format(Locale.US, "/api/2/tag/%s/%d.json", tag.getTag(), count), null, null).toURL();
Request.Builder request = new Request.Builder().url(url);
String response = executeRequest(request);
@@ -130,7 +134,8 @@ public class GpodnetService implements ISyncService {
}
try {
- URL url = new URI(BASE_SCHEME, baseHost, String.format(Locale.US, "/toplist/%d.json", count), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format(Locale.US, "/toplist/%d.json", count), null, null).toURL();
Request.Builder request = new Request.Builder().url(url);
String response = executeRequest(request);
@@ -161,8 +166,8 @@ public class GpodnetService implements ISyncService {
}
try {
- URL url = new URI(BASE_SCHEME, baseHost,
- String.format(Locale.US, "/suggestions/%d.json", count), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format(Locale.US, "/suggestions/%d.json", count), null, null).toURL();
Request.Builder request = new Request.Builder().url(url);
String response = executeRequest(request);
@@ -187,7 +192,7 @@ public class GpodnetService implements ISyncService {
.format(Locale.US, "q=%s&scale_logo=%d", query, scaledLogoSize) : String
.format("q=%s", query);
try {
- URL url = new URI(BASE_SCHEME, null, baseHost, -1, "/search.json",
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT, "/search.json",
parameters, null).toURL();
Request.Builder request = new Request.Builder().url(url);
String response = executeRequest(request);
@@ -214,7 +219,8 @@ public class GpodnetService implements ISyncService {
public List getDevices() throws GpodnetServiceException {
requireLoggedIn();
try {
- URL url = new URI(BASE_SCHEME, baseHost, String.format("/api/2/devices/%s.json", username), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/api/2/devices/%s.json", username), null, null).toURL();
Request.Builder request = new Request.Builder().url(url);
String response = executeRequest(request);
JSONArray devicesArray = new JSONArray(response);
@@ -225,6 +231,45 @@ public class GpodnetService implements ISyncService {
}
}
+ /**
+ * Returns synchronization status of devices.
+ *
+ * This method requires authentication.
+ *
+ * @throws GpodnetServiceAuthenticationException If there is an authentication error.
+ */
+ public List> getSynchronizedDevices() throws GpodnetServiceException {
+ requireLoggedIn();
+ try {
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/api/2/sync-devices/%s.json", username), null, null).toURL();
+ Request.Builder request = new Request.Builder().url(url);
+ String response = executeRequest(request);
+ JSONObject syncStatus = new JSONObject(response);
+ List> result = new ArrayList<>();
+
+ JSONArray synchronizedDevices = syncStatus.getJSONArray("synchronized");
+ for (int i = 0; i < synchronizedDevices.length(); i++) {
+ JSONArray groupDevices = synchronizedDevices.getJSONArray(i);
+ List group = new ArrayList<>();
+ for (int j = 0; j < groupDevices.length(); j++) {
+ group.add(groupDevices.getString(j));
+ }
+ result.add(group);
+ }
+
+ JSONArray notSynchronizedDevices = syncStatus.getJSONArray("not-synchronized");
+ for (int i = 0; i < notSynchronizedDevices.length(); i++) {
+ result.add(Collections.singletonList(notSynchronizedDevices.getString(i)));
+ }
+
+ return result;
+ } catch (JSONException | MalformedURLException | URISyntaxException e) {
+ e.printStackTrace();
+ throw new GpodnetServiceException(e);
+ }
+ }
+
/**
* Configures the device of a given user.
*
@@ -237,8 +282,8 @@ public class GpodnetService implements ISyncService {
throws GpodnetServiceException {
requireLoggedIn();
try {
- URL url = new URI(BASE_SCHEME, baseHost, String.format(
- "/api/2/devices/%s/%s.json", username, deviceId), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/api/2/devices/%s/%s.json", username, deviceId), null, null).toURL();
String content;
if (caption != null || type != null) {
JSONObject jsonContent = new JSONObject();
@@ -261,6 +306,39 @@ public class GpodnetService implements ISyncService {
}
}
+ /**
+ * Links devices for synchronization.
+ *
+ * This method requires authentication.
+ *
+ * @throws GpodnetServiceAuthenticationException If there is an authentication error.
+ */
+ public void linkDevices(@NonNull List deviceIds) throws GpodnetServiceException {
+ requireLoggedIn();
+ try {
+ final URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/api/2/sync-devices/%s.json", username), null, null).toURL();
+ JSONObject jsonContent = new JSONObject();
+ JSONArray group = new JSONArray();
+ for (String deviceId : deviceIds) {
+ group.put(deviceId);
+ }
+
+ JSONArray synchronizedGroups = new JSONArray();
+ synchronizedGroups.put(group);
+ jsonContent.put("synchronize", synchronizedGroups);
+ jsonContent.put("stop-synchronize", new JSONArray());
+
+ Log.d("aaaa", jsonContent.toString());
+ RequestBody body = RequestBody.create(JSON, jsonContent.toString());
+ Request.Builder request = new Request.Builder().post(body).url(url);
+ executeRequest(request);
+ } catch (JSONException | MalformedURLException | URISyntaxException e) {
+ e.printStackTrace();
+ throw new GpodnetServiceException(e);
+ }
+ }
+
/**
* Returns the subscriptions of a specific device.
*
@@ -273,8 +351,8 @@ public class GpodnetService implements ISyncService {
public String getSubscriptionsOfDevice(@NonNull String deviceId) throws GpodnetServiceException {
requireLoggedIn();
try {
- URL url = new URI(BASE_SCHEME, baseHost, String.format(
- "/subscriptions/%s/%s.opml", username, deviceId), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/subscriptions/%s/%s.opml", username, deviceId), null, null).toURL();
Request.Builder request = new Request.Builder().url(url);
return executeRequest(request);
} catch (MalformedURLException | URISyntaxException e) {
@@ -295,7 +373,8 @@ public class GpodnetService implements ISyncService {
public String getSubscriptionsOfUser() throws GpodnetServiceException {
requireLoggedIn();
try {
- URL url = new URI(BASE_SCHEME, baseHost, String.format("/subscriptions/%s.opml", username), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/subscriptions/%s.opml", username), null, null).toURL();
Request.Builder request = new Request.Builder().url(url);
return executeRequest(request);
} catch (MalformedURLException | URISyntaxException e) {
@@ -319,8 +398,8 @@ public class GpodnetService implements ISyncService {
throws GpodnetServiceException {
requireLoggedIn();
try {
- URL url = new URI(BASE_SCHEME, baseHost, String.format(
- "/subscriptions/%s/%s.txt", username, deviceId), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/subscriptions/%s/%s.txt", username, deviceId), null, null).toURL();
StringBuilder builder = new StringBuilder();
for (String s : subscriptions) {
builder.append(s);
@@ -353,8 +432,8 @@ public class GpodnetService implements ISyncService {
@NonNull Collection removed) throws GpodnetServiceException {
requireLoggedIn();
try {
- URL url = new URI(BASE_SCHEME, baseHost, String.format(
- "/api/2/subscriptions/%s/%s.json", username, deviceId), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/api/2/subscriptions/%s/%s.json", username, deviceId), null, null).toURL();
final JSONObject requestObject = new JSONObject();
requestObject.put("add", new JSONArray(added));
@@ -389,8 +468,7 @@ public class GpodnetService implements ISyncService {
String params = String.format(Locale.US, "since=%d", timestamp);
String path = String.format("/api/2/subscriptions/%s/%s.json", username, deviceId);
try {
- URL url = new URI(BASE_SCHEME, null, baseHost, -1, path, params,
- null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT, path, params, null).toURL();
Request.Builder request = new Request.Builder().url(url);
String response = executeRequest(request);
@@ -432,8 +510,8 @@ public class GpodnetService implements ISyncService {
throws SyncServiceException {
try {
Log.d(TAG, "Uploading partial actions " + from + " to " + to + " of " + episodeActions.size());
- URL url = new URI(BASE_SCHEME, baseHost, String.format(
- "/api/2/episodes/%s.json", username), null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/api/2/episodes/%s.json", username), null, null).toURL();
final JSONArray list = new JSONArray();
for (int i = from; i < to; i++) {
@@ -471,7 +549,7 @@ public class GpodnetService implements ISyncService {
String params = String.format(Locale.US, "since=%d", timestamp);
String path = String.format("/api/2/episodes/%s.json", username);
try {
- URL url = new URI(BASE_SCHEME, null, baseHost, -1, path, params, null).toURL();
+ URL url = new URI(BASE_SCHEME, null, baseHost, PORT, path, params, null).toURL();
Request.Builder request = new Request.Builder().url(url);
String response = executeRequest(request);
@@ -497,7 +575,8 @@ public class GpodnetService implements ISyncService {
public void authenticate(@NonNull String username, @NonNull String password) throws GpodnetServiceException {
URL url;
try {
- url = new URI(BASE_SCHEME, baseHost, String.format("/api/2/auth/%s/login.json", username), null).toURL();
+ url = new URI(BASE_SCHEME, null, baseHost, PORT,
+ String.format("/api/2/auth/%s/login.json", username), null, null).toURL();
} catch (MalformedURLException | URISyntaxException e) {
e.printStackTrace();
throw new GpodnetServiceException(e);
@@ -567,6 +646,13 @@ public class GpodnetService implements ISyncService {
if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
throw new GpodnetServiceAuthenticationException("Wrong username or password");
} else {
+ if (BuildConfig.DEBUG) {
+ try {
+ Log.d(TAG, response.body().string());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
throw new GpodnetServiceBadStatusCodeException("Bad response code: " + responseCode, responseCode);
}
}
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index d32f751f4..d8e4a1ff3 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -468,8 +468,6 @@
Customize the number of seconds to jump forward when the fast forward button is clickedRewind Skip TimeCustomize the number of seconds to jump backwards when the rewind button is clicked
- Set hostname
- Use default hostHigh Notification priorityThis usually expands the notification to show playback buttons.Persistent Playback Controls
@@ -631,23 +629,24 @@
SUGGESTIONSSearch gpodder.netLogin
- Welcome to the gpodder.net login process. First, type in your login information:Login
- If you do not have an account yet, you can create one here:\nhttps://gpodder.net/register/
+ Create accountUsernamePassword
- Device Selection
+ Gpodder.net is an open-source podcast synchronization service that is independent of the AntennaPod project.
+ Official gpodder.net server
+ Custom server
+ Hostname
+ Select serverCreate a new device to use for your gpodder.net account or choose an existing one:
- Device ID:\u0020
- Caption
- Create new device
- Choose existing device:
- Device ID must not be empty
- Device ID already in use
+ Device name
+ AntennaPod on %1$sCaption must not be empty
+ Synchronization groups
+ Select
+ Use new groupChoose
- Login successful!Congratulations! Your gpodder.net account is now linked with your device. AntennaPod will from now on automatically sync subscriptions on your device with your gpodder.net account.Start sync nowGo to main screen
From 34e9c318996147e266b524d5ec1d1fae4f9b17c9 Mon Sep 17 00:00:00 2001
From: ByteHamster
Date: Sat, 2 Jan 2021 11:03:57 +0100
Subject: [PATCH 003/128] Revert back to device selection instead of linking
Until this is fixed upstream on the gpodder.net server.
---
.../GpodderAuthenticationFragment.java | 46 ++++++-------------
.../main/res/layout/gpodnetauth_device.xml | 19 ++++----
.../res/layout/gpodnetauth_device_group.xml | 35 --------------
.../res/layout/gpodnetauth_device_row.xml | 13 ++++++
core/src/main/res/values/strings.xml | 5 +-
5 files changed, 37 insertions(+), 81 deletions(-)
delete mode 100644 app/src/main/res/layout/gpodnetauth_device_group.xml
create mode 100644 app/src/main/res/layout/gpodnetauth_device_row.xml
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java
index 26f090ade..187e8480b 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/GpodderAuthenticationFragment.java
@@ -34,7 +34,6 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
-import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
@@ -61,7 +60,6 @@ public class GpodderAuthenticationFragment extends DialogFragment {
private volatile String password;
private volatile GpodnetDevice selectedDevice;
private List devices;
- private List> synchronizedDevices;
@NonNull
@Override
@@ -137,7 +135,6 @@ public class GpodderAuthenticationFragment extends DialogFragment {
Completable.fromAction(() -> {
service.authenticate(usernameStr, passwordStr);
devices = service.getDevices();
- synchronizedDevices = service.getSynchronizedDevices();
GpodderAuthenticationFragment.this.username = usernameStr;
GpodderAuthenticationFragment.this.password = passwordStr;
})
@@ -159,55 +156,40 @@ public class GpodderAuthenticationFragment extends DialogFragment {
private void setupDeviceView(View view) {
final EditText deviceName = view.findViewById(R.id.deviceName);
- final LinearLayout deviceGroups = view.findViewById(R.id.deviceGroups);
+ final LinearLayout devicesContainer = view.findViewById(R.id.devicesContainer);
deviceName.setText(generateDeviceName());
- MaterialButton newGroupButton = view.findViewById(R.id.startNewGroupButton);
- newGroupButton.setOnClickListener(v -> createDevice(view, null));
+ MaterialButton createDeviceButton = view.findViewById(R.id.createDeviceButton);
+ createDeviceButton.setOnClickListener(v -> createDevice(view));
- for (List syncGroup : synchronizedDevices) {
- StringBuilder devicesString = new StringBuilder();
- for (int i = 0; i < syncGroup.size(); i++) {
- String deviceId = syncGroup.get(i);
- devicesString.append(findDevice(deviceId).getCaption());
- if (i != syncGroup.size() - 1) {
- devicesString.append("\n");
- }
- }
-
- View groupView = View.inflate(getContext(), R.layout.gpodnetauth_device_group, null);
- ((TextView) groupView.findViewById(R.id.groupContents)).setText(devicesString.toString());
- groupView.findViewById(R.id.selectGroupButton).setOnClickListener(v -> createDevice(view, syncGroup));
- deviceGroups.addView(groupView);
+ for (GpodnetDevice device : devices) {
+ View row = View.inflate(getContext(), R.layout.gpodnetauth_device_row, null);
+ Button selectDeviceButton = row.findViewById(R.id.selectDeviceButton);
+ selectDeviceButton.setOnClickListener(v -> {
+ selectedDevice = device;
+ advance();
+ });
+ selectDeviceButton.setText(device.getCaption());
+ devicesContainer.addView(row);
}
}
- private void createDevice(View view, List group) {
+ private void createDevice(View view) {
final EditText deviceName = view.findViewById(R.id.deviceName);
final TextView txtvError = view.findViewById(R.id.deviceSelectError);
final ProgressBar progBarCreateDevice = view.findViewById(R.id.progbarCreateDevice);
- final LinearLayout deviceGroups = view.findViewById(R.id.deviceGroups);
- final MaterialButton newGroupButton = view.findViewById(R.id.startNewGroupButton);
String deviceNameStr = deviceName.getText().toString();
if (isDeviceInList(deviceNameStr)) {
return;
}
- deviceGroups.setVisibility(View.GONE);
progBarCreateDevice.setVisibility(View.VISIBLE);
txtvError.setVisibility(View.GONE);
- newGroupButton.setVisibility(View.GONE);
deviceName.setEnabled(false);
Observable.fromCallable(() -> {
String deviceId = generateDeviceId(deviceNameStr);
service.configureDevice(deviceId, deviceNameStr, GpodnetDevice.DeviceType.MOBILE);
-
- if (group != null) {
- List newGroup = new ArrayList<>(group);
- newGroup.add(deviceId);
- service.linkDevices(newGroup);
- }
return new GpodnetDevice(deviceId, deviceNameStr, GpodnetDevice.DeviceType.MOBILE.toString(), 0);
})
.subscribeOn(Schedulers.io())
@@ -218,8 +200,6 @@ public class GpodderAuthenticationFragment extends DialogFragment {
advance();
}, error -> {
deviceName.setEnabled(true);
- newGroupButton.setVisibility(View.VISIBLE);
- deviceGroups.setVisibility(View.VISIBLE);
progBarCreateDevice.setVisibility(View.GONE);
txtvError.setText(error.getMessage());
txtvError.setVisibility(View.VISIBLE);
diff --git a/app/src/main/res/layout/gpodnetauth_device.xml b/app/src/main/res/layout/gpodnetauth_device.xml
index 10ba5486f..656ba0889 100644
--- a/app/src/main/res/layout/gpodnetauth_device.xml
+++ b/app/src/main/res/layout/gpodnetauth_device.xml
@@ -21,12 +21,19 @@
+
+
+ android:text="@string/gpodnetauth_existing_devices"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/gpodnetauth_device_row.xml b/app/src/main/res/layout/gpodnetauth_device_row.xml
new file mode 100644
index 000000000..d39c00571
--- /dev/null
+++ b/app/src/main/res/layout/gpodnetauth_device_row.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index d8e4a1ff3..dca326619 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -642,9 +642,8 @@
Device nameAntennaPod on %1$sCaption must not be empty
- Synchronization groups
- Select
- Use new group
+ Existing devices
+ Create deviceChooseCongratulations! Your gpodder.net account is now linked with your device. AntennaPod will from now on automatically sync subscriptions on your device with your gpodder.net account.
From 0b715d549483840de1f12c07892904092c49c3e9 Mon Sep 17 00:00:00 2001
From: Herbert Reiter <46045854+damoasda@users.noreply.github.com>
Date: Sat, 2 Jan 2021 12:59:26 +0100
Subject: [PATCH 004/128] Run DateUtilsTest as Unit Test (#4805)
---
.../antennapod/core/util/DateUtils.java | 7 ++-
.../antennapod/core/util/DateUtilsTest.java | 48 +++++++------------
2 files changed, 23 insertions(+), 32 deletions(-)
rename core/src/{androidTest => test}/java/de/danoeh/antennapod/core/util/DateUtilsTest.java (79%)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
index 833ff33f1..196583bcd 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
@@ -30,9 +30,12 @@ public class DateUtils {
}
String date = input.trim().replace('/', '-').replaceAll("( ){2,}+", " ");
+ // remove colon from timezone to avoid differences between Android and Java SimpleDateFormat
+ date = date.replaceAll("([+-]\\d\\d):(\\d\\d)$", "$1$2");
+
// CEST is widely used but not in the "ISO 8601 Time zone" list. Let's hack around.
- date = date.replaceAll("CEST$", "+02:00");
- date = date.replaceAll("CET$", "+01:00");
+ date = date.replaceAll("CEST$", "+0200");
+ date = date.replaceAll("CET$", "+0100");
// some generators use "Sept" for September
date = date.replaceAll("\\bSept\\b", "Sep");
diff --git a/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
similarity index 79%
rename from core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
rename to core/src/test/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
index 5d98f133c..92888ae8b 100644
--- a/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
@@ -1,6 +1,5 @@
package de.danoeh.antennapod.core.util;
-import androidx.test.filters.SmallTest;
import org.junit.Test;
import java.util.Calendar;
@@ -12,16 +11,11 @@ import static org.junit.Assert.assertEquals;
/**
* Unit test for {@link DateUtils}.
- *
- * Note: It NEEDS to be run in android devices, i.e., it cannot be run in standard JDK, because
- * the test invokes some android platform-specific behavior in the underlying
- * {@link java.text.SimpleDateFormat} used by {@link DateUtils}.
- *
*/
-@SmallTest
public class DateUtilsTest {
+
@Test
- public void testParseDateWithMicroseconds() throws Exception {
+ public void testParseDateWithMicroseconds() {
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis() + 963);
@@ -30,7 +24,7 @@ public class DateUtilsTest {
}
@Test
- public void testParseDateWithCentiseconds() throws Exception {
+ public void testParseDateWithCentiseconds() {
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis() + 960);
@@ -39,17 +33,17 @@ public class DateUtilsTest {
}
@Test
- public void testParseDateWithDeciseconds() throws Exception {
+ public void testParseDateWithDeciseconds() {
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 13, 31, 4);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis() + 900);
Date actual = DateUtils.parse("2015-03-28T13:31:04.9");
- assertEquals(expected.getTime()/1000, actual.getTime()/1000);
- assertEquals(900, actual.getTime()%1000);
+ assertEquals(expected.getTime() / 1000, actual.getTime() / 1000);
+ assertEquals(900, actual.getTime() % 1000);
}
@Test
- public void testParseDateWithMicrosecondsAndTimezone() throws Exception {
+ public void testParseDateWithMicrosecondsAndTimezone() {
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 6, 31, 4);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis() + 963);
@@ -58,7 +52,7 @@ public class DateUtilsTest {
}
@Test
- public void testParseDateWithCentisecondsAndTimezone() throws Exception {
+ public void testParseDateWithCentisecondsAndTimezone() {
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 6, 31, 4);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis() + 960);
@@ -67,17 +61,17 @@ public class DateUtilsTest {
}
@Test
- public void testParseDateWithDecisecondsAndTimezone() throws Exception {
+ public void testParseDateWithDecisecondsAndTimezone() {
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 6, 31, 4);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis() + 900);
Date actual = DateUtils.parse("2015-03-28T13:31:04.9 +0700");
- assertEquals(expected.getTime()/1000, actual.getTime()/1000);
- assertEquals(900, actual.getTime()%1000);
+ assertEquals(expected.getTime() / 1000, actual.getTime() / 1000);
+ assertEquals(900, actual.getTime() % 1000);
}
@Test
- public void testParseDateWithTimezoneName() throws Exception {
+ public void testParseDateWithTimezoneName() {
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 6, 31, 4);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis());
@@ -86,7 +80,7 @@ public class DateUtilsTest {
}
@Test
- public void testParseDateWithTimezoneName2() throws Exception {
+ public void testParseDateWithTimezoneName2() {
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 6, 31, 0);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis());
@@ -95,7 +89,7 @@ public class DateUtilsTest {
}
@Test
- public void testParseDateWithTimeZoneOffset() throws Exception {
+ public void testParseDateWithTimeZoneOffset() {
GregorianCalendar exp = new GregorianCalendar(2015, 2, 28, 12, 16, 12);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis());
@@ -104,7 +98,7 @@ public class DateUtilsTest {
}
@Test
- public void testAsctime() throws Exception {
+ public void testAsctime() {
GregorianCalendar exp = new GregorianCalendar(2011, 4, 25, 12, 33, 0);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis());
@@ -113,7 +107,7 @@ public class DateUtilsTest {
}
@Test
- public void testMultipleConsecutiveSpaces() throws Exception {
+ public void testMultipleConsecutiveSpaces() {
GregorianCalendar exp = new GregorianCalendar(2010, 2, 23, 6, 6, 26);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis());
@@ -121,14 +115,8 @@ public class DateUtilsTest {
assertEquals(expected, actual);
}
- /**
- * Requires Android platform.
- *
- * Reason: Standard JDK cannot parse timezone -08:00 (ISO 8601 format). It only accepts
- * -0800 (RFC 822 format)
- */
@Test
- public void testParseDateWithNoTimezonePadding() throws Exception {
+ public void testParseDateWithNoTimezonePadding() {
GregorianCalendar exp = new GregorianCalendar(2017, 1, 22, 22, 28, 0);
exp.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected = new Date(exp.getTimeInMillis() + 2);
@@ -143,7 +131,7 @@ public class DateUtilsTest {
* @see #testParseDateWithNoTimezonePadding()
*/
@Test
- public void testParseDateWithForCest() throws Exception {
+ public void testParseDateWithForCest() {
GregorianCalendar exp1 = new GregorianCalendar(2017, 0, 28, 22, 0, 0);
exp1.setTimeZone(TimeZone.getTimeZone("UTC"));
Date expected1 = new Date(exp1.getTimeInMillis());
From a52beda1f1b533fb4cd5ee6b1383824ecf1dcda5 Mon Sep 17 00:00:00 2001
From: Herbert Reiter <46045854+damoasda@users.noreply.github.com>
Date: Sat, 2 Jan 2021 16:53:39 +0100
Subject: [PATCH 005/128] Run FeedFilterTest and FeedItemTest without Android
emulator (#4807)
---
.../de/test/antennapod/feed/FeedItemTest.java | 43 ------------------
.../antennapod/core}/feed/FeedFilterTest.java | 18 +++-----
.../antennapod/core/feed/FeedItemTest.java | 45 +++++++++++++++++--
3 files changed, 49 insertions(+), 57 deletions(-)
delete mode 100644 app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java
rename {app/src/androidTest/java/de/test/antennapod => core/src/test/java/de/danoeh/antennapod/core}/feed/FeedFilterTest.java (88%)
diff --git a/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java b/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java
deleted file mode 100644
index 0b9a67d0a..000000000
--- a/app/src/androidTest/java/de/test/antennapod/feed/FeedItemTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package de.test.antennapod.feed;
-
-import androidx.test.filters.SmallTest;
-import de.danoeh.antennapod.core.feed.FeedItem;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-@SmallTest
-public class FeedItemTest {
- private static final String TEXT_LONG = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
- private static final String TEXT_SHORT = "Lorem ipsum";
-
- /**
- * If one of `description` or `content:encoded` is null, use the other one.
- */
- @Test
- public void testShownotesNullValues() throws Exception {
- testShownotes(null, TEXT_LONG);
- testShownotes(TEXT_LONG, null);
- }
-
- /**
- * If `description` is reasonably longer than `content:encoded`, use `description`.
- */
- @Test
- public void testShownotesLength() throws Exception {
- testShownotes(TEXT_SHORT, TEXT_LONG);
- testShownotes(TEXT_LONG, TEXT_SHORT);
- }
-
- /**
- * Checks if the shownotes equal TEXT_LONG, using the given `description` and `content:encoded`
- * @param description Description of the feed item
- * @param contentEncoded `content:encoded` of the feed item
- */
- private void testShownotes(String description, String contentEncoded) throws Exception {
- FeedItem item = new FeedItem();
- item.setDescription(description);
- item.setContentEncoded(contentEncoded);
- assertEquals(TEXT_LONG, item.loadShownotes().call());
- }
-}
diff --git a/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java b/core/src/test/java/de/danoeh/antennapod/core/feed/FeedFilterTest.java
similarity index 88%
rename from app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
rename to core/src/test/java/de/danoeh/antennapod/core/feed/FeedFilterTest.java
index fc2943205..8b4a13473 100644
--- a/app/src/androidTest/java/de/test/antennapod/feed/FeedFilterTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/feed/FeedFilterTest.java
@@ -1,19 +1,15 @@
-package de.test.antennapod.feed;
+package de.danoeh.antennapod.core.feed;
-import androidx.test.filters.SmallTest;
-import de.danoeh.antennapod.core.feed.FeedFilter;
-import de.danoeh.antennapod.core.feed.FeedItem;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-@SmallTest
public class FeedFilterTest {
@Test
- public void testNullFilter() throws Exception {
+ public void testNullFilter() {
FeedFilter filter = new FeedFilter();
FeedItem item = new FeedItem();
item.setTitle("Hello world");
@@ -26,7 +22,7 @@ public class FeedFilterTest {
}
@Test
- public void testBasicIncludeFilter() throws Exception {
+ public void testBasicIncludeFilter() {
String includeFilter = "Hello";
FeedFilter filter = new FeedFilter(includeFilter, "");
FeedItem item = new FeedItem();
@@ -44,7 +40,7 @@ public class FeedFilterTest {
}
@Test
- public void testBasicExcludeFilter() throws Exception {
+ public void testBasicExcludeFilter() {
String excludeFilter = "Hello";
FeedFilter filter = new FeedFilter("", excludeFilter);
FeedItem item = new FeedItem();
@@ -62,7 +58,7 @@ public class FeedFilterTest {
}
@Test
- public void testComplexIncludeFilter() throws Exception {
+ public void testComplexIncludeFilter() {
String includeFilter = "Hello \n\"Two words\"";
FeedFilter filter = new FeedFilter(includeFilter, "");
FeedItem item = new FeedItem();
@@ -84,7 +80,7 @@ public class FeedFilterTest {
}
@Test
- public void testComplexExcludeFilter() throws Exception {
+ public void testComplexExcludeFilter() {
String excludeFilter = "Hello \"Two words\"";
FeedFilter filter = new FeedFilter("", excludeFilter);
FeedItem item = new FeedItem();
@@ -106,7 +102,7 @@ public class FeedFilterTest {
}
@Test
- public void testComboFilter() throws Exception {
+ public void testComboFilter() {
String includeFilter = "Hello world";
String excludeFilter = "dislike";
FeedFilter filter = new FeedFilter(includeFilter, excludeFilter);
diff --git a/core/src/test/java/de/danoeh/antennapod/core/feed/FeedItemTest.java b/core/src/test/java/de/danoeh/antennapod/core/feed/FeedItemTest.java
index 6bd753561..5bcbed97a 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/feed/FeedItemTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/feed/FeedItemTest.java
@@ -2,16 +2,23 @@ package de.danoeh.antennapod.core.feed;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
import java.text.SimpleDateFormat;
import java.util.Date;
+import de.danoeh.antennapod.core.storage.DBReader;
+
import static de.danoeh.antennapod.core.feed.FeedItemMother.anyFeedItemWithImage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class FeedItemTest {
+ private static final String TEXT_LONG = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
+ private static final String TEXT_SHORT = "Lorem ipsum";
+
private FeedItem original;
private FeedItem changedFeedItem;
@@ -22,21 +29,21 @@ public class FeedItemTest {
}
@Test
- public void testUpdateFromOther_feedItemImageDownloadUrlChanged() throws Exception {
+ public void testUpdateFromOther_feedItemImageDownloadUrlChanged() {
setNewFeedItemImageDownloadUrl();
original.updateFromOther(changedFeedItem);
assertFeedItemImageWasUpdated();
}
@Test
- public void testUpdateFromOther_feedItemImageRemoved() throws Exception {
+ public void testUpdateFromOther_feedItemImageRemoved() {
feedItemImageRemoved();
original.updateFromOther(changedFeedItem);
assertFeedItemImageWasNotUpdated();
}
@Test
- public void testUpdateFromOther_feedItemImageAdded() throws Exception {
+ public void testUpdateFromOther_feedItemImageAdded() {
original.setImageUrl(null);
setNewFeedItemImageDownloadUrl();
original.updateFromOther(changedFeedItem);
@@ -102,4 +109,36 @@ public class FeedItemTest {
assertEquals(anyFeedItemWithImage().getImageUrl(), original.getImageUrl());
}
+ /**
+ * If one of `description` or `content:encoded` is null, use the other one.
+ */
+ @Test
+ public void testShownotesNullValues() throws Exception {
+ testShownotes(null, TEXT_LONG);
+ testShownotes(TEXT_LONG, null);
+ }
+
+ /**
+ * If `description` is reasonably longer than `content:encoded`, use `description`.
+ */
+ @Test
+ public void testShownotesLength() throws Exception {
+ testShownotes(TEXT_SHORT, TEXT_LONG);
+ testShownotes(TEXT_LONG, TEXT_SHORT);
+ }
+
+ /**
+ * Checks if the shownotes equal TEXT_LONG, using the given `description` and `content:encoded`.
+ *
+ * @param description Description of the feed item
+ * @param contentEncoded `content:encoded` of the feed item
+ */
+ private void testShownotes(String description, String contentEncoded) throws Exception {
+ try (MockedStatic ignore = Mockito.mockStatic(DBReader.class)) {
+ FeedItem item = new FeedItem();
+ item.setDescription(description);
+ item.setContentEncoded(contentEncoded);
+ assertEquals(TEXT_LONG, item.loadShownotes().call());
+ }
+ }
}
\ No newline at end of file
From 486de46b8ff294a757064f457fc6259820460ecf Mon Sep 17 00:00:00 2001
From: Herbert Reiter <46045854+damoasda@users.noreply.github.com>
Date: Sat, 2 Jan 2021 17:46:10 +0100
Subject: [PATCH 006/128] Run DbWriterTest with Robolectric (#4814)
---
.../antennapod/core/storage/DbWriterTest.java | 284 +++++++++---------
1 file changed, 141 insertions(+), 143 deletions(-)
rename app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java => core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java (73%)
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java
similarity index 73%
rename from app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
rename to core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java
index 652389d00..3efb2705f 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/storage/DbWriterTest.java
@@ -1,38 +1,37 @@
-package de.test.antennapod.storage;
+package de.danoeh.antennapod.core.storage;
+import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
-import androidx.preference.PreferenceManager;
import android.util.Log;
import androidx.core.util.Consumer;
+import androidx.preference.PreferenceManager;
import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
import org.awaitility.Awaitility;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import java.io.File;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
+import de.danoeh.antennapod.core.ApplicationCallbacks;
+import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBWriter;
-import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import static org.junit.Assert.assertEquals;
@@ -41,83 +40,92 @@ import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
/**
- * Test class for DBWriter
+ * Test class for {@link DBWriter}.
*/
-@MediumTest
-public class DBWriterTest {
+@RunWith(RobolectricTestRunner.class)
+public class DbWriterTest {
private static final String TAG = "DBWriterTest";
private static final String TEST_FOLDER = "testDBWriter";
private static final long TIMEOUT = 5L;
-
- @After
- public void tearDown() throws Exception {
- assertTrue(PodDBAdapter.deleteDatabase());
-
- final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
- File testDir = context.getExternalFilesDir(TEST_FOLDER);
- assertNotNull(testDir);
- for (File f : testDir.listFiles()) {
- f.delete();
- }
- }
+
+ private Context context;
@Before
- public void setUp() throws Exception {
+ public void setUp() {
+ context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ UserPreferences.init(context);
+ PlaybackPreferences.init(context);
+
+ Application app = (Application) context;
+ ClientConfig.applicationCallbacks = mock(ApplicationCallbacks.class);
+ when(ClientConfig.applicationCallbacks.getApplicationInstance()).thenReturn(app);
+
// create new database
- PodDBAdapter.init(InstrumentationRegistry.getInstrumentation().getTargetContext());
+ PodDBAdapter.init(context);
PodDBAdapter.deleteDatabase();
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
adapter.close();
- Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
- SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()).edit();
+ SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(
+ context.getApplicationContext()).edit();
prefEdit.putBoolean(UserPreferences.PREF_DELETE_REMOVES_FROM_QUEUE, true).commit();
+ }
- UserPreferences.init(context);
+ @After
+ public void tearDown() {
+ PodDBAdapter.tearDownTests();
+ DBWriter.tearDownTests();
+
+ File testDir = context.getExternalFilesDir(TEST_FOLDER);
+ assertNotNull(testDir);
+ for (File f : testDir.listFiles()) {
+ //noinspection ResultOfMethodCallIgnored
+ f.delete();
+ }
}
@Test
- public void testSetFeedMediaPlaybackInformation()
- throws IOException, ExecutionException, InterruptedException, TimeoutException {
- final int POSITION = 50;
- final long LAST_PLAYED_TIME = 1000;
- final int PLAYED_DURATION = 60;
- final int DURATION = 100;
+ public void testSetFeedMediaPlaybackInformation() throws Exception {
+ final int position = 50;
+ final long lastPlayedTime = 1000;
+ final int playedDuration = 60;
+ final int duration = 100;
Feed feed = new Feed("url", null, "title");
List items = new ArrayList<>();
feed.setItems(items);
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, feed);
items.add(item);
- FeedMedia media = new FeedMedia(0, item, DURATION, 1, 1, "mime_type", "dummy path", "download_url", true, null, 0, 0);
+ FeedMedia media = new FeedMedia(0, item, duration, 1, 1, "mime_type",
+ "dummy path", "download_url", true, null, 0, 0);
item.setMedia(media);
DBWriter.setFeedItem(item).get(TIMEOUT, TimeUnit.SECONDS);
- media.setPosition(POSITION);
- media.setLastPlayedTime(LAST_PLAYED_TIME);
- media.setPlayedDuration(PLAYED_DURATION);
+ media.setPosition(position);
+ media.setLastPlayedTime(lastPlayedTime);
+ media.setPlayedDuration(playedDuration);
DBWriter.setFeedMediaPlaybackInformation(item.getMedia()).get(TIMEOUT, TimeUnit.SECONDS);
FeedItem itemFromDb = DBReader.getFeedItem(item.getId());
FeedMedia mediaFromDb = itemFromDb.getMedia();
- assertEquals(POSITION, mediaFromDb.getPosition());
- assertEquals(LAST_PLAYED_TIME, mediaFromDb.getLastPlayedTime());
- assertEquals(PLAYED_DURATION, mediaFromDb.getPlayedDuration());
- assertEquals(DURATION, mediaFromDb.getDuration());
+ assertEquals(position, mediaFromDb.getPosition());
+ assertEquals(lastPlayedTime, mediaFromDb.getLastPlayedTime());
+ assertEquals(playedDuration, mediaFromDb.getPlayedDuration());
+ assertEquals(duration, mediaFromDb.getDuration());
}
@Test
- public void testDeleteFeedMediaOfItemFileExists()
- throws IOException, ExecutionException, InterruptedException, TimeoutException {
- File dest = new File(InstrumentationRegistry
- .getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
+ public void testDeleteFeedMediaOfItemFileExists() throws Exception {
+ File dest = new File(context.getExternalFilesDir(TEST_FOLDER), "testFile");
assertTrue(dest.createNewFile());
@@ -126,7 +134,8 @@ public class DBWriterTest {
feed.setItems(items);
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, feed);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null, 0, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type",
+ dest.getAbsolutePath(), "download_url", true, null, 0, 0);
item.setMedia(media);
items.add(item);
@@ -138,7 +147,7 @@ public class DBWriterTest {
assertTrue(media.getId() != 0);
assertTrue(item.getId() != 0);
- DBWriter.deleteFeedMediaOfItem(InstrumentationRegistry.getInstrumentation().getTargetContext(), media.getId())
+ DBWriter.deleteFeedMediaOfItem(context, media.getId())
.get(TIMEOUT, TimeUnit.SECONDS);
media = DBReader.getFeedMedia(media.getId());
assertNotNull(media);
@@ -148,25 +157,24 @@ public class DBWriterTest {
}
@Test
- public void testDeleteFeedMediaOfItemRemoveFromQueue()
- throws IOException, ExecutionException, InterruptedException, TimeoutException {
+ public void testDeleteFeedMediaOfItemRemoveFromQueue() throws Exception {
assertTrue(UserPreferences.shouldDeleteRemoveFromQueue());
- File dest = new File(InstrumentationRegistry
- .getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
+ File dest = new File(context.getExternalFilesDir(TEST_FOLDER), "testFile");
assertTrue(dest.createNewFile());
Feed feed = new Feed("url", null, "title");
List items = new ArrayList<>();
- List queue = new ArrayList<>();
feed.setItems(items);
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.UNPLAYED, feed);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null, 0, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type",
+ dest.getAbsolutePath(), "download_url", true, null, 0, 0);
item.setMedia(media);
items.add(item);
+ List queue = new ArrayList<>();
queue.add(item);
PodDBAdapter adapter = PodDBAdapter.getInstance();
@@ -179,7 +187,7 @@ public class DBWriterTest {
queue = DBReader.getQueue();
assertTrue(queue.size() != 0);
- DBWriter.deleteFeedMediaOfItem(InstrumentationRegistry.getInstrumentation().getTargetContext(), media.getId());
+ DBWriter.deleteFeedMediaOfItem(context, media.getId());
Awaitility.await().until(() -> !dest.exists());
media = DBReader.getFeedMedia(media.getId());
assertNotNull(media);
@@ -191,8 +199,8 @@ public class DBWriterTest {
}
@Test
- public void testDeleteFeed() throws ExecutionException, InterruptedException, IOException, TimeoutException {
- File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ public void testDeleteFeed() throws Exception {
+ File destFolder = context.getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -208,7 +216,8 @@ public class DBWriterTest {
assertTrue(enc.createNewFile());
itemFiles.add(enc);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type",
+ enc.getAbsolutePath(), "download_url", true, null, 0, 0);
item.setMedia(media);
}
@@ -223,8 +232,7 @@ public class DBWriterTest {
assertTrue(item.getMedia().getId() != 0);
}
- DBWriter.deleteFeed(InstrumentationRegistry
- .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeed(context, feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
// check if files still exist
for (File f : itemFiles) {
@@ -248,8 +256,8 @@ public class DBWriterTest {
}
@Test
- public void testDeleteFeedNoItems() throws IOException, ExecutionException, InterruptedException, TimeoutException {
- File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ public void testDeleteFeedNoItems() throws Exception {
+ File destFolder = context.getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -263,8 +271,7 @@ public class DBWriterTest {
assertTrue(feed.getId() != 0);
- DBWriter.deleteFeed(InstrumentationRegistry
- .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeed(context, feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -275,8 +282,8 @@ public class DBWriterTest {
}
@Test
- public void testDeleteFeedNoFeedMedia() throws IOException, ExecutionException, InterruptedException, TimeoutException {
- File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ public void testDeleteFeedNoFeedMedia() throws Exception {
+ File destFolder = context.getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -301,9 +308,7 @@ public class DBWriterTest {
assertTrue(item.getId() != 0);
}
- DBWriter.deleteFeed(InstrumentationRegistry
- .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
-
+ DBWriter.deleteFeed(context, feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -319,8 +324,8 @@ public class DBWriterTest {
}
@Test
- public void testDeleteFeedWithQueueItems() throws ExecutionException, InterruptedException, TimeoutException {
- File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ public void testDeleteFeedWithQueueItems() throws Exception {
+ File destFolder = context.getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -333,7 +338,8 @@ public class DBWriterTest {
FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
File enc = new File(destFolder, "file " + i);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type",
+ enc.getAbsolutePath(), "download_url", false, null, 0, 0);
item.setMedia(media);
}
@@ -348,7 +354,6 @@ public class DBWriterTest {
assertTrue(item.getMedia().getId() != 0);
}
-
List queue = new ArrayList<>(feed.getItems());
adapter.open();
adapter.setQueue(queue);
@@ -358,8 +363,7 @@ public class DBWriterTest {
queueCursor.close();
adapter.close();
- DBWriter.deleteFeed(InstrumentationRegistry
- .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeed(context, feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
adapter.open();
Cursor c = adapter.getFeedCursor(feed.getId());
@@ -380,8 +384,8 @@ public class DBWriterTest {
}
@Test
- public void testDeleteFeedNoDownloadedFiles() throws ExecutionException, InterruptedException, TimeoutException {
- File destFolder = InstrumentationRegistry.getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER);
+ public void testDeleteFeedNoDownloadedFiles() throws Exception {
+ File destFolder = context.getExternalFilesDir(TEST_FOLDER);
assertNotNull(destFolder);
Feed feed = new Feed("url", null, "title");
@@ -394,7 +398,8 @@ public class DBWriterTest {
FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
File enc = new File(destFolder, "file " + i);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type",
+ enc.getAbsolutePath(), "download_url", false, null, 0, 0);
item.setMedia(media);
}
@@ -409,8 +414,7 @@ public class DBWriterTest {
assertTrue(item.getMedia().getId() != 0);
}
- DBWriter.deleteFeed(InstrumentationRegistry
- .getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeed(context, feed.getId()).get(TIMEOUT, TimeUnit.SECONDS);
adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -446,8 +450,7 @@ public class DBWriterTest {
adapter.close();
List itemsToDelete = feed.getItems().subList(0, 2);
- DBWriter.deleteFeedItems(InstrumentationRegistry.getInstrumentation()
- .getTargetContext(), itemsToDelete).get(TIMEOUT, TimeUnit.SECONDS);
+ DBWriter.deleteFeedItems(context, itemsToDelete).get(TIMEOUT, TimeUnit.SECONDS);
adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -468,7 +471,8 @@ public class DBWriterTest {
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
- FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null, "url", false, playbackCompletionDate, 0, 0);
+ FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null,
+ "url", false, playbackCompletionDate, 0, 0);
feed.getItems().add(item);
item.setMedia(media);
PodDBAdapter adapter = PodDBAdapter.getInstance();
@@ -480,8 +484,7 @@ public class DBWriterTest {
}
@Test
- public void testAddItemToPlaybackHistoryNotPlayedYet()
- throws ExecutionException, InterruptedException, TimeoutException {
+ public void testAddItemToPlaybackHistoryNotPlayedYet() throws Exception {
FeedMedia media = playbackHistorySetup(null);
DBWriter.addItemToPlaybackHistory(media).get(TIMEOUT, TimeUnit.SECONDS);
PodDBAdapter adapter = PodDBAdapter.getInstance();
@@ -494,11 +497,10 @@ public class DBWriterTest {
}
@Test
- public void testAddItemToPlaybackHistoryAlreadyPlayed()
- throws ExecutionException, InterruptedException, TimeoutException {
- final long OLD_DATE = 0;
+ public void testAddItemToPlaybackHistoryAlreadyPlayed() throws Exception {
+ final long oldDate = 0;
- FeedMedia media = playbackHistorySetup(new Date(OLD_DATE));
+ FeedMedia media = playbackHistorySetup(new Date(oldDate));
DBWriter.addItemToPlaybackHistory(media).get(TIMEOUT, TimeUnit.SECONDS);
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -507,11 +509,11 @@ public class DBWriterTest {
assertNotNull(media);
assertNotNull(media.getPlaybackCompletionDate());
- assertNotEquals(media.getPlaybackCompletionDate().getTime(), OLD_DATE);
+ assertNotEquals(media.getPlaybackCompletionDate().getTime(), oldDate);
}
- private Feed queueTestSetupMultipleItems(final int numItems) throws InterruptedException, ExecutionException, TimeoutException {
- final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ @SuppressWarnings("SameParameterValue")
+ private Feed queueTestSetupMultipleItems(final int numItems) throws Exception {
UserPreferences.setEnqueueLocation(UserPreferences.EnqueueLocation.BACK);
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
@@ -539,8 +541,7 @@ public class DBWriterTest {
}
@Test
- public void testAddQueueItemSingleItem() throws InterruptedException, ExecutionException, TimeoutException {
- final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ public void testAddQueueItemSingleItem() throws Exception {
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
@@ -564,8 +565,7 @@ public class DBWriterTest {
}
@Test
- public void testAddQueueItemSingleItemAlreadyInQueue() throws InterruptedException, ExecutionException, TimeoutException {
- final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ public void testAddQueueItemSingleItemAlreadyInQueue() throws Exception {
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
@@ -599,18 +599,20 @@ public class DBWriterTest {
}
@Test
- public void testAddQueueItemMultipleItems() throws InterruptedException, ExecutionException, TimeoutException {
- final int NUM_ITEMS = 10;
+ public void testAddQueueItemMultipleItems() throws Exception {
+ final int numItems = 10;
- Feed feed = queueTestSetupMultipleItems(NUM_ITEMS);
+ Feed feed;
+ feed = queueTestSetupMultipleItems(numItems);
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor cursor = adapter.getQueueIDCursor();
assertTrue(cursor.moveToFirst());
- assertEquals(NUM_ITEMS, cursor.getCount());
- List expectedIds = FeedItemUtil.getIdList(feed.getItems());
+ assertEquals(numItems, cursor.getCount());
+ List expectedIds;
+ expectedIds = FeedItemUtil.getIdList(feed.getItems());
List actualIds = new ArrayList<>();
- for (int i = 0; i < NUM_ITEMS; i++) {
+ for (int i = 0; i < numItems; i++) {
assertTrue(cursor.moveToPosition(i));
actualIds.add(cursor.getLong(0));
}
@@ -621,10 +623,10 @@ public class DBWriterTest {
}
@Test
- public void testClearQueue() throws InterruptedException, ExecutionException, TimeoutException {
- final int NUM_ITEMS = 10;
+ public void testClearQueue() throws Exception {
+ final int numItems = 10;
- queueTestSetupMultipleItems(NUM_ITEMS);
+ queueTestSetupMultipleItems(numItems);
DBWriter.clearQueue().get(TIMEOUT, TimeUnit.SECONDS);
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -635,12 +637,11 @@ public class DBWriterTest {
}
@Test
- public void testRemoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException {
- final int NUM_ITEMS = 10;
- final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
- Feed feed = createTestFeed(NUM_ITEMS);
+ public void testRemoveQueueItem() throws Exception {
+ final int numItems = 10;
+ Feed feed = createTestFeed(numItems);
- for (int removeIndex = 0; removeIndex < NUM_ITEMS; removeIndex++) {
+ for (int removeIndex = 0; removeIndex < numItems; removeIndex++) {
final FeedItem item = feed.getItems().get(removeIndex);
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -651,7 +652,7 @@ public class DBWriterTest {
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor queue = adapter.getQueueIDCursor();
- assertEquals(NUM_ITEMS - 1, queue.getCount());
+ assertEquals(numItems - 1, queue.getCount());
for (int i = 0; i < queue.getCount(); i++) {
assertTrue(queue.moveToPosition(i));
final long queueID = queue.getLong(0);
@@ -668,16 +669,13 @@ public class DBWriterTest {
}
@Test
- public void testRemoveQueueItemMultipleItems() throws InterruptedException, ExecutionException, TimeoutException {
- // Setup test data
- //
- final int NUM_ITEMS = 5;
- final int NUM_IN_QUEUE = NUM_ITEMS - 1; // the last one not in queue for boundary condition
- final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
- Feed feed = createTestFeed(NUM_ITEMS);
+ public void testRemoveQueueItemMultipleItems() throws Exception {
+ final int numItems = 5;
+ final int numInQueue = numItems - 1; // the last one not in queue for boundary condition
+ Feed feed = createTestFeed(numItems);
- List itemsToAdd = feed.getItems().subList(0, NUM_IN_QUEUE);
- withPodDB(adapter -> adapter.setQueue(itemsToAdd) );
+ List itemsToAdd = feed.getItems().subList(0, numInQueue);
+ withPodDB(adapter -> adapter.setQueue(itemsToAdd));
// Actual tests
//
@@ -706,12 +704,13 @@ public class DBWriterTest {
}
@Test
- public void testMoveQueueItem() throws InterruptedException, ExecutionException, TimeoutException {
- final int NUM_ITEMS = 10;
+ public void testMoveQueueItem() throws Exception {
+ final int numItems = 10;
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
- for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
+ for (int i = 0; i < numItems; i++) {
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i,
+ new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
}
@@ -723,8 +722,8 @@ public class DBWriterTest {
for (FeedItem item : feed.getItems()) {
assertTrue(item.getId() != 0);
}
- for (int from = 0; from < NUM_ITEMS; from++) {
- for (int to = 0; to < NUM_ITEMS; to++) {
+ for (int from = 0; from < numItems; from++) {
+ for (int to = 0; to < numItems; to++) {
if (from == to) {
continue;
}
@@ -740,7 +739,7 @@ public class DBWriterTest {
adapter = PodDBAdapter.getInstance();
adapter.open();
Cursor queue = adapter.getQueueIDCursor();
- assertEquals(NUM_ITEMS, queue.getCount());
+ assertEquals(numItems, queue.getCount());
assertTrue(queue.moveToPosition(from));
assertNotEquals(fromID, queue.getLong(0));
assertTrue(queue.moveToPosition(to));
@@ -753,12 +752,13 @@ public class DBWriterTest {
}
@Test
- public void testMarkFeedRead() throws InterruptedException, ExecutionException, TimeoutException {
- final int NUM_ITEMS = 10;
+ public void testMarkFeedRead() throws Exception {
+ final int numItems = 10;
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
- for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed);
+ for (int i = 0; i < numItems; i++) {
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i,
+ new Date(), FeedItem.UNPLAYED, feed);
feed.getItems().add(item);
}
@@ -780,12 +780,13 @@ public class DBWriterTest {
}
@Test
- public void testMarkAllItemsReadSameFeed() throws InterruptedException, ExecutionException, TimeoutException {
- final int NUM_ITEMS = 10;
+ public void testMarkAllItemsReadSameFeed() throws Exception {
+ final int numItems = 10;
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
- for (int i = 0; i < NUM_ITEMS; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.UNPLAYED, feed);
+ for (int i = 0; i < numItems; i++) {
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i,
+ new Date(), FeedItem.UNPLAYED, feed);
feed.getItems().add(item);
}
@@ -810,7 +811,8 @@ public class DBWriterTest {
Feed feed = new Feed("url", null, "title");
feed.setItems(new ArrayList<>());
for (int i = 0; i < numItems; i++) {
- FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i, new Date(), FeedItem.PLAYED, feed);
+ FeedItem item = new FeedItem(0, "title " + i, "id " + i, "link " + i,
+ new Date(), FeedItem.PLAYED, feed);
feed.getItems().add(item);
}
@@ -832,10 +834,7 @@ public class DBWriterTest {
}
}
- private static void assertQueueByItemIds(
- String message,
- long... itemIdsExpected
- ) {
+ private static void assertQueueByItemIds(String message, long... itemIdsExpected) {
List queue = DBReader.getQueue();
List itemIdsActualList = toItemIds(queue);
List itemIdsExpectedList = new ArrayList<>(itemIdsExpected.length);
@@ -848,10 +847,9 @@ public class DBWriterTest {
private static List toItemIds(List items) {
List itemIds = new ArrayList<>(items.size());
- for(FeedItem item : items) {
+ for (FeedItem item : items) {
itemIds.add(item.getId());
}
return itemIds;
}
-
}
From 542dbd190c6aa4b01c1b644e5c107333817442cd Mon Sep 17 00:00:00 2001
From: Herbert Reiter <46045854+damoasda@users.noreply.github.com>
Date: Sat, 2 Jan 2021 17:49:30 +0100
Subject: [PATCH 007/128] Run more util tests with Robolectric (#4815)
---
.../antennapod/adapter/NavListAdapter.java | 2 +-
.../core/preferences/PlaybackPreferences.java | 2 +-
.../core/util/FileNameGenerator.java | 2 +-
.../core/util/playback/AudioPlayer.java | 2 +-
.../core}/util/FilenameGeneratorTest.java | 26 +++++------
.../antennapod/core}/util/URLCheckerTest.java | 22 +++++-----
.../core}/util/playback/TimelineTest.java | 44 ++++++++++++-------
.../util/syndication/FeedDiscovererTest.java | 26 ++++++-----
8 files changed, 70 insertions(+), 56 deletions(-)
rename {app/src/androidTest/java/de/test/antennapod => core/src/test/java/de/danoeh/antennapod/core}/util/FilenameGeneratorTest.java (82%)
rename {app/src/androidTest/java/de/test/antennapod => core/src/test/java/de/danoeh/antennapod/core}/util/URLCheckerTest.java (89%)
rename {app/src/androidTest/java/de/test/antennapod => core/src/test/java/de/danoeh/antennapod/core}/util/playback/TimelineTest.java (86%)
rename {app/src/androidTest/java/de/test/antennapod => core/src/test/java/de/danoeh/antennapod/core}/util/syndication/FeedDiscovererTest.java (89%)
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
index 92ed7b052..f8507ba74 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java
@@ -75,7 +75,7 @@ public class NavListAdapter extends BaseAdapter
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (key.equals(UserPreferences.PREF_HIDDEN_DRAWER_ITEMS)) {
+ if (UserPreferences.PREF_HIDDEN_DRAWER_ITEMS.equals(key)) {
loadItems();
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
index 08ea27434..95b828e28 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
@@ -100,7 +100,7 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
- if (key.equals(PREF_CURRENT_PLAYER_STATUS)) {
+ if (PREF_CURRENT_PLAYER_STATUS.equals(key)) {
EventBus.getDefault().post(new PlayerStatusEvent());
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java b/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java
index 2a387b7b0..69c23efc2 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java
@@ -13,7 +13,7 @@ import java.security.NoSuchAlgorithmException;
/** Generates valid filenames for a given string. */
public class FileNameGenerator {
@VisibleForTesting
- public static final int MAX_FILENAME_LENGTH = 255; // Limited by ext4
+ public static final int MAX_FILENAME_LENGTH = 242; // limited by CircleCI
private static final int MD5_HEX_LENGTH = 32;
private static final char[] validChars =
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
index 0467c0a78..031bf9a24 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java
@@ -20,7 +20,7 @@ public class AudioPlayer extends MediaPlayer implements IPlayer {
super(context, true, ClientConfig.USER_AGENT);
PreferenceManager.getDefaultSharedPreferences(context)
.registerOnSharedPreferenceChangeListener((sharedPreferences, key) -> {
- if (key.equals(UserPreferences.PREF_MEDIA_PLAYER)) {
+ if (UserPreferences.PREF_MEDIA_PLAYER.equals(key)) {
checkMpi();
}
});
diff --git a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java b/core/src/test/java/de/danoeh/antennapod/core/util/FilenameGeneratorTest.java
similarity index 82%
rename from app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
rename to core/src/test/java/de/danoeh/antennapod/core/util/FilenameGeneratorTest.java
index f376c75a5..af22a4b9d 100644
--- a/app/src/androidTest/java/de/test/antennapod/util/FilenameGeneratorTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/util/FilenameGeneratorTest.java
@@ -1,22 +1,21 @@
-package de.test.antennapod.util;
+package de.danoeh.antennapod.core.util;
import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
import android.text.TextUtils;
import java.io.File;
-import java.io.IOException;
-import de.danoeh.antennapod.core.util.FileNameGenerator;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-@SmallTest
+@RunWith(RobolectricTestRunner.class)
public class FilenameGeneratorTest {
public FilenameGeneratorTest() {
@@ -24,21 +23,21 @@ public class FilenameGeneratorTest {
}
@Test
- public void testGenerateFileName() throws IOException {
+ public void testGenerateFileName() throws Exception {
String result = FileNameGenerator.generateFileName("abc abc");
assertEquals(result, "abc abc");
createFiles(result);
}
@Test
- public void testGenerateFileName1() throws IOException {
+ public void testGenerateFileName1() throws Exception {
String result = FileNameGenerator.generateFileName("ab/c: dbReaderMock;
@Before
public void setUp() {
context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ // mock DBReader, because Timeline.processShownotes() calls FeedItem.loadShownotes()
+ // which calls DBReader.loadDescriptionOfFeedItem(), but we don't need the database here
+ dbReaderMock = Mockito.mockStatic(DBReader.class);
}
+ @After
+ public void tearDown() {
+ dbReaderMock.close();
+ }
+
+ @SuppressWarnings("SameParameterValue")
private Playable newTestPlayable(List chapters, String shownotes, int duration) {
FeedItem item = new FeedItem(0, "Item", "item-id", "http://example.com/item", new Date(), FeedItem.PLAYED, null);
item.setChapters(chapters);
@@ -49,7 +63,7 @@ public class TimelineTest {
}
@Test
- public void testProcessShownotesAddTimecodeHHMMSSNoChapters() {
+ public void testProcessShownotesAddTimecodeHhmmssNoChapters() {
final String timeStr = "10:11:12";
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11 + 12 * 1000;
@@ -61,7 +75,7 @@ public class TimelineTest {
}
@Test
- public void testProcessShownotesAddTimecodeHHMMSSMoreThen24HoursNoChapters() {
+ public void testProcessShownotesAddTimecodeHhmmssMoreThen24HoursNoChapters() {
final String timeStr = "25:00:00";
final long time = 25 * 60 * 60 * 1000;
@@ -73,7 +87,7 @@ public class TimelineTest {
}
@Test
- public void testProcessShownotesAddTimecodeHHMMNoChapters() {
+ public void testProcessShownotesAddTimecodeHhmmNoChapters() {
final String timeStr = "10:11";
final long time = 3600 * 1000 * 10 + 60 * 1000 * 11;
@@ -85,7 +99,7 @@ public class TimelineTest {
}
@Test
- public void testProcessShownotesAddTimecodeMMSSNoChapters() {
+ public void testProcessShownotesAddTimecodeMmssNoChapters() {
final String timeStr = "10:11";
final long time = 10 * 60 * 1000 + 11 * 1000;
@@ -97,7 +111,7 @@ public class TimelineTest {
}
@Test
- public void testProcessShownotesAddTimecodeHMMSSNoChapters() {
+ public void testProcessShownotesAddTimecodeHmmssNoChapters() {
final String timeStr = "2:11:12";
final long time = 2 * 60 * 60 * 1000 + 11 * 60 * 1000 + 12 * 1000;
Playable p = newTestPlayable(null, "
Some test text with a timecode "
@@ -108,7 +122,7 @@ public class TimelineTest {
}
@Test
- public void testProcessShownotesAddTimecodeMSSNoChapters() {
+ public void testProcessShownotesAddTimecodeMssNoChapters() {
final String timeStr = "1:12";
final long time = 60 * 1000 + 12 * 1000;
@@ -139,8 +153,8 @@ public class TimelineTest {
+ timeStrings[0] + " here. Hey look another one " + timeStrings[1] + " here!