From 7bc5ca74f1cc4a2a7b199a6bbbaaac12663391c6 Mon Sep 17 00:00:00 2001 From: orionlee Date: Sat, 26 Oct 2019 16:38:34 -0700 Subject: [PATCH] make DownloadRequest ArrayList parcelable (support a batch of them) --- .../service/download/DownloadRequestTest.java | 122 ++++++++++++++++++ .../service/download/DownloadRequest.java | 35 ++--- 2 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 core/src/androidTest/java/de/danoeh/antennapod/core/service/download/DownloadRequestTest.java diff --git a/core/src/androidTest/java/de/danoeh/antennapod/core/service/download/DownloadRequestTest.java b/core/src/androidTest/java/de/danoeh/antennapod/core/service/download/DownloadRequestTest.java new file mode 100644 index 000000000..71212e6ec --- /dev/null +++ b/core/src/androidTest/java/de/danoeh/antennapod/core/service/download/DownloadRequestTest.java @@ -0,0 +1,122 @@ +package de.danoeh.antennapod.core.service.download; + +import android.os.Bundle; +import android.os.Parcel; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +import java.util.ArrayList; + +import de.danoeh.antennapod.core.feed.FeedFile; + +import static org.junit.Assert.assertEquals; + +@SmallTest +public class DownloadRequestTest { + + @Test + public void parcelInArrayListTest_WithAuth() { + doTestParcelInArrayList("case has authentication", + "usr1", "pass1", "usr2", "pass2"); + } + + @Test + public void parcelInArrayListTest_NoAuth() { + doTestParcelInArrayList("case no authentication", + null, null, null, null); + } + + @Test + public void parcelInArrayListTest_MixAuth() { + doTestParcelInArrayList("case mixed authentication", + null, null, "usr2", "pass2"); + } + + // Test to ensure parcel using put/getParcelableArrayList() API work + // based on: https://stackoverflow.com/a/13507191 + private void doTestParcelInArrayList(String message, + String username1, String password1, + String username2, String password2) { + ArrayList toParcel; + { // test DownloadRequests to parcel + String destStr = "file://location/media.mp3"; + FeedFile item1 = createFeedItem(1); + Bundle arg1 = new Bundle(); + arg1.putString("arg1", "value1"); + DownloadRequest request1 = new DownloadRequest.Builder(destStr, item1) + .withAuthentication(username1, password1) + .withArguments(arg1) + .build(); + + FeedFile item2 = createFeedItem(2); + DownloadRequest request2 = new DownloadRequest.Builder(destStr, item2) + .withAuthentication(username2, password2) + .build(); + + toParcel = new ArrayList<>(); + toParcel.add(request1); + toParcel.add(request2); + } + + // parcel the download requests + Bundle bundleIn = new Bundle(); + bundleIn.putParcelableArrayList("r", toParcel); + + Parcel parcel = Parcel.obtain(); + bundleIn.writeToParcel(parcel, 0); + + Bundle bundleOut = new Bundle(); + bundleOut.setClassLoader(DownloadRequest.class.getClassLoader()); + parcel.setDataPosition(0); // to read the parcel from the beginning. + bundleOut.readFromParcel(parcel); + + ArrayList fromParcel = bundleOut.getParcelableArrayList("r"); + + // spot-check contents to ensure they are the same + // DownloadRequest.equals() implementation doesn't quite work + // for DownloadRequest.argument (a Bundle) + assertEquals(message + " - size", toParcel.size(), fromParcel.size()); + assertEquals(message + " - source", toParcel.get(1).getSource(), fromParcel.get(1).getSource()); + assertEquals(message + " - password", toParcel.get(0).getPassword(), fromParcel.get(0).getPassword()); + assertEquals(message + " - argument", toString(toParcel.get(0).getArguments()), + toString(fromParcel.get(0).getArguments())); + } + + private static String toString(Bundle b) { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + for (String key: b.keySet()) { + Object val = b.get(key); + sb.append("(").append(key).append(":").append(val).append(") "); + } + sb.append("}"); + return sb.toString(); + } + + private FeedFile createFeedItem(final int id) { + // Use mockito would be less verbose, but it'll take extra 1 second for this tiny test + return new FeedFile() { + @Override + public long getId() { + return id; + } + + @Override + public String getDownload_url() { + return "http://example.com/episode" + id; + } + + @Override + public int getTypeAsInt() { + return 0; + } + + @Override + public String getHumanReadableIdentifier() { + return "human-id-" + id; + } + }; + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java index 60591899d..aa77c85b6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java @@ -3,6 +3,8 @@ package de.danoeh.antennapod.core.service.download; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -74,17 +76,9 @@ public class DownloadRequest implements Parcelable { feedfileType = in.readInt(); lastModified = in.readString(); deleteOnFailure = (in.readByte() > 0); + username = nullIfEmpty(in.readString()); + password = nullIfEmpty(in.readString()); arguments = in.readBundle(); - if (in.dataAvail() > 0) { - username = in.readString(); - } else { - username = null; - } - if (in.dataAvail() > 0) { - password = in.readString(); - } else { - password = null; - } } @Override @@ -101,13 +95,22 @@ public class DownloadRequest implements Parcelable { dest.writeInt(feedfileType); dest.writeString(lastModified); dest.writeByte((deleteOnFailure) ? (byte) 1 : 0); + // in case of null username/password, still write an empty string + // (rather than skipping it). Otherwise, unmarshalling a collection + // of them from a Parcel (from an Intent extra to submit a request to DownloadService) will fail. + // + // see: https://stackoverflow.com/a/22926342 + dest.writeString(nonNullString(username)); + dest.writeString(nonNullString(password)); dest.writeBundle(arguments); - if (username != null) { - dest.writeString(username); - } - if (password != null) { - dest.writeString(password); - } + } + + private static String nonNullString(String str) { + return str != null ? str : ""; + } + + private static String nullIfEmpty(String str) { + return TextUtils.isEmpty(str) ? null : str; } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {