, Parcelable {
setRequestedPermissions(permissions, 23);
}
+ /**
+ * Generate the set of requested permissions for the current Android version.
+ *
+ * There are also a bunch of crazy rules where having one permission will imply
+ * another permission, for example, {@link Manifest.permission#WRITE_EXTERNAL_STORAGE}
+ * implies {@code Manifest.permission#READ_EXTERNAL_STORAGE}. Many of these rules
+ * are for quite old Android versions, so they are not included here.
+ *
+ * @see Manifest.permission#READ_EXTERNAL_STORAGE
+ */
private void setRequestedPermissions(Object[][] permissions, int minSdk) {
HashSet set = new HashSet<>();
if (requestedPermissions != null) {
@@ -500,6 +511,9 @@ public class Apk extends ValueObject implements Comparable, Parcelable {
set.add((String) versions[0]);
}
}
+ if (Build.VERSION.SDK_INT >= 16 && set.contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ set.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+ }
requestedPermissions = set.toArray(new String[set.size()]);
}
diff --git a/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java b/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java
index 1da274f63..58287bdda 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java
@@ -19,6 +19,7 @@
package org.fdroid.fdroid.data;
+import android.Manifest;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -98,6 +99,10 @@ public class RepoXMLHandler extends DefaultHandler {
if ("application".equals(localName) && curapp != null) {
onApplicationParsed();
} else if ("package".equals(localName) && curapk != null && curapp != null) {
+ if (Build.VERSION.SDK_INT >= 16 &&
+ requestedPermissionsSet.contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ requestedPermissionsSet.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+ }
int size = requestedPermissionsSet.size();
curapk.requestedPermissions = requestedPermissionsSet.toArray(new String[size]);
requestedPermissionsSet.clear();
diff --git a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java
index cc9d6394d..3a8d231ef 100644
--- a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java
+++ b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java
@@ -38,6 +38,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -53,6 +55,7 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -132,6 +135,14 @@ public class IndexV1UpdaterTest extends FDroidProviderTest {
InstalledAppTestUtils.install(context, "com.waze", 1019841, "v3.9.5.4", "362488e7be5ea0689b4e97d989ae1404",
"cbbdb8c5dafeccd7dd7b642dde0477d3489e18ac366e3c8473d5c07e5f735a95");
assertEquals(1, AppProvider.Helper.findInstalledAppsWithKnownVulns(context).size());
+
+ Apk apk = ApkProvider.Helper.findApkFromAnyRepo(context, "io.proto.player", 1110);
+ assertNotNull("We should find this APK", apk);
+ assertEquals("io.proto.player-1.apk", apk.apkName);
+ HashSet requestedPermissions = new HashSet<>(Arrays.asList(apk.requestedPermissions));
+ assertTrue(requestedPermissions.contains(android.Manifest.permission.READ_EXTERNAL_STORAGE));
+ assertTrue(requestedPermissions.contains(android.Manifest.permission.WRITE_EXTERNAL_STORAGE));
+ assertFalse(requestedPermissions.contains(android.Manifest.permission.READ_CALENDAR));
}
@Test(expected = IndexUpdater.SigningException.class)