Merge branch 'issue-564--filter-anti-features--refactor-and-test-in-prep' into 'master'
Tests + Refactorings in preperation for #564 (Filter anti features) As described in #564, there is a small amount of ground work to be done in order to support a UI for filtering anti features. This is the first stage of that. A subsequent MR will add a database migration to put anti features in their own table, and have a join table between apps and anti features. See commit messages for more detailed descriptions. See merge request !339
This commit is contained in:
commit
ef403928cf
@ -266,7 +266,7 @@ public class AppDetails extends AppCompatActivity {
|
||||
}
|
||||
|
||||
if (Preferences.get().expertMode() && apk.nativecode != null) {
|
||||
holder.nativecode.setText(apk.nativecode.toString().replaceAll(",", " "));
|
||||
holder.nativecode.setText(TextUtils.join(" ", apk.nativecode));
|
||||
holder.nativecode.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.nativecode.setVisibility(View.GONE);
|
||||
@ -276,7 +276,7 @@ public class AppDetails extends AppCompatActivity {
|
||||
holder.incompatibleReasons.setText(
|
||||
getResources().getString(
|
||||
R.string.requires_features,
|
||||
apk.incompatibleReasons.toPrettyString()));
|
||||
TextUtils.join(", ", apk.incompatibleReasons)));
|
||||
holder.incompatibleReasons.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.incompatibleReasons.setVisibility(View.GONE);
|
||||
@ -1323,7 +1323,7 @@ public class AppDetails extends AppCompatActivity {
|
||||
// Categories TextView
|
||||
final TextView categories = (TextView) view.findViewById(R.id.categories);
|
||||
if (prefs.expertMode() && app.categories != null) {
|
||||
categories.setText(app.categories.toString().replaceAll(",", ", "));
|
||||
categories.setText(TextUtils.join(", ", app.categories));
|
||||
} else {
|
||||
categories.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -25,12 +25,15 @@ public class AppFilter {
|
||||
// Return true if the given app should be filtered out based on user
|
||||
// preferences, and false otherwise.
|
||||
public boolean filter(App app) {
|
||||
if (app.requirements == null) {
|
||||
if (app.requirements != null && !Preferences.get().filterAppsRequiringRoot()) {
|
||||
for (String requirement : app.requirements) {
|
||||
if ("root".equals(requirement)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return !Preferences.get().filterAppsRequiringRoot()
|
||||
&& app.requirements.contains("root");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import android.content.pm.FeatureInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.fdroid.fdroid.compat.SupportedArchitectures;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
@ -69,15 +71,18 @@ public class CompatibilityChecker {
|
||||
cpuAbisDesc = builder.toString();
|
||||
}
|
||||
|
||||
private boolean compatibleApi(Utils.CommaSeparatedList nativecode) {
|
||||
private boolean compatibleApi(@Nullable String[] nativecode) {
|
||||
if (nativecode == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (final String cpuAbi : cpuAbis) {
|
||||
if (nativecode.contains(cpuAbi)) {
|
||||
for (String code : nativecode) {
|
||||
if (code.equals(cpuAbi)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -108,11 +113,9 @@ public class CompatibilityChecker {
|
||||
}
|
||||
}
|
||||
if (!compatibleApi(apk.nativecode)) {
|
||||
for (final String code : apk.nativecode) {
|
||||
incompatibleReasons.add(code);
|
||||
}
|
||||
Collections.addAll(incompatibleReasons, apk.nativecode);
|
||||
Utils.debugLog(TAG, apk.packageName + " vercode " + apk.versionCode
|
||||
+ " only supports " + Utils.CommaSeparatedList.str(apk.nativecode)
|
||||
+ " only supports " + TextUtils.join(", ", apk.nativecode)
|
||||
+ " while your architectures are " + cpuAbisDesc);
|
||||
}
|
||||
|
||||
|
@ -142,13 +142,13 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
curapk.added = Utils.parseDate(str, null);
|
||||
break;
|
||||
case "permissions":
|
||||
curapk.permissions = Utils.CommaSeparatedList.make(str);
|
||||
curapk.permissions = Utils.parseCommaSeparatedString(str);
|
||||
break;
|
||||
case "features":
|
||||
curapk.features = Utils.CommaSeparatedList.make(str);
|
||||
curapk.features = Utils.parseCommaSeparatedString(str);
|
||||
break;
|
||||
case "nativecode":
|
||||
curapk.nativecode = Utils.CommaSeparatedList.make(str);
|
||||
curapk.nativecode = Utils.parseCommaSeparatedString(str);
|
||||
break;
|
||||
}
|
||||
} else if (curapp != null) {
|
||||
@ -218,13 +218,13 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
curapp.upstreamVersionCode = Utils.parseInt(str, -1);
|
||||
break;
|
||||
case "categories":
|
||||
curapp.categories = Utils.CommaSeparatedList.make(str);
|
||||
curapp.categories = Utils.parseCommaSeparatedString(str);
|
||||
break;
|
||||
case "antifeatures":
|
||||
curapp.antiFeatures = Utils.CommaSeparatedList.make(str);
|
||||
curapp.antiFeatures = Utils.parseCommaSeparatedString(str);
|
||||
break;
|
||||
case "requirements":
|
||||
curapp.requirements = Utils.CommaSeparatedList.make(str);
|
||||
curapp.requirements = Utils.parseCommaSeparatedString(str);
|
||||
break;
|
||||
}
|
||||
} else if ("description".equals(localName)) {
|
||||
|
@ -57,11 +57,8 @@ import java.security.cert.CertificateEncodingException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Formatter;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public final class Utils {
|
||||
@ -402,87 +399,6 @@ public final class Utils {
|
||||
return new Locale(languageTag);
|
||||
}
|
||||
|
||||
public static final class CommaSeparatedList implements Iterable<String> {
|
||||
private final String value;
|
||||
|
||||
private CommaSeparatedList(String list) {
|
||||
value = list;
|
||||
}
|
||||
|
||||
public static CommaSeparatedList make(List<String> list) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(list.get(i));
|
||||
}
|
||||
return new CommaSeparatedList(sb.toString());
|
||||
}
|
||||
|
||||
public static CommaSeparatedList make(String[] list) {
|
||||
if (list == null || list.length == 0) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
sb.append(list[i]);
|
||||
}
|
||||
return new CommaSeparatedList(sb.toString());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static CommaSeparatedList make(@Nullable String list) {
|
||||
if (TextUtils.isEmpty(list)) {
|
||||
return null;
|
||||
}
|
||||
return new CommaSeparatedList(list);
|
||||
}
|
||||
|
||||
public static String str(CommaSeparatedList instance) {
|
||||
return instance == null ? null : instance.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String toPrettyString() {
|
||||
return value.replaceAll(",", ", ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
|
||||
splitter.setString(value);
|
||||
return splitter.iterator();
|
||||
}
|
||||
|
||||
public ArrayList<String> toArrayList() {
|
||||
ArrayList<String> out = new ArrayList<>();
|
||||
for (String element : this) {
|
||||
out.add(element);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public boolean contains(String v) {
|
||||
for (final String s : this) {
|
||||
if (s.equals(v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static DisplayImageOptions.Builder getImageLoadingOptions() {
|
||||
return new DisplayImageOptions.Builder()
|
||||
.cacheInMemory(true)
|
||||
@ -560,6 +476,16 @@ public final class Utils {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String[] parseCommaSeparatedString(String values) {
|
||||
return values == null || values.length() == 0 ? null : values.split(",");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String serializeCommaSeparatedString(@Nullable String[] values) {
|
||||
return values == null || values.length == 0 ? null : TextUtils.join(",", values);
|
||||
}
|
||||
|
||||
private static Date parseDateFormat(DateFormat format, String str, Date fallback) {
|
||||
if (str == null || str.length() == 0) {
|
||||
return fallback;
|
||||
|
@ -29,11 +29,11 @@ public class Apk extends ValueObject implements Comparable<Apk> {
|
||||
public int targetSdkVersion = SDK_VERSION_MIN_VALUE; // 0 if unknown
|
||||
public int maxSdkVersion = SDK_VERSION_MAX_VALUE; // "infinity" if not set
|
||||
public Date added;
|
||||
public Utils.CommaSeparatedList permissions; // null if empty or
|
||||
public String[] permissions; // null if empty or
|
||||
// unknown
|
||||
public Utils.CommaSeparatedList features; // null if empty or unknown
|
||||
public String[] features; // null if empty or unknown
|
||||
|
||||
public Utils.CommaSeparatedList nativecode; // null if empty or unknown
|
||||
public String[] nativecode; // null if empty or unknown
|
||||
|
||||
/**
|
||||
* ID (md5 sum of public key) of signature. Might be null, in the
|
||||
@ -58,7 +58,7 @@ public class Apk extends ValueObject implements Comparable<Apk> {
|
||||
|
||||
public int repoVersion;
|
||||
public String repoAddress;
|
||||
public Utils.CommaSeparatedList incompatibleReasons;
|
||||
public String[] incompatibleReasons;
|
||||
|
||||
public Apk() {
|
||||
}
|
||||
@ -83,7 +83,7 @@ public class Apk extends ValueObject implements Comparable<Apk> {
|
||||
added = Utils.parseDate(cursor.getString(i), null);
|
||||
break;
|
||||
case ApkProvider.DataColumns.FEATURES:
|
||||
features = Utils.CommaSeparatedList.make(cursor.getString(i));
|
||||
features = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||
break;
|
||||
case ApkProvider.DataColumns.PACKAGE_NAME:
|
||||
packageName = cursor.getString(i);
|
||||
@ -104,13 +104,13 @@ public class Apk extends ValueObject implements Comparable<Apk> {
|
||||
apkName = cursor.getString(i);
|
||||
break;
|
||||
case ApkProvider.DataColumns.PERMISSIONS:
|
||||
permissions = Utils.CommaSeparatedList.make(cursor.getString(i));
|
||||
permissions = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||
break;
|
||||
case ApkProvider.DataColumns.NATIVE_CODE:
|
||||
nativecode = Utils.CommaSeparatedList.make(cursor.getString(i));
|
||||
nativecode = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||
break;
|
||||
case ApkProvider.DataColumns.INCOMPATIBLE_REASONS:
|
||||
incompatibleReasons = Utils.CommaSeparatedList.make(cursor.getString(i));
|
||||
incompatibleReasons = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||
break;
|
||||
case ApkProvider.DataColumns.REPO_ID:
|
||||
repo = cursor.getInt(i);
|
||||
@ -205,10 +205,10 @@ public class Apk extends ValueObject implements Comparable<Apk> {
|
||||
values.put(ApkProvider.DataColumns.TARGET_SDK_VERSION, targetSdkVersion);
|
||||
values.put(ApkProvider.DataColumns.MAX_SDK_VERSION, maxSdkVersion);
|
||||
values.put(ApkProvider.DataColumns.ADDED_DATE, Utils.formatDate(added, ""));
|
||||
values.put(ApkProvider.DataColumns.PERMISSIONS, Utils.CommaSeparatedList.str(permissions));
|
||||
values.put(ApkProvider.DataColumns.FEATURES, Utils.CommaSeparatedList.str(features));
|
||||
values.put(ApkProvider.DataColumns.NATIVE_CODE, Utils.CommaSeparatedList.str(nativecode));
|
||||
values.put(ApkProvider.DataColumns.INCOMPATIBLE_REASONS, Utils.CommaSeparatedList.str(incompatibleReasons));
|
||||
values.put(ApkProvider.DataColumns.PERMISSIONS, Utils.serializeCommaSeparatedString(permissions));
|
||||
values.put(ApkProvider.DataColumns.FEATURES, Utils.serializeCommaSeparatedString(features));
|
||||
values.put(ApkProvider.DataColumns.NATIVE_CODE, Utils.serializeCommaSeparatedString(nativecode));
|
||||
values.put(ApkProvider.DataColumns.INCOMPATIBLE_REASONS, Utils.serializeCommaSeparatedString(incompatibleReasons));
|
||||
values.put(ApkProvider.DataColumns.IS_COMPATIBLE, compatible ? 1 : 0);
|
||||
return values;
|
||||
}
|
||||
|
@ -88,17 +88,17 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
/**
|
||||
* List of categories (as defined in the metadata documentation) or null if there aren't any.
|
||||
*/
|
||||
public Utils.CommaSeparatedList categories;
|
||||
public String[] categories;
|
||||
|
||||
/**
|
||||
* List of anti-features (as defined in the metadata documentation) or null if there aren't any.
|
||||
*/
|
||||
public Utils.CommaSeparatedList antiFeatures;
|
||||
public String[] antiFeatures;
|
||||
|
||||
/**
|
||||
* List of special requirements (such as root privileges) or null if there aren't any.
|
||||
*/
|
||||
public Utils.CommaSeparatedList requirements;
|
||||
public String[] requirements;
|
||||
|
||||
/**
|
||||
* True if all updates for this app are to be ignored
|
||||
@ -221,13 +221,13 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
lastUpdated = Utils.parseDate(cursor.getString(i), null);
|
||||
break;
|
||||
case AppProvider.DataColumns.CATEGORIES:
|
||||
categories = Utils.CommaSeparatedList.make(cursor.getString(i));
|
||||
categories = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||
break;
|
||||
case AppProvider.DataColumns.ANTI_FEATURES:
|
||||
antiFeatures = Utils.CommaSeparatedList.make(cursor.getString(i));
|
||||
antiFeatures = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||
break;
|
||||
case AppProvider.DataColumns.REQUIREMENTS:
|
||||
requirements = Utils.CommaSeparatedList.make(cursor.getString(i));
|
||||
requirements = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||
break;
|
||||
case AppProvider.DataColumns.IGNORE_ALLUPDATES:
|
||||
ignoreAllUpdates = cursor.getInt(i) == 1;
|
||||
@ -334,7 +334,7 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
apk.targetSdkVersion = minTargetMax[1];
|
||||
apk.maxSdkVersion = minTargetMax[2];
|
||||
apk.packageName = this.packageName;
|
||||
apk.permissions = Utils.CommaSeparatedList.make(packageInfo.requestedPermissions);
|
||||
apk.permissions = packageInfo.requestedPermissions;
|
||||
apk.apkName = apk.packageName + "_" + apk.versionCode + ".apk";
|
||||
apk.installedFile = apkFile;
|
||||
|
||||
@ -348,15 +348,14 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
abis.add(matcher.group(1));
|
||||
}
|
||||
}
|
||||
apk.nativecode = Utils.CommaSeparatedList.make(abis.toArray(new String[abis.size()]));
|
||||
apk.nativecode = abis.toArray(new String[abis.size()]);
|
||||
|
||||
final FeatureInfo[] features = packageInfo.reqFeatures;
|
||||
if (features != null && features.length > 0) {
|
||||
final String[] featureNames = new String[features.length];
|
||||
apk.features = new String[features.length];
|
||||
for (int i = 0; i < features.length; i++) {
|
||||
featureNames[i] = features[i].name;
|
||||
apk.features[i] = features[i].name;
|
||||
}
|
||||
apk.features = Utils.CommaSeparatedList.make(featureNames);
|
||||
}
|
||||
|
||||
final JarEntry aSignedEntry = (JarEntry) apkJar.getEntry("AndroidManifest.xml");
|
||||
@ -462,9 +461,9 @@ public class App extends ValueObject implements Comparable<App> {
|
||||
values.put(AppProvider.DataColumns.SUGGESTED_VERSION_CODE, suggestedVersionCode);
|
||||
values.put(AppProvider.DataColumns.UPSTREAM_VERSION_NAME, upstreamVersionName);
|
||||
values.put(AppProvider.DataColumns.UPSTREAM_VERSION_CODE, upstreamVersionCode);
|
||||
values.put(AppProvider.DataColumns.CATEGORIES, Utils.CommaSeparatedList.str(categories));
|
||||
values.put(AppProvider.DataColumns.ANTI_FEATURES, Utils.CommaSeparatedList.str(antiFeatures));
|
||||
values.put(AppProvider.DataColumns.REQUIREMENTS, Utils.CommaSeparatedList.str(requirements));
|
||||
values.put(AppProvider.DataColumns.CATEGORIES, Utils.serializeCommaSeparatedString(categories));
|
||||
values.put(AppProvider.DataColumns.ANTI_FEATURES, Utils.serializeCommaSeparatedString(antiFeatures));
|
||||
values.put(AppProvider.DataColumns.REQUIREMENTS, Utils.serializeCommaSeparatedString(requirements));
|
||||
values.put(AppProvider.DataColumns.IS_COMPATIBLE, compatible ? 1 : 0);
|
||||
values.put(AppProvider.DataColumns.IGNORE_ALLUPDATES, ignoreAllUpdates ? 1 : 0);
|
||||
values.put(AppProvider.DataColumns.IGNORE_THISUPDATE, ignoreThisUpdate);
|
||||
|
@ -98,11 +98,9 @@ public class AppProvider extends FDroidProvider {
|
||||
cursor.moveToFirst();
|
||||
while (!cursor.isAfterLast()) {
|
||||
final String categoriesString = cursor.getString(0);
|
||||
Utils.CommaSeparatedList categoriesList = Utils.CommaSeparatedList.make(categoriesString);
|
||||
String[] categoriesList = Utils.parseCommaSeparatedString(categoriesString);
|
||||
if (categoriesList != null) {
|
||||
for (final String s : categoriesList) {
|
||||
categorySet.add(s);
|
||||
}
|
||||
Collections.addAll(categorySet, categoriesList);
|
||||
}
|
||||
cursor.moveToNext();
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ public class RepoPersister {
|
||||
final List<String> reasons = checker.getIncompatibleReasons(apk);
|
||||
if (reasons.size() > 0) {
|
||||
apk.compatible = false;
|
||||
apk.incompatibleReasons = Utils.CommaSeparatedList.make(reasons);
|
||||
apk.incompatibleReasons = reasons.toArray(new String[reasons.size()]);
|
||||
} else {
|
||||
apk.compatible = true;
|
||||
apk.incompatibleReasons = null;
|
||||
|
@ -454,7 +454,7 @@ public final class LocalRepoManager {
|
||||
private void tagFeatures(App app) throws IOException {
|
||||
serializer.startTag("", "features");
|
||||
if (app.installedApk.features != null) {
|
||||
serializer.text(Utils.CommaSeparatedList.str(app.installedApk.features));
|
||||
serializer.text(TextUtils.join(",", app.installedApk.features));
|
||||
}
|
||||
serializer.endTag("", "features");
|
||||
}
|
||||
@ -462,7 +462,7 @@ public final class LocalRepoManager {
|
||||
private void tagNativecode(App app) throws IOException {
|
||||
if (app.installedApk.nativecode != null) {
|
||||
serializer.startTag("", "nativecode");
|
||||
serializer.text(Utils.CommaSeparatedList.str(app.installedApk.nativecode));
|
||||
serializer.text(TextUtils.join(",", app.installedApk.nativecode));
|
||||
serializer.endTag("", "nativecode");
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,11 @@ import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
@ -30,6 +34,8 @@ import javax.xml.parsers.SAXParserFactory;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@Config(constants = BuildConfig.class)
|
||||
@ -112,6 +118,65 @@ public class RepoXMLHandlerTest {
|
||||
expectedRepo.timestamp = 1412746769;
|
||||
RepoDetails actualDetails = getFromFile("largeRepo.xml");
|
||||
handlerTestSuite(expectedRepo, actualDetails, 1211, 2381, 14, 12);
|
||||
|
||||
// Generated using something like the following:
|
||||
// sed 's,<application,\n<application,g' largeRepo.xml | grep "antifeatures" | sed 's,.*id="\(.*\)".*<antifeatures>\(.*\)</antifeatures>.*,\1 \2,p' | sort | uniq
|
||||
Map<String, List<String>> expectedAntiFeatures = new HashMap<>();
|
||||
expectedAntiFeatures.put("org.fdroid.fdroid", new ArrayList<String>());
|
||||
expectedAntiFeatures.put("org.adblockplus.android", Arrays.asList("Tracking", "Ads"));
|
||||
expectedAntiFeatures.put("org.microg.nlp.backend.apple", Arrays.asList("Tracking", "NonFreeNet"));
|
||||
expectedAntiFeatures.put("com.ds.avare", Collections.singletonList("NonFreeDep"));
|
||||
expectedAntiFeatures.put("com.miracleas.bitcoin_spinner", Collections.singletonList("NonFreeAdd"));
|
||||
expectedAntiFeatures.put("de.Cherubin7th.blackscreenpresentationremote", Collections.singletonList("Ads"));
|
||||
expectedAntiFeatures.put("budo.budoist", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("no.rkkc.bysykkel", Collections.singletonList("NonFreeDep"));
|
||||
expectedAntiFeatures.put("com.jadn.cc", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("org.atai.TessUI", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("org.zephyrsoft.checknetwork", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("de.bashtian.dashclocksunrise", Collections.singletonList("NonFreeDep"));
|
||||
expectedAntiFeatures.put("org.geometerplus.zlibrary.ui.android", Collections.singletonList("NonFreeAdd"));
|
||||
expectedAntiFeatures.put("org.mozilla.firefox", Arrays.asList("NonFreeAdd", "Tracking"));
|
||||
expectedAntiFeatures.put("com.gmail.charleszq", Collections.singletonList("NonFreeDep"));
|
||||
expectedAntiFeatures.put("it.andreascarpino.forvodroid", Arrays.asList("NonFreeNet", "NonFreeDep"));
|
||||
expectedAntiFeatures.put("de.b0nk.fp1_epo_autoupdate", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("com.blogspot.tonyatkins.freespeech", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("com.frostwire.android", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("com.namsor.api.samples.gendre", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("com.github.mobile", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("com.cradle.iitc_mobile", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("com.matteopacini.katana", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("de.enaikoon.android.keypadmapper3", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("org.linphone", Collections.singletonList("NonFreeDep"));
|
||||
expectedAntiFeatures.put("ch.rrelmy.android.locationcachemap", Collections.singletonList("NonFreeDep"));
|
||||
expectedAntiFeatures.put("com.powerpoint45.lucidbrowser", Arrays.asList("Ads", "NonFreeDep"));
|
||||
expectedAntiFeatures.put("org.mixare", Collections.singletonList("NonFreeDep"));
|
||||
expectedAntiFeatures.put("apps.droidnotify", Collections.singletonList("NonFreeAdd"));
|
||||
expectedAntiFeatures.put("com.numix.calculator", Collections.singletonList("NonFreeAdd"));
|
||||
expectedAntiFeatures.put("com.numix.icons_circle", Collections.singletonList("NonFreeAdd"));
|
||||
expectedAntiFeatures.put("com.gh4a", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("at.tomtasche.reader", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("de.uni_potsdam.hpi.openmensa", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("net.osmand.plus", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("byrne.utilities.pasteedroid", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("com.bwx.bequick", Collections.singletonList("NonFreeAdd"));
|
||||
expectedAntiFeatures.put("be.geecko.QuickLyric", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("com.wanghaus.remembeer", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("cri.sanity", Collections.singletonList("Ads"));
|
||||
expectedAntiFeatures.put("com.showmehills", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("com.akop.bach", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("org.dmfs.tasks", Collections.singletonList("NonFreeAdd"));
|
||||
expectedAntiFeatures.put("org.telegram.messenger", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("com.danvelazco.fbwrapper", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("org.zephyrsoft.trackworktime", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("org.transdroid", Collections.singletonList("Tracking"));
|
||||
expectedAntiFeatures.put("com.lonepulse.travisjr", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("com.twsitedapps.homemanager", Collections.singletonList("NonFreeAdd"));
|
||||
expectedAntiFeatures.put("org.zeitgeist.movement", Collections.singletonList("NonFreeDep"));
|
||||
expectedAntiFeatures.put("net.wigle.wigleandroid", Collections.singletonList("NonFreeNet"));
|
||||
expectedAntiFeatures.put("org.nick.wwwjdic", Collections.singletonList("Tracking"));
|
||||
|
||||
checkAntiFeatures(actualDetails.apps, expectedAntiFeatures);
|
||||
|
||||
/*
|
||||
* generated using: sed 's,<application,\n<application,g' largeRepo.xml
|
||||
* | sed -n 's,.*id="\(.[^"]*\)".*,"\1"\,,p'
|
||||
@ -599,6 +664,22 @@ public class RepoXMLHandlerTest {
|
||||
});
|
||||
}
|
||||
|
||||
private void checkAntiFeatures(List<App> apps, Map<String, List<String>> expectedAntiFeatures) {
|
||||
for (App app : apps) {
|
||||
if (expectedAntiFeatures.containsKey(app.packageName)) {
|
||||
List<String> antiFeatures = expectedAntiFeatures.get(app.packageName);
|
||||
if (antiFeatures.size() == 0) {
|
||||
assertNull(app.antiFeatures);
|
||||
} else {
|
||||
List<String> actualAntiFeatures = new ArrayList<>();
|
||||
Collections.addAll(actualAntiFeatures, app.antiFeatures);
|
||||
assertTrue(actualAntiFeatures.containsAll(antiFeatures));
|
||||
assertTrue(antiFeatures.containsAll(actualAntiFeatures));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIncludedApps(List<App> actualApps, String[] expctedAppIds) {
|
||||
assertNotNull(actualApps);
|
||||
assertNotNull(expctedAppIds);
|
||||
|
@ -15,6 +15,8 @@ import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@Config(constants = BuildConfig.class)
|
||||
@ -49,6 +51,29 @@ public class UtilsTest {
|
||||
String fingerprintLongByOneFingerprint = "59050C8155DCA377F23D5A15B77D37134000CDBD8B42FBFBE0E3F38096E68CECE";
|
||||
String fingerprintLongByOnePubkey = "308203c5308202ada00302010202047b7cf549300d06092a864886f70d01010b0500308192310b30090603550406130255533111300f060355040813084e657720596f726b3111300f060355040713084e657720596f726b311d301b060355040a131454686520477561726469616e2050726f6a656374311f301d060355040b1316477561726469616e20462d44726f6964204275696c64311d301b06035504031314677561726469616e70726f6a6563742e696e666f301e170d3132313032393130323530305a170d3430303331363130323530305a308192310b30090603550406130255533111300f060355040813084e657720596f726b3111300f060355040713084e657720596f726b311d301b060355040a131454686520477561726469616e2050726f6a656374311f301d060355040b1316477561726469616e20462d44726f6964204275696c64311d301b06035504031314677561726469616e70726f6a6563742e696e666f30820122300d06092a864886f70d01010105000382010f003082010a0282010100b7f1f635fa3fce1a8042aaa960c2dc557e4ad2c082e5787488cba587fd26207cf59507919fc4dcebda5c8c0959d14146d0445593aa6c29dc639570b71712451fd5c231b0c9f5f0bec380503a1c2a3bc00048bc5db682915afa54d1ecf67b45e1e05c0934b3037a33d3a565899131f27a72c03a5de93df17a2376cc3107f03ee9d124c474dfab30d4053e8f39f292e2dcb6cc131bce12a0c5fc307985195d256bf1d7a2703d67c14bf18ed6b772bb847370b20335810e337c064fef7e2795a524c664a853cd46accb8494f865164dabfb698fa8318236432758bc40d52db00d5ce07fe2210dc06cd95298b4f09e6c9b7b7af61c1d62ea43ea36a2331e7b2d4e250203010001a321301f301d0603551d0e0416041404d763e981cf3a295b94a790d8536a783097232b300d06092a864886f70d01010b05000382010100654e6484ff032c54fed1d96d3c8e731302be9dbd7bb4fe635f2dac05b69f3ecbb5acb7c9fe405e2a066567a8f5c2beb8b199b5a4d5bb1b435cf02df026d4fb4edd9d8849078f085b00950083052d57467d65c6eebd98f037cff9b148d621cf8819c4f7dc1459bf8fc5c7d76f901495a7caf35d1e5c106e1d50610c4920c3c1b50adcfbd4ad83ce7353cdea7d856bba0419c224f89a2f3ebc203d20eb6247711ad2b55fd4737936dc42ced7a047cbbd24012079204a2883b6d55d5d5b66d9fd82fb51fca9a5db5fad9af8564cb380ff30ae8263dbbf01b46e01313f53279673daa3f893380285646b244359203e7eecde94ae141b7dfa8e6499bb8e7e0b25ab85";
|
||||
|
||||
@Test
|
||||
public void commaSeparatedStrings() {
|
||||
assertNull(Utils.parseCommaSeparatedString(null));
|
||||
assertNull(Utils.parseCommaSeparatedString(""));
|
||||
|
||||
String[] singleValue = Utils.parseCommaSeparatedString("single");
|
||||
assertNotNull(singleValue);
|
||||
assertEquals(1, singleValue.length);
|
||||
assertEquals("single", singleValue[0]);
|
||||
|
||||
String[] tripleValue = Utils.parseCommaSeparatedString("One,TWO,three");
|
||||
assertNotNull(tripleValue);
|
||||
assertEquals(3, tripleValue.length);
|
||||
assertEquals("One", tripleValue[0]);
|
||||
assertEquals("TWO", tripleValue[1]);
|
||||
assertEquals("three", tripleValue[2]);
|
||||
|
||||
assertNull(Utils.serializeCommaSeparatedString(null));
|
||||
assertNull(Utils.serializeCommaSeparatedString(new String[] {}));
|
||||
assertEquals("Single", Utils.serializeCommaSeparatedString(new String[] {"Single"}));
|
||||
assertEquals("One,TWO,three", Utils.serializeCommaSeparatedString(new String[] {"One", "TWO", "three"}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatFingerprint() {
|
||||
Context context = RuntimeEnvironment.application;
|
||||
|
@ -7,7 +7,6 @@ import android.net.Uri;
|
||||
|
||||
import org.fdroid.fdroid.Assert;
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.mock.MockApk;
|
||||
import org.fdroid.fdroid.mock.MockApp;
|
||||
import org.fdroid.fdroid.mock.MockRepo;
|
||||
@ -289,7 +288,8 @@ public class ApkProviderTest extends FDroidProviderTest {
|
||||
assertEquals(0, apk.repoVersion);
|
||||
|
||||
// But this should have saved correctly...
|
||||
assertEquals("Some features", apk.features.toString());
|
||||
assertEquals(1, apk.features.length);
|
||||
assertEquals("Some features", apk.features[0]);
|
||||
assertEquals("com.example.com", apk.packageName);
|
||||
assertEquals(1, apk.versionCode);
|
||||
assertEquals(10, apk.repo);
|
||||
@ -409,7 +409,7 @@ public class ApkProviderTest extends FDroidProviderTest {
|
||||
assertNull(apk.added);
|
||||
assertNull(apk.hashType);
|
||||
|
||||
apk.features = Utils.CommaSeparatedList.make("one,two,three");
|
||||
apk.features = new String[] {"one", "two", "three" };
|
||||
long dateTimestamp = System.currentTimeMillis();
|
||||
apk.added = new Date(dateTimestamp);
|
||||
apk.hashType = "i'm a hash type";
|
||||
@ -435,7 +435,10 @@ public class ApkProviderTest extends FDroidProviderTest {
|
||||
assertNotNull(updatedApk.added);
|
||||
assertNotNull(updatedApk.hashType);
|
||||
|
||||
assertEquals("one,two,three", updatedApk.features.toString());
|
||||
assertEquals(3, updatedApk.features.length);
|
||||
assertEquals("one", updatedApk.features[0]);
|
||||
assertEquals("two", updatedApk.features[1]);
|
||||
assertEquals("three", updatedApk.features[2]);
|
||||
assertEquals(new Date(dateTimestamp).getYear(), updatedApk.added.getYear());
|
||||
assertEquals(new Date(dateTimestamp).getMonth(), updatedApk.added.getMonth());
|
||||
assertEquals(new Date(dateTimestamp).getDay(), updatedApk.added.getDay());
|
||||
|
Loading…
x
Reference in New Issue
Block a user