Merge branch 'enforce-max-length-118' into 'master'
enforce max line length set by Android Studio, gitlab, etc. See merge request !532
This commit is contained in:
commit
833ae329e4
@ -54,7 +54,8 @@ public class HttpDownloaderTest {
|
||||
httpDownloader.setListener(new ProgressListener() {
|
||||
@Override
|
||||
public void onProgress(URL sourceUrl, int bytesRead, int totalBytes) {
|
||||
System.out.println("DownloaderProgressListener.sendProgress " + sourceUrl + " " + bytesRead + " / " + totalBytes);
|
||||
System.out.println("DownloaderProgressListener.sendProgress "
|
||||
+ sourceUrl + " " + bytesRead + " / " + totalBytes);
|
||||
receivedProgress = true;
|
||||
}
|
||||
});
|
||||
|
@ -107,6 +107,7 @@ import java.util.Map;
|
||||
* @author Brad Drehmer
|
||||
* @author gcstang
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class IntentIntegrator {
|
||||
|
||||
public static final int REQUEST_CODE = 0x0000c0de; // Only use bottom 16 bits
|
||||
|
@ -83,7 +83,8 @@ public final class IntentResult {
|
||||
@Override
|
||||
public String toString() {
|
||||
int rawBytesLength = rawBytes == null ? 0 : rawBytes.length;
|
||||
return "Format: " + formatName + '\n' + "Contents: " + contents + '\n' + "Raw bytes: (" + rawBytesLength + " bytes)\n" + "Orientation: " + orientation + '\n' + "EC level: " + errorCorrectionLevel + '\n';
|
||||
return "Format: " + formatName + '\n' + "Contents: " + contents + '\n' + "Raw bytes: (" + rawBytesLength
|
||||
+ " bytes)\n" + "Orientation: " + orientation + '\n' + "EC level: " + errorCorrectionLevel + '\n';
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ import org.fdroid.fdroid.views.apps.FeatureImage;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog.ShareChooserDialogListener, AppDetailsRecyclerViewAdapter.AppDetailsRecyclerViewAdapterCallbacks {
|
||||
|
||||
public static final String EXTRA_APPID = "appid";
|
||||
|
@ -32,7 +32,7 @@ public class AppFilter {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (app.antiFeatures != null && app.antiFeatures.length > 0 && Preferences.get().filterAppsWithAntiFeatures()) { // NOPMD
|
||||
if (app.antiFeatures != null && app.antiFeatures.length > 0 && Preferences.get().filterAppsWithAntiFeatures()) { // NOPMD NOCHECKSTYLE LineLength
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -13,7 +13,6 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.TaskStackBuilder;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
@ -36,16 +35,17 @@ import java.util.Map;
|
||||
* and {@code versionCode} since there could be different copies of the same
|
||||
* APK on different servers, signed by different keys, or even different builds.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public final class AppUpdateStatusManager {
|
||||
|
||||
private static final String TAG = "AppUpdateStatusManager";
|
||||
|
||||
/**
|
||||
* Broadcast when:
|
||||
* * The user clears the list of installed apps from notification manager.
|
||||
* * The user clears the list of apps available to update from the notification manager.
|
||||
* * A repo update is completed and a bunch of new apps are ready to be updated.
|
||||
* * F-Droid is opened, and it finds a bunch of .apk files downloaded and ready to install.
|
||||
* * The user clears the list of installed apps from notification manager.
|
||||
* * The user clears the list of apps available to update from the notification manager.
|
||||
* * A repo update is completed and a bunch of new apps are ready to be updated.
|
||||
* * F-Droid is opened, and it finds a bunch of .apk files downloaded and ready to install.
|
||||
*/
|
||||
public static final String BROADCAST_APPSTATUS_LIST_CHANGED = "org.fdroid.fdroid.installer.appstatus.listchange";
|
||||
|
||||
@ -61,9 +61,9 @@ public final class AppUpdateStatusManager {
|
||||
|
||||
/**
|
||||
* Broadcast when:
|
||||
* * The associated app has the {@link Status#Installed} status, and the user either visits
|
||||
* that apps details page or clears the individual notification for the app.
|
||||
* * The download for an app is cancelled.
|
||||
* * The associated app has the {@link Status#Installed} status, and the user either visits
|
||||
* that apps details page or clears the individual notification for the app.
|
||||
* * The download for an app is cancelled.
|
||||
*/
|
||||
public static final String BROADCAST_APPSTATUS_REMOVED = "org.fdroid.fdroid.installer.appstatus.appchange.remove";
|
||||
|
||||
@ -129,7 +129,8 @@ public final class AppUpdateStatusManager {
|
||||
* Dumps some information about the status for debugging purposes.
|
||||
*/
|
||||
public String toString() {
|
||||
return app.packageName + " [Status: " + status + ", Progress: " + progressCurrent + " / " + progressMax + "]";
|
||||
return app.packageName + " [Status: " + status
|
||||
+ ", Progress: " + progressCurrent + " / " + progressMax + "]";
|
||||
}
|
||||
|
||||
protected AppUpdateStatus(Parcel in) {
|
||||
@ -191,7 +192,9 @@ public final class AppUpdateStatusManager {
|
||||
private final HashMap<String, AppUpdateStatus> appMapping = new HashMap<>();
|
||||
private boolean isBatchUpdating;
|
||||
|
||||
/** @see #isPendingInstall(String) */
|
||||
/**
|
||||
* @see #isPendingInstall(String)
|
||||
*/
|
||||
private final SharedPreferences apksPendingInstall;
|
||||
|
||||
private AppUpdateStatusManager(Context context) {
|
||||
@ -215,6 +218,7 @@ public final class AppUpdateStatusManager {
|
||||
|
||||
/**
|
||||
* Get all entries associated with a package name. There may be several.
|
||||
*
|
||||
* @param packageName Package name of the app
|
||||
* @return A list of entries, or an empty list
|
||||
*/
|
||||
@ -309,8 +313,9 @@ public final class AppUpdateStatusManager {
|
||||
|
||||
/**
|
||||
* Add an Apk to the AppUpdateStatusManager manager (or update it if we already know about it).
|
||||
* @param apk The apk to add.
|
||||
* @param status The current status of the app
|
||||
*
|
||||
* @param apk The apk to add.
|
||||
* @param status The current status of the app
|
||||
* @param pendingIntent Action when notification is clicked. Can be null for default action(s)
|
||||
*/
|
||||
public void addApk(Apk apk, @NonNull Status status, @Nullable PendingIntent pendingIntent) {
|
||||
@ -433,7 +438,7 @@ public final class AppUpdateStatusManager {
|
||||
|
||||
void clearAllUpdates() {
|
||||
synchronized (appMapping) {
|
||||
for (Iterator<Map.Entry<String, AppUpdateStatus>> it = appMapping.entrySet().iterator(); it.hasNext();) {
|
||||
for (Iterator<Map.Entry<String, AppUpdateStatus>> it = appMapping.entrySet().iterator(); it.hasNext(); ) { // NOCHECKSTYLE EmptyForIteratorPad
|
||||
Map.Entry<String, AppUpdateStatus> entry = it.next();
|
||||
if (entry.getValue().status != Status.Installed) {
|
||||
it.remove();
|
||||
@ -445,7 +450,7 @@ public final class AppUpdateStatusManager {
|
||||
|
||||
void clearAllInstalled() {
|
||||
synchronized (appMapping) {
|
||||
for (Iterator<Map.Entry<String, AppUpdateStatus>> it = appMapping.entrySet().iterator(); it.hasNext();) {
|
||||
for (Iterator<Map.Entry<String, AppUpdateStatus>> it = appMapping.entrySet().iterator(); it.hasNext(); ) { // NOCHECKSTYLE EmptyForIteratorPad
|
||||
Map.Entry<String, AppUpdateStatus> entry = it.next();
|
||||
if (entry.getValue().status == Status.Installed) {
|
||||
it.remove();
|
||||
@ -517,6 +522,7 @@ public final class AppUpdateStatusManager {
|
||||
* being more permanent than the notification info. As such, the different clients should be
|
||||
* aware of their requirements when invoking general-sounding methods like "addApk()", rather
|
||||
* than this class trying to second-guess why they added an apk.
|
||||
*
|
||||
* @see #isPendingInstall(String)
|
||||
*/
|
||||
public void markAsPendingInstall(String uniqueKey) {
|
||||
|
@ -25,6 +25,7 @@ import java.util.List;
|
||||
* run on a background thread, as it hits the disk a bit to figure out the hash of each downloaded
|
||||
* file.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class AppUpdateStatusService extends IntentService {
|
||||
|
||||
private static final String TAG = "AppUpdateStatusService";
|
||||
|
@ -290,7 +290,7 @@ public class FDroidApp extends Application {
|
||||
String fileNameToSanitize;
|
||||
Uri uri = Uri.parse(imageUri);
|
||||
if (TextUtils.isEmpty(uri.getPath())) {
|
||||
// e.g. files with a URL like "drawable://213083835209" used by the category backgrounds.
|
||||
// files with URL like "drawable://213083835209" used by the category backgrounds
|
||||
fileNameToSanitize = imageUri.replaceAll("[:/]", "");
|
||||
} else {
|
||||
fileNameToSanitize = uri.getPath().replace("/", "-");
|
||||
|
@ -33,6 +33,7 @@ import org.fdroid.fdroid.views.main.MainActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
class NotificationHelper {
|
||||
|
||||
static final String BROADCAST_NOTIFICATIONS_ALL_UPDATES_CLEARED = "org.fdroid.fdroid.installer.notifications.allupdates.cleared";
|
||||
|
@ -5,6 +5,7 @@ import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import info.guardianproject.netcipher.NetCipher;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
@ -16,8 +17,6 @@ import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import info.guardianproject.netcipher.NetCipher;
|
||||
|
||||
/**
|
||||
* Handles shared preferences for FDroid, looking after the names of
|
||||
* preferences, default values and caching. Needs to be setup in the FDroidApp
|
||||
@ -320,7 +319,8 @@ public final class Preferences implements SharedPreferences.OnSharedPreferenceCh
|
||||
public boolean filterAppsWithAntiFeatures() {
|
||||
if (!isInitialized(PREF_HIDE_ANTI_FEATURE_APPS)) {
|
||||
initialize(PREF_HIDE_ANTI_FEATURE_APPS);
|
||||
filterAppsWithAntiFeatures = preferences.getBoolean(PREF_HIDE_ANTI_FEATURE_APPS, DEFAULT_HIDE_ANTI_FEATURE_APPS);
|
||||
filterAppsWithAntiFeatures = preferences.getBoolean(PREF_HIDE_ANTI_FEATURE_APPS,
|
||||
DEFAULT_HIDE_ANTI_FEATURE_APPS);
|
||||
}
|
||||
return filterAppsWithAntiFeatures;
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class UpdateService extends IntentService {
|
||||
|
||||
private static final String TAG = "UpdateService";
|
||||
|
@ -244,7 +244,8 @@ public class Apk extends ValueObject implements Comparable<Apk>, Parcelable {
|
||||
|
||||
private void checkRepoAddress() {
|
||||
if (repoAddress == null || apkName == null) {
|
||||
throw new IllegalStateException("Apk needs to have both Schema.ApkTable.Cols.REPO_ADDRESS and Schema.ApkTable.Cols.NAME set in order to calculate URL.");
|
||||
throw new IllegalStateException("Apk needs to have both Schema.ApkTable.Cols.REPO_ADDRESS and "
|
||||
+ "Schema.ApkTable.Cols.NAME set in order to calculate URL.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class ApkProvider extends FDroidProvider {
|
||||
|
||||
private static final String TAG = "ApkProvider";
|
||||
@ -88,7 +89,8 @@ public class ApkProvider extends FDroidProvider {
|
||||
return cursorToList(cursor);
|
||||
}
|
||||
|
||||
public static Apk findApkFromAnyRepo(Context context, String packageName, int versionCode, String[] projection) {
|
||||
public static Apk findApkFromAnyRepo(Context context,
|
||||
String packageName, int versionCode, String[] projection) {
|
||||
final Uri uri = getApkFromAnyRepoUri(packageName, versionCode);
|
||||
return findByUri(context, uri, projection);
|
||||
}
|
||||
@ -283,7 +285,7 @@ public class ApkProvider extends FDroidProvider {
|
||||
* Intentionally left protected because it will break if apks is larger than
|
||||
* {@link org.fdroid.fdroid.data.ApkProvider#MAX_APKS_TO_QUERY}. Instead of using
|
||||
* this directly, think about using
|
||||
* {@link org.fdroid.fdroid.data.ApkProvider.Helper#knownApks(android.content.Context, java.util.List, String[])}
|
||||
* {@link ApkProvider.Helper#knownApks(android.content.Context, java.util.List, String[])}
|
||||
*/
|
||||
static Uri getContentUri(List<Apk> apks) {
|
||||
return getContentUri().buildUpon()
|
||||
|
@ -476,11 +476,11 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
||||
promoGraphic = getLocalizedGraphicsEntry(localized, localesToUse, "promoGraphic");
|
||||
tvBanner = getLocalizedGraphicsEntry(localized, localesToUse, "tvBanner");
|
||||
|
||||
wearScreenshots = setLocalizedListEntry(localized, localesToUse, "wearScreenshots");
|
||||
phoneScreenshots = setLocalizedListEntry(localized, localesToUse, "phoneScreenshots");
|
||||
sevenInchScreenshots = setLocalizedListEntry(localized, localesToUse, "sevenInchScreenshots");
|
||||
tenInchScreenshots = setLocalizedListEntry(localized, localesToUse, "tenInchScreenshots");
|
||||
tvScreenshots = setLocalizedListEntry(localized, localesToUse, "tvScreenshots");
|
||||
wearScreenshots = getLocalizedListEntry(localized, localesToUse, "wearScreenshots");
|
||||
phoneScreenshots = getLocalizedListEntry(localized, localesToUse, "phoneScreenshots");
|
||||
sevenInchScreenshots = getLocalizedListEntry(localized, localesToUse, "sevenInchScreenshots");
|
||||
tenInchScreenshots = getLocalizedListEntry(localized, localesToUse, "tenInchScreenshots");
|
||||
tvScreenshots = getLocalizedListEntry(localized, localesToUse, "tvScreenshots");
|
||||
}
|
||||
|
||||
private String getLocalizedEntry(Map<String, Map<String, Object>> localized,
|
||||
@ -518,7 +518,7 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String[] setLocalizedListEntry(Map<String, Map<String, Object>> localized,
|
||||
private String[] getLocalizedListEntry(Map<String, Map<String, Object>> localized,
|
||||
Set<String> locales, String key) {
|
||||
try {
|
||||
for (String locale : locales) {
|
||||
@ -909,7 +909,7 @@ public class App extends ValueObject implements Comparable<App>, Parcelable {
|
||||
* {@code AndroidManifest.xml}. If {@code targetSdkVersion} is not set, then it is
|
||||
* equal to {@code minSdkVersion}
|
||||
*
|
||||
* @see <a href="https://developer.android.com/guide/topics/manifest/uses-sdk-element.html"><uses-sdk> element</a>
|
||||
* @see <a href="https://developer.android.com/guide/topics/manifest/uses-sdk-element.html"><uses-sdk></a>
|
||||
*/
|
||||
private static int[] getMinTargetMaxSdkVersions(Context context, String packageName) {
|
||||
int minSdkVersion = Apk.SDK_VERSION_MIN_VALUE;
|
||||
|
@ -7,14 +7,14 @@ import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.fdroid.fdroid.data.Schema.AppPrefsTable;
|
||||
import org.fdroid.fdroid.data.Schema.AppPrefsTable.Cols;
|
||||
|
||||
public class AppPrefsProvider extends FDroidProvider {
|
||||
|
||||
public static final class Helper {
|
||||
private Helper() { }
|
||||
private Helper() {
|
||||
}
|
||||
|
||||
public static void update(Context context, App app, AppPrefs prefs) {
|
||||
ContentValues values = new ContentValues(3);
|
||||
@ -37,7 +37,8 @@ public class AppPrefsProvider extends FDroidProvider {
|
||||
|
||||
@Nullable
|
||||
public static AppPrefs getPrefsOrNull(Context context, App app) {
|
||||
Cursor cursor = context.getContentResolver().query(getAppUri(app.packageName), Cols.ALL, null, null, null);
|
||||
Cursor cursor = context.getContentResolver().query(getAppUri(app.packageName), Cols.ALL,
|
||||
null, null, null);
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
}
|
||||
@ -114,7 +115,8 @@ public class AppPrefsProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
public Cursor query(Uri uri, String[] projection,
|
||||
String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
if (MATCHER.match(uri) != CODE_SINGLE) {
|
||||
throw new UnsupportedOperationException("Invalid URI for app content provider: " + uri);
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ import java.util.Set;
|
||||
* The same can be said of retrieving a list of {@link App} objects, where the metadata for each app
|
||||
* in the result set should be populated from the repository with the best priority.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class AppProvider extends FDroidProvider {
|
||||
|
||||
private static final String TAG = "AppProvider";
|
||||
|
@ -6,17 +6,17 @@ import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable;
|
||||
import org.fdroid.fdroid.data.Schema.CatJoinTable;
|
||||
import org.fdroid.fdroid.data.Schema.CategoryTable;
|
||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable;
|
||||
import org.fdroid.fdroid.data.Schema.PackageTable;
|
||||
import org.fdroid.fdroid.data.Schema.CategoryTable.Cols;
|
||||
import org.fdroid.fdroid.data.Schema.PackageTable;
|
||||
|
||||
public class CategoryProvider extends FDroidProvider {
|
||||
|
||||
public static final class Helper {
|
||||
private Helper() { }
|
||||
private Helper() {
|
||||
}
|
||||
|
||||
public static long ensureExists(Context context, String category) {
|
||||
long id = getCategoryId(context, category);
|
||||
@ -30,8 +30,9 @@ public class CategoryProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
public static long getCategoryId(Context context, String category) {
|
||||
String[] projection = new String[] {Cols.ROW_ID};
|
||||
Cursor cursor = context.getContentResolver().query(getCategoryUri(category), projection, null, null, null);
|
||||
String[] projection = new String[]{Cols.ROW_ID};
|
||||
Cursor cursor = context.getContentResolver().query(getCategoryUri(category), projection,
|
||||
null, null, null);
|
||||
if (cursor == null) {
|
||||
return 0;
|
||||
}
|
||||
@ -70,8 +71,10 @@ public class CategoryProvider extends FDroidProvider {
|
||||
public void setOnlyCategoriesWithApps() {
|
||||
// Make sure that metadata from the preferred repository is used to determine if
|
||||
// there is an app present or not.
|
||||
join(AppMetadataTable.NAME, "app", "app." + AppMetadataTable.Cols.ROW_ID + " = " + CatJoinTable.NAME + "." + CatJoinTable.Cols.APP_METADATA_ID);
|
||||
join(PackageTable.NAME, "pkg", "pkg." + PackageTable.Cols.PREFERRED_METADATA + " = " + "app." + AppMetadataTable.Cols.ROW_ID);
|
||||
join(AppMetadataTable.NAME, "app", "app." + AppMetadataTable.Cols.ROW_ID
|
||||
+ " = " + CatJoinTable.NAME + "." + CatJoinTable.Cols.APP_METADATA_ID);
|
||||
join(PackageTable.NAME, "pkg", "pkg." + PackageTable.Cols.PREFERRED_METADATA
|
||||
+ " = " + "app." + AppMetadataTable.Cols.ROW_ID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +154,8 @@ public class CategoryProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(@NonNull Uri uri, String[] projection, String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
public Cursor query(@NonNull Uri uri, String[] projection,
|
||||
String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
QuerySelection selection = new QuerySelection(customSelection, selectionArgs);
|
||||
boolean onlyCategoriesWithApps = false;
|
||||
switch (MATCHER.match(uri)) {
|
||||
|
@ -45,6 +45,7 @@ import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
class DBHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String TAG = "DBHelper";
|
||||
|
@ -163,6 +163,7 @@ public abstract class FDroidProvider extends ContentProvider {
|
||||
* when all you have is the package name.
|
||||
*/
|
||||
protected static String getPackageIdFromPackageNameQuery() {
|
||||
return "SELECT " + Schema.PackageTable.Cols.ROW_ID + " FROM " + Schema.PackageTable.NAME + " WHERE " + Schema.PackageTable.Cols.PACKAGE_NAME + " = ?";
|
||||
return "SELECT " + Schema.PackageTable.Cols.ROW_ID + " FROM " + Schema.PackageTable.NAME
|
||||
+ " WHERE " + Schema.PackageTable.Cols.PACKAGE_NAME + " = ?";
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Schema.InstalledAppTable;
|
||||
@ -77,7 +76,7 @@ public class InstalledAppProvider extends FDroidProvider {
|
||||
private static final String PROVIDER_NAME = "InstalledAppProvider";
|
||||
|
||||
private static final String PATH_SEARCH = "search";
|
||||
private static final int CODE_SEARCH = CODE_SINGLE + 1;
|
||||
private static final int CODE_SEARCH = CODE_SINGLE + 1;
|
||||
|
||||
private static final UriMatcher MATCHER = new UriMatcher(-1);
|
||||
|
||||
@ -100,9 +99,9 @@ public class InstalledAppProvider extends FDroidProvider {
|
||||
|
||||
public static Uri getSearchUri(String keywords) {
|
||||
return getContentUri().buildUpon()
|
||||
.appendPath(PATH_SEARCH)
|
||||
.appendPath(keywords)
|
||||
.build();
|
||||
.appendPath(PATH_SEARCH)
|
||||
.appendPath(keywords)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static String getApplicationLabel(Context context, String packageName) {
|
||||
@ -146,7 +145,8 @@ public class InstalledAppProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
public Cursor query(Uri uri, String[] projection,
|
||||
String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
if (sortOrder == null) {
|
||||
sortOrder = Cols.APPLICATION_LABEL;
|
||||
}
|
||||
@ -170,7 +170,8 @@ public class InstalledAppProvider extends FDroidProvider {
|
||||
throw new UnsupportedOperationException(message);
|
||||
}
|
||||
|
||||
Cursor cursor = db().query(getTableName(), projection, selection.getSelection(), selection.getArgs(), null, null, sortOrder);
|
||||
Cursor cursor = db().query(getTableName(), projection,
|
||||
selection.getSelection(), selection.getArgs(), null, null, sortOrder);
|
||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
||||
return cursor;
|
||||
}
|
||||
@ -207,7 +208,8 @@ public class InstalledAppProvider extends FDroidProvider {
|
||||
*/
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
|
||||
throw new UnsupportedOperationException("\"Update' not supported for installed appp provider. Instead, you should insert, and it will overwrite the relevant rows if one exists.");
|
||||
throw new UnsupportedOperationException("\"Update' not supported for installed appp provider."
|
||||
+ " Instead, you should insert, and it will overwrite the relevant rows if one exists.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,6 +42,7 @@ import rx.subjects.PublishSubject;
|
||||
* {@link #deleteAppFromDb(Context, String)} are both static methods to enable easy testing
|
||||
* of this stuff.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class InstalledAppProviderService extends IntentService {
|
||||
private static final String TAG = "InstalledAppProviderSer";
|
||||
|
||||
@ -94,7 +95,8 @@ public class InstalledAppProviderService extends IntentService {
|
||||
.subscribe(new Action1<String>() {
|
||||
@Override
|
||||
public void call(String packageName) {
|
||||
getContentResolver().notifyChange(AppProvider.getHighestPriorityMetadataUri(packageName), null);
|
||||
getContentResolver()
|
||||
.notifyChange(AppProvider.getHighestPriorityMetadataUri(packageName), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ import org.fdroid.fdroid.Utils;
|
||||
* LEFT JOIN fdroid_apk ON (fdroid_apk.appId = fdroid_app.rowid)
|
||||
* LEFT JOIN fdroid_repo ON (fdroid_apk.repo = fdroid_repo._id)
|
||||
* LEFT JOIN fdroid_installedApp AS installed ON (installed.appId = fdroid_app.id)
|
||||
* LEFT JOIN fdroid_apk AS suggestedApk ON (fdroid_app.suggestedVercode = suggestedApk.vercode AND fdroid_app.rowid = suggestedApk.appId)
|
||||
* LEFT JOIN fdroid_apk AS suggestedApk ON (fdroid_app.suggestedVercode = suggestedApk.vercode
|
||||
* AND fdroid_app.rowid = suggestedApk.appId)
|
||||
* WHERE
|
||||
* fdroid_repo.isSwap = 0 OR fdroid_repo.isSwap IS NULL
|
||||
* GROUP BY fdroid_app.rowid
|
||||
|
@ -5,14 +5,14 @@ import android.content.Context;
|
||||
import android.content.UriMatcher;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.fdroid.fdroid.data.Schema.PackageTable;
|
||||
import org.fdroid.fdroid.data.Schema.PackageTable.Cols;
|
||||
|
||||
public class PackageProvider extends FDroidProvider {
|
||||
|
||||
public static final class Helper {
|
||||
private Helper() { }
|
||||
private Helper() {
|
||||
}
|
||||
|
||||
public static long ensureExists(Context context, String packageName) {
|
||||
long id = getPackageId(context, packageName);
|
||||
@ -26,8 +26,9 @@ public class PackageProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
public static long getPackageId(Context context, String packageName) {
|
||||
String[] projection = new String[] {Cols.ROW_ID};
|
||||
Cursor cursor = context.getContentResolver().query(getPackageUri(packageName), projection, null, null, null);
|
||||
String[] projection = new String[]{Cols.ROW_ID};
|
||||
Cursor cursor = context.getContentResolver().query(getPackageUri(packageName), projection,
|
||||
null, null, null);
|
||||
if (cursor == null) {
|
||||
return 0;
|
||||
}
|
||||
@ -122,7 +123,8 @@ public class PackageProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
public Cursor query(Uri uri, String[] projection,
|
||||
String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
if (MATCHER.match(uri) != CODE_SINGLE) {
|
||||
throw new UnsupportedOperationException("Invalid URI for content provider: " + uri);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ abstract class QueryBuilder {
|
||||
}
|
||||
|
||||
protected final void appendField(String field, String tableAlias,
|
||||
String fieldAlias) {
|
||||
String fieldAlias) {
|
||||
|
||||
StringBuilder fieldBuilder = new StringBuilder();
|
||||
|
||||
@ -121,17 +121,17 @@ abstract class QueryBuilder {
|
||||
|
||||
private void joinWithType(String type, String table, String alias, String condition) {
|
||||
tables.append(' ')
|
||||
.append(type)
|
||||
.append(" JOIN ")
|
||||
.append(table);
|
||||
.append(type)
|
||||
.append(" JOIN ")
|
||||
.append(table);
|
||||
|
||||
if (alias != null) {
|
||||
tables.append(" AS ").append(alias);
|
||||
}
|
||||
|
||||
tables.append(" ON (")
|
||||
.append(condition)
|
||||
.append(')');
|
||||
.append(condition)
|
||||
.append(')');
|
||||
}
|
||||
|
||||
private String distinctSql() {
|
||||
@ -166,6 +166,7 @@ abstract class QueryBuilder {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "SELECT " + distinctSql() + fieldsSql() + " FROM " + tablesSql() + whereSql() + groupBySql() + orderBySql() + limitSql();
|
||||
return "SELECT " + distinctSql() + fieldsSql() + " FROM " + tablesSql()
|
||||
+ whereSql() + groupBySql() + orderBySql() + limitSql();
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class RepoPersister {
|
||||
|
||||
private static final String TAG = "RepoPersister";
|
||||
|
@ -10,7 +10,6 @@ import android.net.Uri;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||
import org.fdroid.fdroid.data.Schema.RepoTable.Cols;
|
||||
@ -27,7 +26,8 @@ public class RepoProvider extends FDroidProvider {
|
||||
|
||||
private static final String TAG = "RepoProvider.Helper";
|
||||
|
||||
private Helper() { }
|
||||
private Helper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find by the content URI of a repo ({@link RepoProvider#getContentUri(long)}).
|
||||
@ -54,14 +54,15 @@ public class RepoProvider extends FDroidProvider {
|
||||
* This method decides what repo a URL belongs to by iteratively removing path fragments and
|
||||
* checking if it belongs to a repo or not. It will match the most specific repository which
|
||||
* could serve the file at the given URL.
|
||||
*
|
||||
* <p>
|
||||
* For any given HTTP resource requested by F-Droid, it should belong to a repository.
|
||||
* Whether that resource is an index.jar, an icon, or a .apk file, they all belong to a
|
||||
* repository. Therefore, that repository must exist in the database. The way to find out
|
||||
* which repository a particular URL came from requires some consideration:
|
||||
* * Repositories can exist at particular paths on a server (e.g. /fdroid/repo)
|
||||
* * Individual files can exist at a more specific path on the repo (e.g. /fdroid/repo/icons/org.fdroid.fdroid.png)
|
||||
*
|
||||
* <li>Repositories can exist at particular paths on a server (e.g. /fdroid/repo)
|
||||
* <li>Individual files can exist at a more specific path on the repo (e.g.
|
||||
* /fdroid/repo/icons/org.fdroid.fdroid.png)</li>
|
||||
* <p>
|
||||
* So for a given URL "/fdroid/repo/icons/org.fdroid.fdroid.png" we don't actually know
|
||||
* whether it is for the file "org.fdroid.fdroid.png" at repository "/fdroid/repo/icons" or
|
||||
* the file "icons/org.fdroid.fdroid.png" at the repository at "/fdroid/repo".
|
||||
@ -212,7 +213,7 @@ public class RepoProvider extends FDroidProvider {
|
||||
* each of the CRUD methods available in the helper class.
|
||||
*/
|
||||
public static Uri insert(Context context,
|
||||
ContentValues values) {
|
||||
ContentValues values) {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Uri uri = RepoProvider.getContentUri();
|
||||
return resolver.insert(uri, values);
|
||||
@ -258,7 +259,8 @@ public class RepoProvider extends FDroidProvider {
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
final String[] projection = {Cols.LAST_UPDATED};
|
||||
final String selection = Cols.IN_USE + " = 1";
|
||||
Cursor cursor = resolver.query(getContentUri(), projection, selection, null, Cols.LAST_UPDATED + " DESC");
|
||||
Cursor cursor = resolver.query(getContentUri(), projection,
|
||||
selection, null, Cols.LAST_UPDATED + " DESC");
|
||||
|
||||
Date lastUpdate = null;
|
||||
if (cursor != null) {
|
||||
@ -347,7 +349,8 @@ public class RepoProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
public Cursor query(Uri uri, String[] projection,
|
||||
String selection, String[] selectionArgs, String sortOrder) {
|
||||
|
||||
if (TextUtils.isEmpty(sortOrder)) {
|
||||
sortOrder = Cols.PRIORITY + " ASC";
|
||||
@ -360,7 +363,7 @@ public class RepoProvider extends FDroidProvider {
|
||||
|
||||
case CODE_SINGLE:
|
||||
selection = (selection == null ? "" : selection + " AND ") +
|
||||
Cols._ID + " = " + uri.getLastPathSegment();
|
||||
Cols._ID + " = " + uri.getLastPathSegment();
|
||||
break;
|
||||
|
||||
case CODE_ALL_EXCEPT_SWAP:
|
||||
@ -372,7 +375,8 @@ public class RepoProvider extends FDroidProvider {
|
||||
throw new UnsupportedOperationException("Invalid URI for repo content provider: " + uri);
|
||||
}
|
||||
|
||||
Cursor cursor = db().query(getTableName(), projection, selection, selectionArgs, null, null, sortOrder);
|
||||
Cursor cursor = db().query(getTableName(), projection,
|
||||
selection, selectionArgs, null, null, sortOrder);
|
||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
||||
return cursor;
|
||||
}
|
||||
@ -415,7 +419,8 @@ public class RepoProvider extends FDroidProvider {
|
||||
}
|
||||
|
||||
private int getMaxPriority() {
|
||||
Cursor cursor = db().query(RepoTable.NAME, new String[] {"MAX(" + Cols.PRIORITY + ")"}, "COALESCE(" + Cols.IS_SWAP + ", 0) = 0", null, null, null, null);
|
||||
Cursor cursor = db().query(RepoTable.NAME, new String[]{"MAX(" + Cols.PRIORITY + ")"},
|
||||
"COALESCE(" + Cols.IS_SWAP + ", 0) = 0", null, null, null, null);
|
||||
cursor.moveToFirst();
|
||||
int max = cursor.getInt(0);
|
||||
cursor.close();
|
||||
@ -432,7 +437,7 @@ public class RepoProvider extends FDroidProvider {
|
||||
return 0;
|
||||
|
||||
case CODE_SINGLE:
|
||||
selection = selection.add(Cols._ID + " = ?", new String[] {uri.getLastPathSegment()});
|
||||
selection = selection.add(Cols._ID + " = ?", new String[]{uri.getLastPathSegment()});
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -464,7 +469,8 @@ public class RepoProvider extends FDroidProvider {
|
||||
// to be recalculated.
|
||||
boolean priorityChanged = false;
|
||||
if (values.containsKey(Cols.PRIORITY)) {
|
||||
Cursor priorityCursor = db().query(getTableName(), new String[]{Cols.PRIORITY}, where, whereArgs, null, null, null);
|
||||
Cursor priorityCursor = db().query(getTableName(), new String[]{Cols.PRIORITY},
|
||||
where, whereArgs, null, null, null);
|
||||
if (priorityCursor.getCount() > 0) {
|
||||
priorityCursor.moveToFirst();
|
||||
int oldPriority = priorityCursor.getInt(priorityCursor.getColumnIndex(Cols.PRIORITY));
|
||||
|
@ -13,6 +13,7 @@ import java.util.List;
|
||||
/**
|
||||
* This class does all of its operations in a temporary sqlite table.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class TempApkProvider extends ApkProvider {
|
||||
|
||||
private static final String PROVIDER_NAME = "TempApkProvider";
|
||||
|
@ -8,9 +8,6 @@ import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Schema.ApkTable;
|
||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable;
|
||||
@ -18,9 +15,12 @@ import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols;
|
||||
import org.fdroid.fdroid.data.Schema.CatJoinTable;
|
||||
import org.fdroid.fdroid.data.Schema.PackageTable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class does all of its operations in a temporary sqlite table.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class TempAppProvider extends AppProvider {
|
||||
|
||||
/**
|
||||
@ -94,7 +94,7 @@ public class TempAppProvider extends AppProvider {
|
||||
}
|
||||
|
||||
private AppQuerySelection queryRepo(long repoId) {
|
||||
String[] args = new String[] {Long.toString(repoId)};
|
||||
String[] args = new String[]{Long.toString(repoId)};
|
||||
String selection = getTableName() + "." + Cols.REPO_ID + " = ? ";
|
||||
return new AppQuerySelection(selection, args);
|
||||
}
|
||||
@ -111,7 +111,8 @@ public class TempAppProvider extends AppProvider {
|
||||
TempApkProvider.Helper.init(context);
|
||||
}
|
||||
|
||||
public static List<App> findByPackageNames(Context context, List<String> packageNames, long repoId, String[] projection) {
|
||||
public static List<App> findByPackageNames(Context context,
|
||||
List<String> packageNames, long repoId, String[] projection) {
|
||||
Uri uri = getAppsUri(packageNames, repoId);
|
||||
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
|
||||
return AppProvider.Helper.cursorToList(cursor);
|
||||
@ -167,7 +168,8 @@ public class TempAppProvider extends AppProvider {
|
||||
values.remove(Cols.Package.PACKAGE_NAME);
|
||||
|
||||
if (values.containsKey(Cols.ForWriting.Categories.CATEGORIES)) {
|
||||
String[] categories = Utils.parseCommaSeparatedString(values.getAsString(Cols.ForWriting.Categories.CATEGORIES));
|
||||
String[] categories = Utils.parseCommaSeparatedString(
|
||||
values.getAsString(Cols.ForWriting.Categories.CATEGORIES));
|
||||
ensureCategories(categories, packageName, repoId);
|
||||
values.remove(Cols.ForWriting.Categories.CATEGORIES);
|
||||
}
|
||||
@ -192,7 +194,8 @@ public class TempAppProvider extends AppProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
public Cursor query(Uri uri, String[] projection,
|
||||
String customSelection, String[] selectionArgs, String sortOrder) {
|
||||
AppQuerySelection selection = new AppQuerySelection(customSelection, selectionArgs);
|
||||
switch (MATCHER.match(uri)) {
|
||||
case APPS:
|
||||
|
@ -23,9 +23,7 @@ import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.nostra13.universalimageloader.utils.StorageUtils;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.fdroid.fdroid.Hasher;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
@ -45,7 +43,8 @@ public class ApkCache {
|
||||
* verify the hash after copying. This is because we are copying from an installed apk, which
|
||||
* other apps do not have permission to modify.
|
||||
*/
|
||||
public static SanitizedFile copyInstalledApkToFiles(Context context, PackageInfo packageInfo) throws IOException {
|
||||
public static SanitizedFile copyInstalledApkToFiles(Context context, PackageInfo packageInfo)
|
||||
throws IOException {
|
||||
ApplicationInfo appInfo = packageInfo.applicationInfo;
|
||||
CharSequence name = context.getPackageManager().getApplicationLabel(appInfo);
|
||||
String apkFileName = name + "-" + packageInfo.versionName + ".apk";
|
||||
@ -60,7 +59,8 @@ public class ApkCache {
|
||||
*/
|
||||
public static SanitizedFile copyApkFromCacheToFiles(Context context, File apkFile, Apk expectedApk)
|
||||
throws IOException {
|
||||
App app = AppProvider.Helper.findHighestPriorityMetadata(context.getContentResolver(), expectedApk.packageName);
|
||||
App app = AppProvider.Helper.findHighestPriorityMetadata(context.getContentResolver(),
|
||||
expectedApk.packageName);
|
||||
String name = app == null ? expectedApk.packageName : app.name;
|
||||
String apkFileName = name + "-" + expectedApk.versionName + ".apk";
|
||||
return copyApkToFiles(context, apkFile, apkFileName, true, expectedApk.hash, expectedApk.hashType);
|
||||
@ -68,12 +68,14 @@ public class ApkCache {
|
||||
|
||||
/**
|
||||
* Copy an APK from {@param apkFile} to our internal files directory for 20 minutes.
|
||||
*
|
||||
* @param verifyHash If the file was just downloaded, then you should mark this as true and
|
||||
* request the file to be verified once it has finished copying. Otherwise,
|
||||
* if the app was installed from part of the system where it can't be tampered
|
||||
* with (e.g. installed apks on disk) then
|
||||
*/
|
||||
private static SanitizedFile copyApkToFiles(Context context, File apkFile, String destinationName, boolean verifyHash, String hash, String hashType)
|
||||
private static SanitizedFile copyApkToFiles(Context context, File apkFile, String destinationName,
|
||||
boolean verifyHash, String hash, String hashType)
|
||||
throws IOException {
|
||||
SanitizedFile sanitizedApkFile = new SanitizedFile(context.getFilesDir(), destinationName);
|
||||
|
||||
|
@ -24,7 +24,6 @@ import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
|
||||
import org.acra.ACRA;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
@ -54,7 +53,8 @@ class ApkSignatureVerifier {
|
||||
public boolean hasFDroidSignature(File apkFile) {
|
||||
if (!apkFile.exists()) {
|
||||
ACRA.getErrorReporter().handleException(
|
||||
new Exception("Failed to install Privileged Extension, because " + apkFile.getAbsolutePath() + " does not exist."),
|
||||
new Exception("Failed to install Privileged Extension, because " + apkFile.getAbsolutePath()
|
||||
+ " does not exist."),
|
||||
false
|
||||
);
|
||||
|
||||
@ -77,7 +77,8 @@ class ApkSignatureVerifier {
|
||||
private byte[] getApkSignature(File apkFile) {
|
||||
final String pkgPath = apkFile.getAbsolutePath();
|
||||
if (!apkFile.exists()) {
|
||||
throw new IllegalArgumentException("Could not find APK at \"" + pkgPath + "\" when checking for signature.");
|
||||
throw new IllegalArgumentException("Could not find APK at \"" + pkgPath
|
||||
+ "\" when checking for signature.");
|
||||
}
|
||||
|
||||
PackageInfo pkgInfo = pm.getPackageArchiveInfo(pkgPath, PackageManager.GET_SIGNATURES);
|
||||
|
@ -30,7 +30,6 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
|
||||
@ -40,8 +39,10 @@ import org.fdroid.fdroid.data.Apk;
|
||||
public class DefaultInstallerActivity extends FragmentActivity {
|
||||
private static final String TAG = "DefaultInstallerActivit";
|
||||
|
||||
static final String ACTION_INSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.INSTALL_PACKAGE";
|
||||
static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.UNINSTALL_PACKAGE";
|
||||
static final String ACTION_INSTALL_PACKAGE
|
||||
= "org.fdroid.fdroid.installer.DefaultInstaller.action.INSTALL_PACKAGE";
|
||||
static final String ACTION_UNINSTALL_PACKAGE
|
||||
= "org.fdroid.fdroid.installer.DefaultInstaller.action.UNINSTALL_PACKAGE";
|
||||
|
||||
private static final int REQUEST_CODE_INSTALL = 0;
|
||||
private static final int REQUEST_CODE_UNINSTALL = 1;
|
||||
|
@ -62,6 +62,7 @@ import java.io.IOException;
|
||||
*
|
||||
* @see <a href="https://developer.android.com/google/play/expansion-files.html">APK Expansion Files</a>
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class InstallManagerService extends Service {
|
||||
private static final String TAG = "InstallManagerService";
|
||||
|
||||
|
@ -45,6 +45,7 @@ import java.io.IOException;
|
||||
/**
|
||||
* Handles the actual install process. Subclasses implement the details.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public abstract class Installer {
|
||||
private static final String TAG = "Installer";
|
||||
|
||||
|
@ -66,8 +66,10 @@ public class PrivilegedInstaller extends Installer {
|
||||
|
||||
private static final String TAG = "PrivilegedInstaller";
|
||||
|
||||
private static final String PRIVILEGED_EXTENSION_SERVICE_INTENT = "org.fdroid.fdroid.privileged.IPrivilegedService";
|
||||
public static final String PRIVILEGED_EXTENSION_PACKAGE_NAME = "org.fdroid.fdroid.privileged";
|
||||
private static final String PRIVILEGED_EXTENSION_SERVICE_INTENT
|
||||
= "org.fdroid.fdroid.privileged.IPrivilegedService";
|
||||
public static final String PRIVILEGED_EXTENSION_PACKAGE_NAME
|
||||
= "org.fdroid.fdroid.privileged";
|
||||
|
||||
public static final int IS_EXTENSION_INSTALLED_NO = 0;
|
||||
public static final int IS_EXTENSION_INSTALLED_YES = 1;
|
||||
|
@ -54,6 +54,7 @@ import kellinwood.security.zipsigner.ZipSigner;
|
||||
|
||||
// TODO Address exception handling in a uniform way throughout
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public final class LocalRepoKeyStore {
|
||||
|
||||
private static final String TAG = "LocalRepoKeyStore";
|
||||
|
@ -54,6 +54,7 @@ import java.util.jar.JarOutputStream;
|
||||
* This class deals specifically with the webroot side of things, ensuring we have a valid index.jar
|
||||
* and the relevant .apk and icon files available.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public final class LocalRepoManager {
|
||||
private static final String TAG = "LocalRepoManager";
|
||||
|
||||
|
@ -65,6 +65,7 @@ import rx.schedulers.Schedulers;
|
||||
* Central service which manages all of the different moving parts of swap which are required
|
||||
* to enable p2p swapping of apps.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class SwapService extends Service {
|
||||
|
||||
private static final String TAG = "SwapService";
|
||||
|
@ -16,6 +16,7 @@ import rx.Subscriber;
|
||||
import rx.functions.Action0;
|
||||
import rx.subscriptions.Subscriptions;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
final class BluetoothFinder extends PeerFinder {
|
||||
|
||||
public static Observable<Peer> createBluetoothObservable(final Context context) {
|
||||
|
@ -31,7 +31,9 @@ public class BluetoothPeer implements Peer {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object peer) {
|
||||
return peer != null && peer instanceof BluetoothPeer && ((BluetoothPeer) peer).device.getAddress().equals(device.getAddress());
|
||||
return peer != null
|
||||
&& peer instanceof BluetoothPeer
|
||||
&& ((BluetoothPeer) peer).device.getAddress().equals(device.getAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,7 @@ import rx.Subscriber;
|
||||
import rx.functions.Action0;
|
||||
import rx.subscriptions.Subscriptions;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
final class BonjourFinder extends PeerFinder implements ServiceListener {
|
||||
|
||||
public static Observable<Peer> createBonjourObservable(final Context context) {
|
||||
|
@ -13,6 +13,7 @@ import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothServer;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public final class BluetoothSwap extends SwapType {
|
||||
|
||||
private static final String TAG = "BluetoothSwap";
|
||||
|
@ -3,20 +3,18 @@ package org.fdroid.fdroid.localrepo.type;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
|
||||
import javax.jmdns.JmDNS;
|
||||
import javax.jmdns.ServiceInfo;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.jmdns.JmDNS;
|
||||
import javax.jmdns.ServiceInfo;
|
||||
|
||||
/**
|
||||
* Sends a {@link SwapService#BONJOUR_STATE_CHANGE} broadcasts when starting, started or stopped.
|
||||
*/
|
||||
@ -38,7 +36,8 @@ public class BonjourBroadcast extends SwapType {
|
||||
|
||||
InetAddress address = getDeviceAddress();
|
||||
if (address == null) {
|
||||
Log.e(TAG, "Starting Bonjour service, but couldn't ascertain IP address. Seems we are not connected to a network.");
|
||||
Log.e(TAG, "Starting Bonjour service, but couldn't ascertain IP address."
|
||||
+ " Seems we are not connected to a network.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -103,7 +102,8 @@ public class BonjourBroadcast extends SwapType {
|
||||
if (FDroidApp.ipAddressString != null) {
|
||||
try {
|
||||
return InetAddress.getByName(FDroidApp.ipAddressString);
|
||||
} catch (UnknownHostException ignored) { }
|
||||
} catch (UnknownHostException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -26,6 +26,7 @@ import rx.functions.Action1;
|
||||
import rx.functions.Func2;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class WifiSwap extends SwapType {
|
||||
|
||||
private static final String TAG = "WifiSwap";
|
||||
|
@ -143,7 +143,8 @@ public abstract class Downloader {
|
||||
* keeping track of the number of bytes that have flowed through for the
|
||||
* progress counter.
|
||||
*/
|
||||
private void copyInputToOutputStream(InputStream input, int bufferSize, OutputStream output) throws IOException, InterruptedException {
|
||||
private void copyInputToOutputStream(InputStream input, int bufferSize, OutputStream output)
|
||||
throws IOException, InterruptedException {
|
||||
Timer timer = new Timer();
|
||||
try {
|
||||
bytesRead = 0;
|
||||
|
@ -131,13 +131,15 @@ public class DownloaderService extends Service {
|
||||
Utils.debugLog(TAG, "Cancelling download of " + uriString);
|
||||
Integer whatToRemove = uriString.hashCode();
|
||||
if (serviceHandler.hasMessages(whatToRemove)) {
|
||||
Utils.debugLog(TAG, "Removing download with ID of " + whatToRemove + " from service handler, then sending interrupted event.");
|
||||
Utils.debugLog(TAG, "Removing download with ID of " + whatToRemove
|
||||
+ " from service handler, then sending interrupted event.");
|
||||
serviceHandler.removeMessages(whatToRemove);
|
||||
sendBroadcast(intent.getData(), Downloader.ACTION_INTERRUPTED);
|
||||
} else if (isActive(uriString)) {
|
||||
downloader.cancelDownload();
|
||||
} else {
|
||||
Utils.debugLog(TAG, "ACTION_CANCEL called on something not queued or running (expected to find message with ID of " + whatToRemove + " in queue).");
|
||||
Utils.debugLog(TAG, "ACTION_CANCEL called on something not queued or running"
|
||||
+ " (expected to find message with ID of " + whatToRemove + " in queue).");
|
||||
}
|
||||
} else if (ACTION_QUEUE.equals(intent.getAction())) {
|
||||
Message msg = serviceHandler.obtainMessage();
|
||||
|
@ -93,7 +93,8 @@ public class LocalHTTPD extends NanoHTTPD {
|
||||
session.parseBody(new HashMap<String, String>());
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "An error occured while parsing the POST body", e);
|
||||
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "Internal server error, check logcat on server for details.");
|
||||
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT,
|
||||
"Internal server error, check logcat on server for details.");
|
||||
} catch (ResponseException re) {
|
||||
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
|
||||
}
|
||||
@ -108,8 +109,10 @@ public class LocalHTTPD extends NanoHTTPD {
|
||||
switch (uri.getPath()) {
|
||||
case "/request-swap":
|
||||
if (!session.getParms().containsKey("repo")) {
|
||||
Log.e(TAG, "Malformed /request-swap request to local repo HTTP server. Should have posted a 'repo' parameter.");
|
||||
return new Response(Response.Status.BAD_REQUEST, MIME_PLAINTEXT, "Requires 'repo' parameter to be posted.");
|
||||
Log.e(TAG, "Malformed /request-swap request to local repo HTTP server."
|
||||
+ " Should have posted a 'repo' parameter.");
|
||||
return new Response(Response.Status.BAD_REQUEST, MIME_PLAINTEXT,
|
||||
"Requires 'repo' parameter to be posted.");
|
||||
}
|
||||
requestSwap(session.getParms().get("repo"));
|
||||
return new Response(Response.Status.OK, MIME_PLAINTEXT, "Swap request received.");
|
||||
|
@ -41,6 +41,7 @@ import java.util.Locale;
|
||||
* changed. Having the {@code Thread} also makes it easy to kill work
|
||||
* that is in progress.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class WifiStateChangeService extends IntentService {
|
||||
private static final String TAG = "WifiStateChangeService";
|
||||
|
||||
|
@ -39,7 +39,7 @@ public class BluetoothClient {
|
||||
throw e1;
|
||||
|
||||
/*
|
||||
Log.e(TAG, "There was an error while establishing Bluetooth connection. Falling back to using reflection...");
|
||||
Log.e(TAG, "There was an error while establishing Bluetooth connection. Falling back to reflection");
|
||||
Class<?> clazz = socket.getRemoteDevice().getClass();
|
||||
Class<?>[] paramTypes = new Class<?>[]{Integer.TYPE};
|
||||
|
||||
|
@ -26,6 +26,7 @@ import fi.iki.elonen.NanoHTTPD;
|
||||
* Act as a layer on top of LocalHTTPD server, by forwarding requests served
|
||||
* over bluetooth to that server.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class BluetoothServer extends Thread {
|
||||
|
||||
private static final String TAG = "BluetoothServer";
|
||||
|
@ -18,7 +18,7 @@ public final class Request {
|
||||
|
||||
public interface Methods {
|
||||
String HEAD = "HEAD";
|
||||
String GET = "GET";
|
||||
String GET = "GET";
|
||||
}
|
||||
|
||||
private String method;
|
||||
@ -73,10 +73,12 @@ public final class Request {
|
||||
Utils.debugLog(TAG, "Read " + headers.size() + " headers");
|
||||
|
||||
if (method.equals(Methods.HEAD)) {
|
||||
Utils.debugLog(TAG, "Request was a " + Methods.HEAD + " request, not including anything other than headers and status...");
|
||||
Utils.debugLog(TAG, "Request was a " + Methods.HEAD
|
||||
+ " request, not including anything other than headers and status...");
|
||||
return new Response(responseCode, headers);
|
||||
}
|
||||
Utils.debugLog(TAG, "Request was a " + Methods.GET + " request, so including content stream in response...");
|
||||
Utils.debugLog(TAG, "Request was a " + Methods.GET
|
||||
+ " request, so including content stream in response...");
|
||||
return new Response(responseCode, headers, connection.getInputStream());
|
||||
}
|
||||
|
||||
@ -102,8 +104,8 @@ public final class Request {
|
||||
return false;
|
||||
}
|
||||
|
||||
method = parts[0].toUpperCase(Locale.ENGLISH);
|
||||
path = parts[1];
|
||||
method = parts[0].toUpperCase(Locale.ENGLISH);
|
||||
path = parts[1];
|
||||
headers = readHeaders();
|
||||
return true;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package org.fdroid.fdroid.net.bluetooth.httpish;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothConnection;
|
||||
import org.fdroid.fdroid.net.bluetooth.FileDetails;
|
||||
@ -99,7 +98,8 @@ public class Response {
|
||||
|
||||
public InputStream toContentStream() throws UnsupportedOperationException {
|
||||
if (contentStream == null) {
|
||||
throw new UnsupportedOperationException("This kind of response doesn't have a content stream. Did you perform a HEAD request instead of a GET request?");
|
||||
throw new UnsupportedOperationException("This kind of response doesn't have a content stream."
|
||||
+ " Did you perform a HEAD request instead of a GET request?");
|
||||
}
|
||||
return contentStream;
|
||||
}
|
||||
@ -136,7 +136,8 @@ public class Response {
|
||||
private int fileSize = -1;
|
||||
private String etag;
|
||||
|
||||
public Builder() { }
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
public Builder(InputStream contentStream) {
|
||||
this.contentStream = contentStream;
|
||||
|
@ -37,6 +37,7 @@ import eu.chainfire.libsuperuser.Shell;
|
||||
* http://omerjerk.in/2014/08/how-to-install-an-app-to-system-partition/
|
||||
* https://github.com/omerjerk/RemoteDroid/blob/master/app/src/main/java/in/omerjerk/remotedroid/app/MainActivity.java
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
abstract class InstallExtension {
|
||||
|
||||
final Context context;
|
||||
|
@ -42,10 +42,9 @@ import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.Preferences.Theme;
|
||||
import org.fdroid.fdroid.R;
|
||||
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
@ -70,9 +69,9 @@ import java.util.Set;
|
||||
* Based on AOSP core/java/android/widget/AppSecurityPermissions
|
||||
* latest included commit: a3f68ef2f6811cf72f1282214c0883db5a30901d
|
||||
* <p/>
|
||||
* To update this file:
|
||||
* - Open https://github.com/android/platform_frameworks_base/commits/master/core/java/android/widget/AppSecurityPermissions.java
|
||||
* - Start from latest included commit and include changes until the newest commit with care
|
||||
* To update this file, Start from latest included commit and include changes
|
||||
* until the newest commit with care:
|
||||
* github.com/android/platform_frameworks_base/blob/master/core/java/android/widget/AppSecurityPermissions.java
|
||||
*/
|
||||
public class AppSecurityPermissions {
|
||||
|
||||
@ -92,6 +91,7 @@ public class AppSecurityPermissions {
|
||||
|
||||
// PermissionGroupInfo implements Parcelable but its Parcel constructor is private and thus cannot be extended.
|
||||
@SuppressLint("ParcelCreator")
|
||||
@SuppressWarnings("LineLength")
|
||||
static class MyPermissionGroupInfo extends PermissionGroupInfo {
|
||||
CharSequence label;
|
||||
|
||||
@ -402,8 +402,8 @@ public class AppSecurityPermissions {
|
||||
}
|
||||
}
|
||||
|
||||
private PermissionItemView getPermissionItemView(MyPermissionGroupInfo grp,
|
||||
MyPermissionInfo perm, boolean first, CharSequence newPermPrefix) {
|
||||
private PermissionItemView getPermissionItemView(MyPermissionGroupInfo grp, MyPermissionInfo perm,
|
||||
boolean first, CharSequence newPermPrefix) {
|
||||
PermissionItemView permView = (PermissionItemView) inflater.inflate(
|
||||
Build.VERSION.SDK_INT >= 17 &&
|
||||
(perm.flags & PermissionInfo.FLAG_COSTS_MONEY) != 0
|
||||
|
@ -36,11 +36,9 @@ import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TabHost;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
@ -119,7 +117,8 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
|
||||
scrollView.addView(perms.getPermissionsView(
|
||||
AppSecurityPermissions.WHICH_NEW));
|
||||
} else {
|
||||
throw new RuntimeException("This should not happen. No new permissions were found but InstallConfirmActivity has been started!");
|
||||
throw new RuntimeException("This should not happen. No new permissions were found"
|
||||
+ " but InstallConfirmActivity has been started!");
|
||||
}
|
||||
adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator(
|
||||
getText(R.string.newPerms)), scrollView);
|
||||
@ -191,7 +190,8 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
|
||||
intent = getIntent();
|
||||
Uri uri = intent.getData();
|
||||
Apk apk = ApkProvider.Helper.findByUri(this, uri, Schema.ApkTable.Cols.ALL);
|
||||
app = AppProvider.Helper.findSpecificApp(getContentResolver(), apk.packageName, apk.repoId, Schema.AppMetadataTable.Cols.ALL);
|
||||
app = AppProvider.Helper.findSpecificApp(getContentResolver(),
|
||||
apk.packageName, apk.repoId, Schema.AppMetadataTable.Cols.ALL);
|
||||
|
||||
appDiff = new AppDiff(getPackageManager(), apk);
|
||||
|
||||
|
@ -53,6 +53,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class AppDetailsRecyclerViewAdapter
|
||||
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
|
@ -8,7 +8,6 @@ import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.UpdateService;
|
||||
|
||||
@ -53,7 +52,8 @@ public class BannerUpdatingRepos extends android.support.v7.widget.AppCompatText
|
||||
return;
|
||||
}
|
||||
|
||||
LocalBroadcastManager.getInstance(getContext()).registerReceiver(onRepoFeedback, new IntentFilter(UpdateService.LOCAL_ACTION_STATUS));
|
||||
LocalBroadcastManager.getInstance(getContext()).registerReceiver(onRepoFeedback,
|
||||
new IntentFilter(UpdateService.LOCAL_ACTION_STATUS));
|
||||
setBannerIsVisible(UpdateService.isUpdating());
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import android.support.v7.widget.OrientationHelper;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class LinearLayoutManagerSnapHelper extends LinearSnapHelper {
|
||||
|
||||
private View lastSavedTarget;
|
||||
|
@ -50,7 +50,6 @@ import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.UpdateService;
|
||||
@ -70,6 +69,7 @@ import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class ManageReposActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>, RepoAdapter.EnabledListener {
|
||||
private static final String TAG = "ManageReposActivity";
|
||||
|
||||
@ -191,9 +191,9 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
* Utility class to encapsulate the process of adding a new repo (or an existing one,
|
||||
* depending on if the incoming address is the same as a previous repo). It is responsible
|
||||
* for managing the lifecycle of adding a repo:
|
||||
* * Showing the add dialog
|
||||
* * Deciding whether to add a new repo or update an existing one
|
||||
* * Search for repos at common suffixes (/, /fdroid/repo, /repo)
|
||||
* <li>Showing the add dialog
|
||||
* <li>Deciding whether to add a new repo or update an existing one
|
||||
* <li>Search for repos at common suffixes (/, /fdroid/repo, /repo)
|
||||
*/
|
||||
private class AddRepo {
|
||||
|
||||
@ -314,10 +314,12 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
final TextWatcher textChangedListener = new TextWatcher() {
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) { }
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
@ -557,7 +559,7 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
* Some basic sanitization of URLs, so that two URLs which have the same semantic meaning
|
||||
* are represented by the exact same string by F-Droid. This will help to make sure that,
|
||||
* e.g. "http://10.0.1.50" and "http://10.0.1.50/" are not two different repositories.
|
||||
*
|
||||
* <p>
|
||||
* Currently it normalizes the path so that "/./" are removed and "test/../" is collapsed.
|
||||
* This is done using {@link URI#normalize()}. It also removes multiple consecutive forward
|
||||
* slashes in the path and replaces them with one. Finally, it removes trailing slashes.
|
||||
|
@ -406,7 +406,8 @@ public class RepoDetailsActivity extends ActionBarActivity {
|
||||
|
||||
} else {
|
||||
|
||||
Toast.makeText(RepoDetailsActivity.this, R.string.repo_error_empty_username, Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(RepoDetailsActivity.this, R.string.repo_error_empty_username,
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.fdroid.fdroid.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
@ -16,7 +17,8 @@ import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
|
||||
public class ScreenShotsRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements LinearLayoutManagerSnapHelper.LinearSnapHelperListener {
|
||||
public class ScreenShotsRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||
implements LinearLayoutManagerSnapHelper.LinearSnapHelperListener {
|
||||
private final String[] screenshots;
|
||||
private final DisplayImageOptions displayImageOptions;
|
||||
private View selectedView;
|
||||
@ -28,8 +30,9 @@ public class ScreenShotsRecyclerViewAdapter extends RecyclerView.Adapter<Recycle
|
||||
super();
|
||||
screenshots = app.getAllScreenshots(context);
|
||||
selectedPosition = 0;
|
||||
selectedItemElevation = context.getResources().getDimensionPixelSize(R.dimen.details_screenshot_selected_elevation);
|
||||
unselectedItemMargin = context.getResources().getDimensionPixelSize(R.dimen.details_screenshot_margin);
|
||||
Resources r = context.getResources();
|
||||
selectedItemElevation = r.getDimensionPixelSize(R.dimen.details_screenshot_selected_elevation);
|
||||
unselectedItemMargin = r.getDimensionPixelSize(R.dimen.details_screenshot_margin);
|
||||
displayImageOptions = new DisplayImageOptions.Builder()
|
||||
.cacheInMemory(true)
|
||||
.cacheOnDisk(true)
|
||||
|
@ -20,7 +20,6 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
@ -156,7 +155,9 @@ public class ShareChooserDialog extends BottomSheetDialogFragment {
|
||||
|
||||
@Override
|
||||
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate((viewType == 1) ? R.layout.share_header_item : R.layout.share_item, parent, false);
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate((viewType == 1)
|
||||
? R.layout.share_header_item
|
||||
: R.layout.share_item, parent, false);
|
||||
return new VH(view);
|
||||
}
|
||||
|
||||
@ -200,7 +201,11 @@ public class ShareChooserDialog extends BottomSheetDialogFragment {
|
||||
|
||||
}
|
||||
|
||||
public static void createChooser(CoordinatorLayout rootView, ShareChooserDialog.ShareChooserDialogListener listener, final AppCompatActivity parent, final Intent shareIntent, boolean showNearbyItem) {
|
||||
public static void createChooser(CoordinatorLayout rootView,
|
||||
ShareChooserDialog.ShareChooserDialogListener listener,
|
||||
final AppCompatActivity parent,
|
||||
final Intent shareIntent,
|
||||
boolean showNearbyItem) {
|
||||
ShareChooserDialog d = new ShareChooserDialog();
|
||||
d.setListener(listener);
|
||||
Bundle args = new Bundle();
|
||||
|
@ -17,16 +17,18 @@ import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.Schema;
|
||||
|
||||
public class AppListActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>, CategoryTextWatcher.SearchTermsChangedListener {
|
||||
public class AppListActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>,
|
||||
CategoryTextWatcher.SearchTermsChangedListener {
|
||||
|
||||
public static final String EXTRA_CATEGORY = "org.fdroid.fdroid.views.apps.AppListActivity.EXTRA_CATEGORY";
|
||||
public static final String EXTRA_SEARCH_TERMS = "org.fdroid.fdroid.views.apps.AppListActivity.EXTRA_SEARCH_TERMS";
|
||||
public static final String EXTRA_CATEGORY
|
||||
= "org.fdroid.fdroid.views.apps.AppListActivity.EXTRA_CATEGORY";
|
||||
public static final String EXTRA_SEARCH_TERMS
|
||||
= "org.fdroid.fdroid.views.apps.AppListActivity.EXTRA_SEARCH_TERMS";
|
||||
|
||||
private RecyclerView appView;
|
||||
private AppListAdapter appAdapter;
|
||||
|
@ -4,7 +4,6 @@ import android.app.Activity;
|
||||
import android.database.Cursor;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
|
||||
@ -26,7 +25,8 @@ class AppListAdapter extends RecyclerView.Adapter<AppListItemController> {
|
||||
|
||||
@Override
|
||||
public AppListItemController onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new AppListItemController(activity, activity.getLayoutInflater().inflate(R.layout.app_list_item, parent, false));
|
||||
return new AppListItemController(activity, activity.getLayoutInflater()
|
||||
.inflate(R.layout.app_list_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,6 +46,7 @@ import java.io.File;
|
||||
import java.util.Iterator;
|
||||
|
||||
// TODO: Support cancelling of downloads by tapping the install button a second time.
|
||||
@SuppressWarnings("LineLength")
|
||||
public class AppListItemController extends RecyclerView.ViewHolder {
|
||||
|
||||
private static final String TAG = "AppListItemController";
|
||||
|
@ -10,7 +10,6 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.style.ReplacementSpan;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.views.categories.CategoryController;
|
||||
|
||||
@ -74,7 +73,8 @@ public class CategorySpan extends ReplacementSpan {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
|
||||
public void draw(@NonNull Canvas canvas, CharSequence text,
|
||||
int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
|
||||
CharSequence categoryName = getCategoryName(text, start, end);
|
||||
if (categoryName == null) {
|
||||
return;
|
||||
@ -94,7 +94,8 @@ public class CategorySpan extends ReplacementSpan {
|
||||
canvas.save();
|
||||
canvas.translate(x, bottom - height + TEXT_BELOW_PADDING * density);
|
||||
|
||||
RectF backgroundRect = new RectF(0, 0, iconBackgroundSize + textLeadingPadding + textWidth + textTrailingPadding, height);
|
||||
RectF backgroundRect = new RectF(0, 0, iconBackgroundSize + textLeadingPadding
|
||||
+ textWidth + textTrailingPadding, height);
|
||||
|
||||
// The shadow below the entire category chip.
|
||||
canvas.save();
|
||||
|
@ -10,17 +10,16 @@ import android.text.Spanned;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.style.TtsSpan;
|
||||
import android.widget.EditText;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
|
||||
/**
|
||||
* The search input treats text before the first colon as a category name. Text after this colon
|
||||
* (or all text if there is no colon) is the free text search terms.
|
||||
* The behaviour of this search input is:
|
||||
* * Replacing anything before the first colon with a {@link CategorySpan} that renders a "Chip"
|
||||
* including an icon representing "category" and the name of the category.
|
||||
* * Removing the trailing ":" from a category chip will cause it to remove the entire category
|
||||
* from the input.
|
||||
* * Replacing anything before the first colon with a {@link CategorySpan} that renders a "Chip"
|
||||
* including an icon representing "category" and the name of the category.
|
||||
* * Removing the trailing ":" from a category chip will cause it to remove the entire category
|
||||
* from the input.
|
||||
*/
|
||||
public class CategoryTextWatcher implements TextWatcher {
|
||||
|
||||
@ -35,7 +34,8 @@ public class CategoryTextWatcher implements TextWatcher {
|
||||
private int removeTo = -1;
|
||||
private boolean requiresSpanRecalculation = false;
|
||||
|
||||
public CategoryTextWatcher(final Context context, final EditText widget, final SearchTermsChangedListener listener) {
|
||||
public CategoryTextWatcher(final Context context, final EditText widget,
|
||||
final SearchTermsChangedListener listener) {
|
||||
this.context = context;
|
||||
this.widget = widget;
|
||||
this.listener = listener;
|
||||
@ -75,8 +75,10 @@ public class CategoryTextWatcher implements TextWatcher {
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
boolean addingOrReplacing = count > 0;
|
||||
boolean addingColon = addingOrReplacing && s.subSequence(start, start + count).toString().indexOf(':') >= 0;
|
||||
boolean addingFirstColon = addingColon && s.subSequence(0, start).toString().indexOf(':') == -1;
|
||||
boolean addingColon = addingOrReplacing
|
||||
&& s.subSequence(start, start + count).toString().indexOf(':') >= 0;
|
||||
boolean addingFirstColon = addingColon
|
||||
&& s.subSequence(0, start).toString().indexOf(':') == -1;
|
||||
if (addingFirstColon) {
|
||||
requiresSpanRecalculation = true;
|
||||
}
|
||||
@ -99,7 +101,8 @@ public class CategoryTextWatcher implements TextWatcher {
|
||||
|
||||
int colonIndex = searchText.toString().indexOf(':');
|
||||
String category = colonIndex == -1 ? null : searchText.subSequence(0, colonIndex).toString();
|
||||
String searchTerms = searchText.subSequence(colonIndex == -1 ? 0 : colonIndex + 1, searchText.length()).toString();
|
||||
String searchTerms = searchText.subSequence(colonIndex == -1 ? 0 : colonIndex + 1,
|
||||
searchText.length()).toString();
|
||||
listener.onSearchTermsChanged(category, searchTerms);
|
||||
}
|
||||
|
||||
@ -140,7 +143,8 @@ public class CategoryTextWatcher implements TextWatcher {
|
||||
// For accessibility reasons, make this more clear to screen readers that the
|
||||
// span we just added semantically represents a category.
|
||||
CharSequence categoryName = textToSpannify.subSequence(0, colonIndex);
|
||||
TtsSpan ttsSpan = new TtsSpan.TextBuilder(context.getString(R.string.tts_category_name, categoryName)).build();
|
||||
TtsSpan ttsSpan = new TtsSpan.TextBuilder(context.getString(R.string.tts_category_name,
|
||||
categoryName)).build();
|
||||
textToSpannify.setSpan(ttsSpan, 0, 0, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ import java.util.Random;
|
||||
*
|
||||
* It is suggested that you obtain the Palette from the icon of an app.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class FeatureImage extends AppCompatImageView {
|
||||
|
||||
private static final int NUM_SQUARES_WIDE = 4;
|
||||
|
@ -18,12 +18,10 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||
|
||||
import org.fdroid.fdroid.AppDetails2;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
@ -33,12 +31,13 @@ import org.fdroid.fdroid.views.apps.FeatureImage;
|
||||
/**
|
||||
* The {@link AppCardController} can bind an app to several different layouts, as long as the layout
|
||||
* contains the following elements:
|
||||
* + {@link R.id#icon} ({@link ImageView}, required)
|
||||
* + {@link R.id#summary} ({@link TextView}, required)
|
||||
* + {@link R.id#new_tag} ({@link TextView}, optional)
|
||||
* + {@link R.id#featured_image} ({@link ImageView}, optional)
|
||||
* + {@link R.id#icon} ({@link ImageView}, required)
|
||||
* + {@link R.id#summary} ({@link TextView}, required)
|
||||
* + {@link R.id#new_tag} ({@link TextView}, optional)
|
||||
* + {@link R.id#featured_image} ({@link ImageView}, optional)
|
||||
*/
|
||||
public class AppCardController extends RecyclerView.ViewHolder implements ImageLoadingListener, View.OnClickListener {
|
||||
public class AppCardController extends RecyclerView.ViewHolder
|
||||
implements ImageLoadingListener, View.OnClickListener {
|
||||
|
||||
/**
|
||||
* After this many days, don't consider showing the "New" tag next to an app.
|
||||
@ -124,7 +123,8 @@ public class AppCardController extends RecyclerView.ViewHolder implements ImageL
|
||||
featuredImage.setColour(ContextCompat.getColor(activity, R.color.fdroid_blue));
|
||||
featuredImage.setImageDrawable(null);
|
||||
|
||||
// Note: We could call the convenience function loadImageAndDisplay(ImageLoader, DisplayImageOptions, String, String)
|
||||
// Note: We could call the convenience function
|
||||
// loadImageAndDisplay(ImageLoader, DisplayImageOptions, String, String)
|
||||
// which includes a fallback for when currentApp.featureGraphic is empty. However we need
|
||||
// to take care of also loading the icon (regardless of whether there is a featureGraphic
|
||||
// or not for this app) so that we can display the icon to the user. We will use the
|
||||
@ -132,7 +132,8 @@ public class AppCardController extends RecyclerView.ViewHolder implements ImageL
|
||||
// from that icon and assign to the `FeatureImage` (or whether we should wait for the
|
||||
// feature image to be loaded).
|
||||
if (!TextUtils.isEmpty(app.featureGraphic)) {
|
||||
featuredImage.loadImageAndDisplay(ImageLoader.getInstance(), displayImageOptions, app.featureGraphic);
|
||||
featuredImage.loadImageAndDisplay(ImageLoader.getInstance(),
|
||||
displayImageOptions, app.featureGraphic);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,12 +159,12 @@ public class AppCardController extends RecyclerView.ViewHolder implements ImageL
|
||||
Intent intent = new Intent(activity, AppDetails2.class);
|
||||
intent.putExtra(AppDetails2.EXTRA_APPID, currentApp.packageName);
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
Pair<View, String> iconTransitionPair = Pair.create((View) icon, activity.getString(R.string.transition_app_item_icon));
|
||||
Pair<View, String> iconTransitionPair = Pair.create((View) icon,
|
||||
activity.getString(R.string.transition_app_item_icon));
|
||||
|
||||
@SuppressWarnings("unchecked") // We are passing the right type as the second varargs argument (i.e. a Pair<View, String>).
|
||||
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, iconTransitionPair).toBundle();
|
||||
|
||||
activity.startActivity(intent, bundle);
|
||||
@SuppressWarnings("unchecked") // the right type is passed as 2nd varargs arg: Pair<View, String>
|
||||
Bundle b = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, iconTransitionPair).toBundle();
|
||||
activity.startActivity(intent, b);
|
||||
} else {
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
@ -180,7 +181,10 @@ public class AppCardController extends RecyclerView.ViewHolder implements ImageL
|
||||
|
||||
@Override
|
||||
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
||||
if (currentApp != null && TextUtils.isEmpty(currentApp.featureGraphic) && featuredImage != null && loadedImage != null) {
|
||||
if (currentApp != null
|
||||
&& TextUtils.isEmpty(currentApp.featureGraphic)
|
||||
&& featuredImage != null
|
||||
&& loadedImage != null) {
|
||||
new Palette.Builder(loadedImage).generate(new Palette.PaletteAsyncListener() {
|
||||
@Override
|
||||
public void onGenerated(Palette palette) {
|
||||
|
@ -4,7 +4,6 @@ import android.app.Activity;
|
||||
import android.database.Cursor;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
|
||||
@ -19,7 +18,8 @@ class AppPreviewAdapter extends RecyclerView.Adapter<AppCardController> {
|
||||
|
||||
@Override
|
||||
public AppCardController onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new AppCardController(activity, activity.getLayoutInflater().inflate(R.layout.app_card_normal, parent, false));
|
||||
return new AppCardController(activity, activity.getLayoutInflater()
|
||||
.inflate(R.layout.app_card_normal, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,7 +5,6 @@ import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
|
||||
import java.util.Collections;
|
||||
@ -26,7 +25,8 @@ public class CategoryAdapter extends RecyclerView.Adapter<CategoryController> {
|
||||
|
||||
@Override
|
||||
public CategoryController onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new CategoryController(activity, loaderManager, activity.getLayoutInflater().inflate(R.layout.category_item, parent, false));
|
||||
return new CategoryController(activity, loaderManager, activity.getLayoutInflater()
|
||||
.inflate(R.layout.category_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,8 +1,9 @@
|
||||
package org.fdroid.fdroid.views.categories;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
@ -20,12 +21,10 @@ import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
||||
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.Schema;
|
||||
@ -106,12 +105,13 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade
|
||||
}
|
||||
|
||||
/**
|
||||
* @param requiresLowerCaseId Previously categories were translated using strings such as "category_Reading" for
|
||||
* the "Reading" category. Now we also need to have drawable resources such as
|
||||
* @param requiresLowerCaseId Previously categories were translated using strings such as "category_Reading"
|
||||
* for the "Reading" category. Now we also need to have drawable resources such as
|
||||
* "category_reading". Note how drawables must have only lower case letters, whereas
|
||||
* we already have upper case letters in strings.xml. Hence this flag.
|
||||
*/
|
||||
private static int getCategoryResource(Context context, @NonNull String categoryName, String resourceType, boolean requiresLowerCaseId) {
|
||||
private static int getCategoryResource(Context context, @NonNull String categoryName, String resourceType,
|
||||
boolean requiresLowerCaseId) {
|
||||
String suffix = categoryName.replace(" & ", "_").replace(" ", "_").replace("'", "");
|
||||
if (requiresLowerCaseId) {
|
||||
suffix = suffix.toLowerCase(Locale.ENGLISH);
|
||||
@ -178,8 +178,11 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade
|
||||
cursor.moveToFirst();
|
||||
int numAppsInCategory = cursor.getInt(0);
|
||||
viewAll.setVisibility(View.VISIBLE);
|
||||
viewAll.setText(activity.getResources().getQuantityString(R.plurals.button_view_all_apps_in_category, numAppsInCategory, numAppsInCategory));
|
||||
viewAll.setContentDescription(activity.getResources().getQuantityString(R.plurals.tts_view_all_in_category, numAppsInCategory, numAppsInCategory, currentCategory));
|
||||
Resources r = activity.getResources();
|
||||
viewAll.setText(r.getQuantityString(R.plurals.button_view_all_apps_in_category, numAppsInCategory,
|
||||
numAppsInCategory));
|
||||
viewAll.setContentDescription(r.getQuantityString(R.plurals.tts_view_all_in_category, numAppsInCategory,
|
||||
numAppsInCategory, currentCategory));
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,6 +208,7 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade
|
||||
/**
|
||||
* Applies excessive padding to the start of the first item. This is so that the category artwork
|
||||
* can peek out and make itself visible. This is RTL friendly.
|
||||
*
|
||||
* @see org.fdroid.fdroid.R.dimen#category_preview__app_list__padding__horizontal
|
||||
* @see org.fdroid.fdroid.R.dimen#category_preview__app_list__padding__horizontal__first
|
||||
*/
|
||||
@ -217,8 +221,10 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
int horizontalPadding = (int) context.getResources().getDimension(R.dimen.category_preview__app_list__padding__horizontal);
|
||||
int horizontalPaddingFirst = (int) context.getResources().getDimension(R.dimen.category_preview__app_list__padding__horizontal__first);
|
||||
Resources r = context.getResources();
|
||||
int horizontalPadding = (int) r.getDimension(R.dimen.category_preview__app_list__padding__horizontal);
|
||||
int horizontalPaddingFirst = (int) r.getDimension(
|
||||
R.dimen.category_preview__app_list__padding__horizontal__first);
|
||||
boolean isLtr = ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_LTR;
|
||||
int itemPosition = parent.getChildLayoutPosition(view);
|
||||
boolean first = itemPosition == 0;
|
||||
|
@ -30,22 +30,22 @@ public class PreferencesFragment extends PreferenceFragment
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private static final String[] SUMMARIES_TO_UPDATE = {
|
||||
Preferences.PREF_UPD_INTERVAL,
|
||||
Preferences.PREF_UPD_WIFI_ONLY,
|
||||
Preferences.PREF_UPD_NOTIFY,
|
||||
Preferences.PREF_ROOTED,
|
||||
Preferences.PREF_HIDE_ANTI_FEATURE_APPS,
|
||||
Preferences.PREF_INCOMP_VER,
|
||||
Preferences.PREF_THEME,
|
||||
Preferences.PREF_IGN_TOUCH,
|
||||
Preferences.PREF_LOCAL_REPO_NAME,
|
||||
Preferences.PREF_LANGUAGE,
|
||||
Preferences.PREF_KEEP_CACHE_TIME,
|
||||
Preferences.PREF_EXPERT,
|
||||
Preferences.PREF_PRIVILEGED_INSTALLER,
|
||||
Preferences.PREF_ENABLE_PROXY,
|
||||
Preferences.PREF_PROXY_HOST,
|
||||
Preferences.PREF_PROXY_PORT,
|
||||
Preferences.PREF_UPD_INTERVAL,
|
||||
Preferences.PREF_UPD_WIFI_ONLY,
|
||||
Preferences.PREF_UPD_NOTIFY,
|
||||
Preferences.PREF_ROOTED,
|
||||
Preferences.PREF_HIDE_ANTI_FEATURE_APPS,
|
||||
Preferences.PREF_INCOMP_VER,
|
||||
Preferences.PREF_THEME,
|
||||
Preferences.PREF_IGN_TOUCH,
|
||||
Preferences.PREF_LOCAL_REPO_NAME,
|
||||
Preferences.PREF_LANGUAGE,
|
||||
Preferences.PREF_KEEP_CACHE_TIME,
|
||||
Preferences.PREF_EXPERT,
|
||||
Preferences.PREF_PRIVILEGED_INSTALLER,
|
||||
Preferences.PREF_ENABLE_PROXY,
|
||||
Preferences.PREF_PROXY_HOST,
|
||||
Preferences.PREF_PROXY_PORT,
|
||||
};
|
||||
|
||||
private static final int REQUEST_INSTALL_ORBOT = 0x1234;
|
||||
@ -180,8 +180,10 @@ public class PreferencesFragment extends PreferenceFragment
|
||||
break;
|
||||
|
||||
case Preferences.PREF_PRIVILEGED_INSTALLER:
|
||||
// We may have removed this preference if it is not suitable to show the user. So lets check it is here first.
|
||||
final CheckBoxPreference pref = (CheckBoxPreference) findPreference(Preferences.PREF_PRIVILEGED_INSTALLER);
|
||||
// We may have removed this preference if it is not suitable to show the user.
|
||||
// So lets check it is here first.
|
||||
final CheckBoxPreference pref = (CheckBoxPreference) findPreference(
|
||||
Preferences.PREF_PRIVILEGED_INSTALLER);
|
||||
if (pref != null) {
|
||||
checkSummary(key, R.string.system_installer_on);
|
||||
}
|
||||
|
@ -12,15 +12,13 @@ import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.TextUtils;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
import com.ashokvarma.bottomnavigation.BadgeItem;
|
||||
import com.ashokvarma.bottomnavigation.BottomNavigationBar;
|
||||
import com.ashokvarma.bottomnavigation.BottomNavigationItem;
|
||||
|
||||
import org.fdroid.fdroid.AppDetails2;
|
||||
import org.fdroid.fdroid.AppUpdateStatusManager;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
@ -37,17 +35,17 @@ import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
|
||||
|
||||
/**
|
||||
* Main view shown to users upon starting F-Droid.
|
||||
*
|
||||
* <p>
|
||||
* Shows a bottom navigation bar, with the following entries:
|
||||
* + Whats new
|
||||
* + Categories list
|
||||
* + App swap
|
||||
* + Updates
|
||||
* + Settings
|
||||
*
|
||||
* Users navigate between items by using the bottom navigation bar, or by swiping left and right.
|
||||
* When switching from one screen to the next, we stay within this activity. The new screen will
|
||||
* get inflated (if required)
|
||||
* + Whats new
|
||||
* + Categories list
|
||||
* + App swap
|
||||
* + Updates
|
||||
* + Settings
|
||||
* <p>
|
||||
* Users navigate between items by using the bottom navigation bar, or by swiping left and right.
|
||||
* When switching from one screen to the next, we stay within this activity. The new screen will
|
||||
* get inflated (if required)
|
||||
*/
|
||||
public class MainActivity extends AppCompatActivity implements BottomNavigationBar.OnTabSelectedListener {
|
||||
|
||||
@ -105,7 +103,8 @@ public class MainActivity extends AppCompatActivity implements BottomNavigationB
|
||||
.addItem(new BottomNavigationItem(R.drawable.ic_settings, R.string.menu_settings))
|
||||
.initialise();
|
||||
|
||||
IntentFilter updateableAppsFilter = new IntentFilter(AppUpdateStatusManager.BROADCAST_APPSTATUS_LIST_CHANGED);
|
||||
IntentFilter updateableAppsFilter = new IntentFilter(
|
||||
AppUpdateStatusManager.BROADCAST_APPSTATUS_LIST_CHANGED);
|
||||
updateableAppsFilter.addAction(AppUpdateStatusManager.BROADCAST_APPSTATUS_CHANGED);
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(onUpdateableAppsChanged, updateableAppsFilter);
|
||||
|
||||
@ -349,10 +348,10 @@ public class MainActivity extends AppCompatActivity implements BottomNavigationB
|
||||
* There are a bunch of reasons why we would get notified about app statuses.
|
||||
* The ones we are interested in are those which would result in the "items requiring user interaction"
|
||||
* to increase or decrease:
|
||||
* * Bulk updates of ready-to-install-apps (relating to {@link org.fdroid.fdroid.AppUpdateStatusService}.
|
||||
* * Change in status to:
|
||||
* * {@link AppUpdateStatusManager.Status#ReadyToInstall} (Causes the count to go UP by one)
|
||||
* * {@link AppUpdateStatusManager.Status#Installed} (Causes the count to go DOWN by one)
|
||||
* * Bulk updates of ready-to-install-apps (relating to {@link org.fdroid.fdroid.AppUpdateStatusService}.
|
||||
* * Change in status to:
|
||||
* * {@link AppUpdateStatusManager.Status#ReadyToInstall} (Causes the count to go UP by one)
|
||||
* * {@link AppUpdateStatusManager.Status#Installed} (Causes the count to go DOWN by one)
|
||||
*/
|
||||
private final BroadcastReceiver onUpdateableAppsChanged = new BroadcastReceiver() {
|
||||
@Override
|
||||
@ -362,14 +361,18 @@ public class MainActivity extends AppCompatActivity implements BottomNavigationB
|
||||
AppUpdateStatusManager manager = AppUpdateStatusManager.getInstance(context);
|
||||
|
||||
if (AppUpdateStatusManager.BROADCAST_APPSTATUS_LIST_CHANGED.equals(intent.getAction()) &&
|
||||
AppUpdateStatusManager.REASON_READY_TO_INSTALL.equals(intent.getStringExtra(AppUpdateStatusManager.EXTRA_REASON_FOR_CHANGE))) {
|
||||
AppUpdateStatusManager.REASON_READY_TO_INSTALL.equals(
|
||||
intent.getStringExtra(AppUpdateStatusManager.EXTRA_REASON_FOR_CHANGE))) {
|
||||
updateBadge = true;
|
||||
}
|
||||
|
||||
// Check if we have moved into the ReadyToInstall or Installed state.
|
||||
AppUpdateStatusManager.AppUpdateStatus status = manager.get(intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL));
|
||||
AppUpdateStatusManager.AppUpdateStatus status = manager.get(
|
||||
intent.getStringExtra(AppUpdateStatusManager.EXTRA_APK_URL));
|
||||
boolean isStatusChange = intent.getBooleanExtra(AppUpdateStatusManager.EXTRA_IS_STATUS_UPDATE, false);
|
||||
if (isStatusChange && status != null && (status.status == AppUpdateStatusManager.Status.ReadyToInstall || status.status == AppUpdateStatusManager.Status.Installed)) {
|
||||
if (isStatusChange
|
||||
&& status != null
|
||||
&& (status.status == AppUpdateStatusManager.Status.ReadyToInstall || status.status == AppUpdateStatusManager.Status.Installed)) { // NOCHECKSTYLE LineLength
|
||||
updateBadge = true;
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,8 @@ class MainViewAdapter extends RecyclerView.Adapter<MainViewController> {
|
||||
|
||||
private MainViewController createEmptyView() {
|
||||
FrameLayout frame = new FrameLayout(activity);
|
||||
frame.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
frame.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
return new MainViewController(activity, frame);
|
||||
}
|
||||
|
||||
|
@ -9,11 +9,10 @@ import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.views.fragments.PreferencesFragment;
|
||||
import org.fdroid.fdroid.views.updates.UpdatesViewBinder;
|
||||
import org.fdroid.fdroid.views.swap.SwapWorkflowActivity;
|
||||
import org.fdroid.fdroid.views.updates.UpdatesViewBinder;
|
||||
|
||||
/**
|
||||
* Decides which view on the main screen to attach to a given {@link FrameLayout}. This class
|
||||
@ -79,7 +78,8 @@ class MainViewController extends RecyclerView.ViewHolder {
|
||||
// To allow for whitelabel versions of F-Droid, make sure not to hardcode "F-Droid" into our
|
||||
// translation here.
|
||||
TextView subtext = (TextView) swapView.findViewById(R.id.text2);
|
||||
subtext.setText(activity.getString(R.string.nearby_splash__both_parties_need_fdroid, activity.getString(R.string.app_name)));
|
||||
subtext.setText(activity.getString(R.string.nearby_splash__both_parties_need_fdroid,
|
||||
activity.getString(R.string.app_name)));
|
||||
|
||||
Button startButton = (Button) swapView.findViewById(R.id.button);
|
||||
startButton.setOnClickListener(new View.OnClickListener() {
|
||||
@ -93,7 +93,7 @@ class MainViewController extends RecyclerView.ViewHolder {
|
||||
/**
|
||||
* Attaches a {@link PreferencesFragment} to the view. Everything else is managed by the
|
||||
* fragment itself, so no further work needs to be done by this view binder.
|
||||
*
|
||||
* <p>
|
||||
* Note: It is tricky to attach a {@link Fragment} to a view from this view holder. This is due
|
||||
* to the way in which the {@link RecyclerView} will reuse existing views and ask us to
|
||||
* put a settings fragment in there at arbitrary times. Usually it wont be the same view we
|
||||
|
@ -7,16 +7,17 @@ import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.views.fragments.PreferencesFragment;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
/**
|
||||
* When attached to the window, the {@link PreferencesFragment} will be added. When detached from
|
||||
* the window, the fragment will be removed.
|
||||
*
|
||||
* <p>
|
||||
* Based on code from https://github.com/lsjwzh/RecyclerViewPager/blob/master/lib/src/main/java/com/lsjwzh/widget/recyclerviewpager/FragmentStatePagerAdapter.java
|
||||
* licensed under the Apache 2.0 license (https://github.com/lsjwzh/RecyclerViewPager/blob/master/LICENSE).
|
||||
*
|
||||
* @see android.support.v4.app.FragmentStatePagerAdapter Much of the code here was ported from this class.
|
||||
*/
|
||||
public class SettingsView extends FrameLayout {
|
||||
|
@ -14,7 +14,6 @@ import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.UpdateService;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
@ -55,7 +54,8 @@ class WhatsNewViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
appList.setLayoutManager(layoutManager);
|
||||
appList.setAdapter(whatsNewAdapter);
|
||||
|
||||
final SwipeRefreshLayout swipeToRefresh = (SwipeRefreshLayout) whatsNewView.findViewById(R.id.swipe_to_refresh);
|
||||
final SwipeRefreshLayout swipeToRefresh = (SwipeRefreshLayout) whatsNewView
|
||||
.findViewById(R.id.swipe_to_refresh);
|
||||
swipeToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
|
||||
@Override
|
||||
public void onRefresh() {
|
||||
|
@ -19,7 +19,6 @@ import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
@ -111,7 +110,8 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity
|
||||
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.swap_next, menu);
|
||||
MenuItem next = menu.findItem(R.id.action_next);
|
||||
MenuItemCompat.setShowAsAction(next, MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
|
||||
MenuItemCompat.setShowAsAction(next,
|
||||
MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
|
||||
next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
@ -119,7 +119,7 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -12,7 +12,6 @@ import android.view.MenuItem;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import org.fdroid.fdroid.Preferences;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
@ -56,7 +55,8 @@ public class NfcView extends RelativeLayout implements SwapWorkflowActivity.Inne
|
||||
public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.swap_skip, menu);
|
||||
MenuItem next = menu.findItem(R.id.action_next);
|
||||
MenuItemCompat.setShowAsAction(next, MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
|
||||
MenuItemCompat.setShowAsAction(next,
|
||||
MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
|
||||
next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
|
@ -77,7 +77,8 @@ public class SelectAppsView extends ListView implements
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
adapter = new AppListAdapter(this, getContext(),
|
||||
getContext().getContentResolver().query(InstalledAppProvider.getContentUri(), InstalledAppTable.Cols.ALL, null, null, null));
|
||||
getContext().getContentResolver().query(InstalledAppProvider.getContentUri(),
|
||||
InstalledAppTable.Cols.ALL, null, null, null));
|
||||
|
||||
setAdapter(adapter);
|
||||
setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
@ -124,7 +125,8 @@ public class SelectAppsView extends ListView implements
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
// TODO: The STEP_JOIN_WIFI step isn't shown first, need to make it so that it is, or so that this doesn't go back there.
|
||||
// TODO: The STEP_JOIN_WIFI step isn't shown first, need to make it
|
||||
// so that it is, or so that this doesn't go back there.
|
||||
return getState().isConnectingWithPeer() ? SwapService.STEP_INTRO : SwapService.STEP_JOIN_WIFI;
|
||||
}
|
||||
|
||||
|
@ -27,20 +27,19 @@ import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import cc.mvdan.accesspoint.WifiApControl;
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
import org.fdroid.fdroid.localrepo.peers.Peer;
|
||||
import org.fdroid.fdroid.net.WifiStateChangeService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import cc.mvdan.accesspoint.WifiApControl;
|
||||
import rx.Subscriber;
|
||||
import rx.Subscription;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
public class StartSwapView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
|
||||
|
||||
private static final String TAG = "StartSwapView";
|
||||
@ -78,12 +77,14 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(getContext()).inflate(R.layout.swap_peer_list_item, parent, false);
|
||||
convertView = LayoutInflater.from(getContext())
|
||||
.inflate(R.layout.swap_peer_list_item, parent, false);
|
||||
}
|
||||
|
||||
Peer peer = getItem(position);
|
||||
((TextView) convertView.findViewById(R.id.peer_name)).setText(peer.getName());
|
||||
((ImageView) convertView.findViewById(R.id.icon)).setImageDrawable(getResources().getDrawable(peer.getIcon()));
|
||||
((ImageView) convertView.findViewById(R.id.icon))
|
||||
.setImageDrawable(getResources().getDrawable(peer.getIcon()));
|
||||
|
||||
return convertView;
|
||||
}
|
||||
@ -142,7 +143,7 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
|
||||
/**
|
||||
* Remove relevant listeners/subscriptions/etc so that they do not receive and process events
|
||||
* when this view is not in use.
|
||||
*
|
||||
* <p>
|
||||
* TODO: Not sure if this is the best place to handle being removed from the view.
|
||||
*/
|
||||
@Override
|
||||
@ -391,10 +392,10 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
|
||||
* Helper function to set the "enable wifi" switch, but prevents the listeners from
|
||||
* being notified. This enables the UI to be updated without triggering further enable/disable
|
||||
* events being queued.
|
||||
*
|
||||
* <p>
|
||||
* This is required because the SwitchCompat and its parent classes will always try to notify
|
||||
* their listeners if there is one (e.g. http://stackoverflow.com/a/15523518).
|
||||
*
|
||||
* <p>
|
||||
* The fact that this method also deals with enabling/disabling the switch is more of a convenience
|
||||
* Nigh on all times this UI wants to change the state of the switch, it is also interested in
|
||||
* ensuring the enabled state of the switch.
|
||||
@ -408,10 +409,10 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
|
||||
|
||||
/**
|
||||
* When the wifi switch is:
|
||||
*
|
||||
* <p>
|
||||
* Toggled on: Ask the swap service to ensure wifi swap is running.
|
||||
* Toggled off: Ask the swap service to prevent the wifi swap service from running.
|
||||
*
|
||||
* <p>
|
||||
* Both of these actions will be performed in a background thread which will send broadcast
|
||||
* intents when they are completed.
|
||||
*/
|
||||
|
@ -132,7 +132,7 @@ public class SwapAppsView extends ListView implements
|
||||
|
||||
private void pollForUpdates() {
|
||||
if (adapter.getCount() > 1 ||
|
||||
(adapter.getCount() == 1 && !new App((Cursor) adapter.getItem(0)).packageName.equals("org.fdroid.fdroid"))) {
|
||||
(adapter.getCount() == 1 && !new App((Cursor) adapter.getItem(0)).packageName.equals("org.fdroid.fdroid"))) { // NOCHECKSTYLE LineLength
|
||||
Utils.debugLog(TAG, "Not polling for new apps from swap repo, because we already have more than one.");
|
||||
return;
|
||||
}
|
||||
@ -194,7 +194,8 @@ public class SwapAppsView extends ListView implements
|
||||
? AppProvider.getRepoUri(repo)
|
||||
: AppProvider.getSearchUri(repo, currentFilterString);
|
||||
|
||||
return new CursorLoader(getActivity(), uri, AppMetadataTable.Cols.ALL, null, null, AppMetadataTable.Cols.NAME);
|
||||
return new CursorLoader(getActivity(), uri, AppMetadataTable.Cols.ALL,
|
||||
null, null, AppMetadataTable.Cols.NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -305,7 +306,8 @@ public class SwapAppsView extends ListView implements
|
||||
this.app = app;
|
||||
|
||||
Context context = getContext();
|
||||
Apk apk = ApkProvider.Helper.findApkFromAnyRepo(context, app.packageName, app.suggestedVersionCode);
|
||||
Apk apk = ApkProvider.Helper.findApkFromAnyRepo(context,
|
||||
app.packageName, app.suggestedVersionCode);
|
||||
String urlString = apk.getUrl();
|
||||
|
||||
// TODO unregister receivers? or will they just die with this instance
|
||||
|
@ -64,6 +64,7 @@ import cc.mvdan.accesspoint.WifiApControl;
|
||||
* The problem comes when there are two competing goals - 1) Show the user a list of apps from another
|
||||
* device to download and install, and 2) Prepare your own list of apps to share.
|
||||
*/
|
||||
@SuppressWarnings("LineLength")
|
||||
public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
|
||||
/**
|
||||
|
@ -13,9 +13,7 @@ import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.hannesdorfmann.adapterdelegates3.AdapterDelegatesManager;
|
||||
|
||||
import org.fdroid.fdroid.AppUpdateStatusManager;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
@ -34,31 +32,38 @@ import java.util.Set;
|
||||
|
||||
/**
|
||||
* Manages the following types of information:
|
||||
* * Apps marked for downloading (while the user is offline)
|
||||
* * Currently downloading apps
|
||||
* * Apps which have been downloaded (and need further action to install). This includes new installs and updates.
|
||||
* * Reminders to users that they can donate to apps (only shown infrequently after several updates)
|
||||
* * A list of apps which are eligible to be updated (for when the "Automatic Updates" option is disabled), including:
|
||||
* + A summary of all apps to update including an "Update all" button and a "Show apps" button.
|
||||
* + Once "Show apps" is expanded then each app is shown along with its own download button.
|
||||
*
|
||||
* <ul>
|
||||
* <li>Apps marked for downloading (while the user is offline)</li>
|
||||
* <li>Currently downloading apps</li>
|
||||
* <li>Apps which have been downloaded (and need further action to install)</li>
|
||||
* </ul>
|
||||
* This includes new installs and updates.
|
||||
* <ul>
|
||||
* <li>Reminders to users that they can donate to apps (only shown infrequently after several updates)</li>
|
||||
* <li>A list of apps which are eligible to be updated (for when the "Automatic Updates" option is disabled),
|
||||
* including:
|
||||
* + A summary of all apps to update including an "Update all" button and a "Show apps" button.
|
||||
* + Once "Show apps" is expanded then each app is shown along with its own download button.</li>
|
||||
* </ul>
|
||||
* It does this by maintaining several different lists of interesting apps. Each list contains wrappers
|
||||
* around the piece of data it wants to render ({@link AppStatus}, {@link UpdateableApp}).
|
||||
* Instead of juggling the various viewTypes
|
||||
* to find out which position in the adapter corresponds to which view type, this is handled by
|
||||
* the {@link UpdatesAdapter#delegatesManager}.
|
||||
*
|
||||
* <p>
|
||||
* There are a series of type-safe lists which hold the specific data this adapter is interested in.
|
||||
* This data is then collated into a single list (see {@link UpdatesAdapter#populateItems()}) which
|
||||
* is the actual thing the adapter binds too. At any point it is safe to clear the single list and
|
||||
* repopulate it from the original source lists of data. When this is done, the adapter will notify
|
||||
* the recycler view that its data has changed. Sometimes it will also ask the recycler view to
|
||||
* scroll to the newly added item (if attached to the recycler view).
|
||||
*
|
||||
* <p>
|
||||
* TODO: If a user downloads an old version of an app (resulting in a new update being available
|
||||
* instantly), then we need to refresh the list of apps to update.
|
||||
*/
|
||||
public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
@SuppressWarnings("LineLength")
|
||||
public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
|
||||
implements LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
private final AdapterDelegatesManager<List<AppUpdateData>> delegatesManager = new AdapterDelegatesManager<>();
|
||||
private final List<AppUpdateData> items = new ArrayList<>();
|
||||
@ -221,7 +226,8 @@ public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader) { }
|
||||
public void onLoaderReset(Loader<Cursor> loader) {
|
||||
}
|
||||
|
||||
/**
|
||||
* If this adapter is "active" then it is part of the current UI that the user is looking to.
|
||||
|
@ -4,9 +4,7 @@ import android.app.Activity;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.hannesdorfmann.adapterdelegates3.AdapterDelegate;
|
||||
|
||||
import org.fdroid.fdroid.AppUpdateStatusManager;
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
@ -16,8 +14,10 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Apps which we want to show some more substantial information about.
|
||||
*
|
||||
* @see R.layout#updateable_app_status_item The view that this binds to
|
||||
* @see AppListItemController Used for binding the {@link App} to the {@link R.layout#updateable_app_status_item}
|
||||
* @see AppListItemController Used for binding the {@link App} to the
|
||||
* {@link R.layout#updateable_app_status_item}
|
||||
*/
|
||||
public class AppStatus extends AppUpdateData {
|
||||
|
||||
@ -44,11 +44,13 @@ public class AppStatus extends AppUpdateData {
|
||||
@NonNull
|
||||
@Override
|
||||
protected RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
return new AppListItemController(activity, activity.getLayoutInflater().inflate(R.layout.updateable_app_status_item, parent, false));
|
||||
return new AppListItemController(activity, activity.getLayoutInflater()
|
||||
.inflate(R.layout.updateable_app_status_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBindViewHolder(@NonNull List<AppUpdateData> items, int position, @NonNull RecyclerView.ViewHolder holder, @NonNull List<Object> payloads) {
|
||||
protected void onBindViewHolder(@NonNull List<AppUpdateData> items, int position,
|
||||
@NonNull RecyclerView.ViewHolder holder, @NonNull List<Object> payloads) {
|
||||
AppStatus app = (AppStatus) items.get(position);
|
||||
((AppListItemController) holder).bindModel(app.status.app);
|
||||
}
|
||||
|
@ -3,8 +3,10 @@ package org.fdroid.fdroid.views.updates.items;
|
||||
import android.app.Activity;
|
||||
|
||||
/**
|
||||
* Used as a common base class for all data types in the {@link org.fdroid.fdroid.views.updates.UpdatesAdapter}.
|
||||
* Doesn't have any functionality of its own, but allows the {@link org.fdroid.fdroid.views.updates.UpdatesAdapter#delegatesManager}
|
||||
* Used as a common base class for all data types in the {@link
|
||||
* org.fdroid.fdroid.views.updates.UpdatesAdapter}. Doesn't have any
|
||||
* functionality of its own, but allows the {@link
|
||||
* org.fdroid.fdroid.views.updates.UpdatesAdapter#delegatesManager}
|
||||
* to specify a data type more specific than just {@link Object}.
|
||||
*/
|
||||
public abstract class AppUpdateData {
|
||||
|
@ -4,9 +4,7 @@ import android.app.Activity;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.hannesdorfmann.adapterdelegates3.AdapterDelegate;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.views.apps.AppListItemController;
|
||||
@ -15,6 +13,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* List of all apps which can be updated, but have not yet been downloaded.
|
||||
*
|
||||
* @see UpdateableApp The data that is bound to this view.
|
||||
* @see R.layout#updateable_app_list_item The view that this binds to.
|
||||
* @see AppListItemController Used for binding the {@link App} to the {@link R.layout#updateable_app_list_item}
|
||||
@ -44,11 +43,13 @@ public class UpdateableApp extends AppUpdateData {
|
||||
@NonNull
|
||||
@Override
|
||||
protected RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
return new AppListItemController(activity, activity.getLayoutInflater().inflate(R.layout.updateable_app_list_item, parent, false));
|
||||
return new AppListItemController(activity, activity.getLayoutInflater()
|
||||
.inflate(R.layout.updateable_app_list_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBindViewHolder(@NonNull List<AppUpdateData> items, int position, @NonNull RecyclerView.ViewHolder holder, @NonNull List<Object> payloads) {
|
||||
protected void onBindViewHolder(@NonNull List<AppUpdateData> items, int position,
|
||||
@NonNull RecyclerView.ViewHolder holder, @NonNull List<Object> payloads) {
|
||||
UpdateableApp app = (UpdateableApp) items.get(position);
|
||||
((AppListItemController) holder).bindModel(app.app);
|
||||
}
|
||||
|
@ -10,9 +10,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.hannesdorfmann.adapterdelegates3.AdapterDelegate;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.UpdateService;
|
||||
import org.fdroid.fdroid.views.updates.UpdatesAdapter;
|
||||
@ -23,6 +21,7 @@ import java.util.List;
|
||||
/**
|
||||
* Summary of all apps that can be downloaded. Includes a button to download all of them and also
|
||||
* a toggle to show or hide the list of each individual item.
|
||||
*
|
||||
* @see R.layout#updates_header The view that this binds to.
|
||||
* @see UpdateableAppsHeader The data that is bound to this view.
|
||||
*/
|
||||
@ -31,7 +30,8 @@ public class UpdateableAppsHeader extends AppUpdateData {
|
||||
public final List<UpdateableApp> apps;
|
||||
public final UpdatesAdapter adapter;
|
||||
|
||||
public UpdateableAppsHeader(Activity activity, UpdatesAdapter updatesAdapter, List<UpdateableApp> updateableApps) {
|
||||
public UpdateableAppsHeader(Activity activity,
|
||||
UpdatesAdapter updatesAdapter, List<UpdateableApp> updateableApps) {
|
||||
super(activity);
|
||||
apps = updateableApps;
|
||||
adapter = updatesAdapter;
|
||||
@ -57,7 +57,8 @@ public class UpdateableAppsHeader extends AppUpdateData {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBindViewHolder(@NonNull List<AppUpdateData> items, int position, @NonNull RecyclerView.ViewHolder holder, @NonNull List<Object> payloads) {
|
||||
protected void onBindViewHolder(@NonNull List<AppUpdateData> items, int position,
|
||||
@NonNull RecyclerView.ViewHolder holder, @NonNull List<Object> payloads) {
|
||||
UpdateableAppsHeader app = (UpdateableAppsHeader) items.get(position);
|
||||
((ViewHolder) holder).bindHeader(app);
|
||||
}
|
||||
@ -87,7 +88,9 @@ public class UpdateableAppsHeader extends AppUpdateData {
|
||||
public void bindHeader(UpdateableAppsHeader header) {
|
||||
this.header = header;
|
||||
|
||||
updatesAvailable.setText(itemView.getResources().getQuantityString(R.plurals.updates__download_updates_for_apps, header.apps.size(), header.apps.size()));
|
||||
updatesAvailable.setText(itemView.getResources()
|
||||
.getQuantityString(R.plurals.updates__download_updates_for_apps, header.apps.size(),
|
||||
header.apps.size()));
|
||||
|
||||
List<String> appNames = new ArrayList<>(header.apps.size());
|
||||
for (UpdateableApp app : header.apps) {
|
||||
|
@ -2,6 +2,7 @@ package org.fdroid.fdroid.views.whatsnew;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Rect;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
@ -9,7 +10,6 @@ import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.views.categories.AppCardController;
|
||||
@ -108,6 +108,7 @@ public class WhatsNewAdapter extends RecyclerView.Adapter<AppCardController> {
|
||||
/**
|
||||
* Applies padding to items, ensuring that the spacing on the left, centre, and right all match.
|
||||
* The vertical padding is slightly shorter than the horizontal padding also.
|
||||
*
|
||||
* @see org.fdroid.fdroid.R.dimen#whats_new__padding__app_card__horizontal
|
||||
* @see org.fdroid.fdroid.R.dimen#whats_new__padding__app_card__vertical
|
||||
*/
|
||||
@ -121,8 +122,9 @@ public class WhatsNewAdapter extends RecyclerView.Adapter<AppCardController> {
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
int position = parent.getChildAdapterPosition(view);
|
||||
int horizontalPadding = (int) context.getResources().getDimension(R.dimen.whats_new__padding__app_card__horizontal);
|
||||
int verticalPadding = (int) context.getResources().getDimension(R.dimen.whats_new__padding__app_card__vertical);
|
||||
Resources resources = context.getResources();
|
||||
int horizontalPadding = (int) resources.getDimension(R.dimen.whats_new__padding__app_card__horizontal);
|
||||
int verticalPadding = (int) resources.getDimension(R.dimen.whats_new__padding__app_card__vertical);
|
||||
|
||||
int relativePositionInCycle = position % 5;
|
||||
if (position == 0) {
|
||||
|
@ -6,8 +6,9 @@ import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
|
||||
/**
|
||||
* This class is added so that the bluetooth:// scheme we use for the {@link org.fdroid.fdroid.net.BluetoothDownloader}
|
||||
* is not treated as invalid by the {@link URL} class.
|
||||
* This class is added so that the bluetooth:// scheme we use for the {@link
|
||||
* org.fdroid.fdroid.net.BluetoothDownloader} is not treated as invalid by
|
||||
* the {@link URL} class.
|
||||
*/
|
||||
public class Handler extends URLStreamHandler {
|
||||
@Override
|
||||
|
@ -4,9 +4,7 @@ import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
@ -118,7 +116,7 @@ public class Assert {
|
||||
}
|
||||
|
||||
public static void assertInvalidUri(ShadowContentResolver resolver, Uri uri) {
|
||||
Cursor cursor = resolver.query(uri, new String[] {}, null, null, null);
|
||||
Cursor cursor = resolver.query(uri, new String[]{}, null, null, null);
|
||||
assertNull(cursor);
|
||||
}
|
||||
|
||||
@ -128,16 +126,18 @@ public class Assert {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
public static void assertValidUri(ShadowContentResolver resolver, Uri actualUri, String expectedUri, String[] projection) {
|
||||
public static void assertValidUri(ShadowContentResolver resolver, Uri actualUri, String expectedUri,
|
||||
String[] projection) {
|
||||
assertValidUri(resolver, actualUri, projection);
|
||||
assertEquals(expectedUri, actualUri.toString());
|
||||
}
|
||||
|
||||
public static void assertResultCount(ShadowContentResolver resolver, int expectedCount, Uri uri) {
|
||||
assertResultCount(resolver, expectedCount, uri, new String[] {});
|
||||
assertResultCount(resolver, expectedCount, uri, new String[]{});
|
||||
}
|
||||
|
||||
public static void assertResultCount(ShadowContentResolver resolver, int expectedCount, Uri uri, String[] projection) {
|
||||
public static void assertResultCount(ShadowContentResolver resolver, int expectedCount, Uri uri,
|
||||
String[] projection) {
|
||||
Cursor cursor = resolver.query(uri, projection, null, null, null);
|
||||
assertResultCount(expectedCount, cursor);
|
||||
cursor.close();
|
||||
@ -153,7 +153,8 @@ public class Assert {
|
||||
assertEquals(expectedCount, result.getCount());
|
||||
}
|
||||
|
||||
public static void assertIsInstalledVersionInDb(ShadowContentResolver resolver, String appId, int versionCode, String versionName) {
|
||||
public static void assertIsInstalledVersionInDb(ShadowContentResolver resolver,
|
||||
String appId, int versionCode, String versionName) {
|
||||
Uri uri = InstalledAppProvider.getAppUri(appId);
|
||||
|
||||
String[] projection = {
|
||||
@ -198,14 +199,17 @@ public class Assert {
|
||||
Uri uri = AppProvider.getContentUri();
|
||||
|
||||
context.getContentResolver().insert(uri, values);
|
||||
return AppProvider.Helper.findSpecificApp(context.getContentResolver(), packageName, 1, AppMetadataTable.Cols.ALL);
|
||||
return AppProvider.Helper.findSpecificApp(context.getContentResolver(), packageName, 1,
|
||||
AppMetadataTable.Cols.ALL);
|
||||
}
|
||||
|
||||
public static App ensureApp(Context context, String packageName) {
|
||||
App app = AppProvider.Helper.findSpecificApp(context.getContentResolver(), packageName, 1, AppMetadataTable.Cols.ALL);
|
||||
App app = AppProvider.Helper.findSpecificApp(context.getContentResolver(), packageName, 1,
|
||||
AppMetadataTable.Cols.ALL);
|
||||
if (app == null) {
|
||||
insertApp(context, packageName, packageName);
|
||||
app = AppProvider.Helper.findSpecificApp(context.getContentResolver(), packageName, 1, AppMetadataTable.Cols.ALL);
|
||||
app = AppProvider.Helper.findSpecificApp(context.getContentResolver(), packageName, 1,
|
||||
AppMetadataTable.Cols.ALL);
|
||||
}
|
||||
assertNotNull(app);
|
||||
return app;
|
||||
@ -215,7 +219,8 @@ public class Assert {
|
||||
return insertApk(context, ensureApp(context, packageName), versionCode);
|
||||
}
|
||||
|
||||
public static Uri insertApk(Context context, String packageName, int versionCode, ContentValues additionalValues) {
|
||||
public static Uri insertApk(Context context, String packageName, int versionCode,
|
||||
ContentValues additionalValues) {
|
||||
return insertApk(context, ensureApp(context, packageName), versionCode, additionalValues);
|
||||
}
|
||||
|
||||
|
@ -55,12 +55,14 @@ public class TestUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* The way that Robolectric has to implement shadows for Android classes such as {@link android.content.ContentProvider}
|
||||
* is by using a special annotation that means the classes will implement the correct methods at runtime.
|
||||
* However this means that the shadow of a content provider does not actually extend
|
||||
* {@link android.content.ContentProvider}. As such, we need to do some special mocking using
|
||||
* Mockito in order to provide a {@link ContextWrapper} which is able to return a proper
|
||||
* content resolver that delegates to the Robolectric shadow object.
|
||||
* The way that Robolectric has to implement shadows for Android classes
|
||||
* such as {@link android.content.ContentProvider} is by using a special
|
||||
* annotation that means the classes will implement the correct methods at
|
||||
* runtime. However this means that the shadow of a content provider does
|
||||
* not actually extend {@link android.content.ContentProvider}. As such,
|
||||
* we need to do some special mocking using Mockito in order to provide a
|
||||
* {@link ContextWrapper} which is able to return a proper content
|
||||
* resolver that delegates to the Robolectric shadow object.
|
||||
*/
|
||||
public static ContextWrapper createContextWithContentResolver(ShadowContentResolver contentResolver) {
|
||||
final ContentResolver resolver = mock(ContentResolver.class, AdditionalAnswers.delegatesTo(contentResolver));
|
||||
|
@ -18,6 +18,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
@Config(constants = BuildConfig.class, sdk = 24)
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@SuppressWarnings("LineLength")
|
||||
public class UtilsTest {
|
||||
|
||||
String fdroidFingerprint = "43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB";
|
||||
|
@ -30,6 +30,7 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
@Config(constants = BuildConfig.class, application = Application.class, sdk = 24)
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@SuppressWarnings("LineLength")
|
||||
public class AppProviderTest extends FDroidProviderTest {
|
||||
|
||||
private static final String[] PROJ = Cols.ALL;
|
||||
|
@ -5,7 +5,6 @@ import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols;
|
||||
@ -46,7 +45,7 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
||||
insertAppWithCategory("com.dog.rock.apple", "Dog-Rock-Apple", "Animal,Mineral,Vegetable", mainRepo);
|
||||
insertAppWithCategory("com.banana.apple", "Banana", "Vegetable,Vegetable", mainRepo);
|
||||
|
||||
String[] expectedFDroid = new String[] {
|
||||
String[] expectedFDroid = new String[]{
|
||||
"Animal",
|
||||
"Mineral",
|
||||
"Security",
|
||||
@ -54,13 +53,13 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
||||
"Writing",
|
||||
};
|
||||
|
||||
String[] expectedGP = new String[] {
|
||||
String[] expectedGP = new String[]{
|
||||
"GuardianProject",
|
||||
"Office",
|
||||
};
|
||||
|
||||
// We overwrite "Security" + "Writing" with "GuardianProject" + "Office"
|
||||
String[] expectedBoth = new String[] {
|
||||
String[] expectedBoth = new String[]{
|
||||
"Animal",
|
||||
"Mineral",
|
||||
"Vegetable",
|
||||
@ -90,16 +89,16 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
||||
insertAppWithCategory("com.banana", "Banana", "Food");
|
||||
insertAppWithCategory("com.dog-food", "Dog Food", "Food");
|
||||
|
||||
assertPackagesInUri(AppProvider.getSearchUri("dog", "Animal"), new String[] {
|
||||
assertPackagesInUri(AppProvider.getSearchUri("dog", "Animal"), new String[]{
|
||||
"com.dog",
|
||||
"com.dog-statue",
|
||||
});
|
||||
|
||||
assertPackagesInUri(AppProvider.getSearchUri("dog", "Food"), new String[] {
|
||||
assertPackagesInUri(AppProvider.getSearchUri("dog", "Food"), new String[]{
|
||||
"com.dog-food",
|
||||
});
|
||||
|
||||
assertPackagesInUri(AppProvider.getSearchUri("dog", null), new String[] {
|
||||
assertPackagesInUri(AppProvider.getSearchUri("dog", null), new String[]{
|
||||
"com.dog",
|
||||
"com.dog-statue",
|
||||
"com.dog-food",
|
||||
@ -116,14 +115,14 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
||||
insertAppWithCategory("com.rock", "Rock", "Mineral");
|
||||
insertAppWithCategory("com.banana", "Banana", "Food");
|
||||
|
||||
assertPackagesInCategory("Animal", new String[] {
|
||||
assertPackagesInCategory("Animal", new String[]{
|
||||
"com.dog",
|
||||
"com.cat",
|
||||
"com.crow",
|
||||
"com.chicken",
|
||||
});
|
||||
|
||||
assertPackagesInCategory("animal", new String[] {
|
||||
assertPackagesInCategory("animal", new String[]{
|
||||
"com.dog",
|
||||
"com.cat",
|
||||
"com.crow",
|
||||
@ -136,12 +135,12 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
||||
"com.bird-statue",
|
||||
});
|
||||
|
||||
assertPackagesInCategory("Food", new String[] {
|
||||
assertPackagesInCategory("Food", new String[]{
|
||||
"com.chicken",
|
||||
"com.banana",
|
||||
});
|
||||
|
||||
assertPackagesInCategory("Mineral", new String[] {
|
||||
assertPackagesInCategory("Mineral", new String[]{
|
||||
"com.rock",
|
||||
"com.bird-statue",
|
||||
});
|
||||
@ -178,17 +177,18 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
||||
insertAppWithCategory("com.banana", "Banana", "Vegetable");
|
||||
insertAppWithCategory("com.tomato", "Tomato", "Vegetable");
|
||||
|
||||
assertContainsOnly(topAppsFromCategory("Animal", 3), new String[] {"com.bird", "com.cat", "com.dog", });
|
||||
assertContainsOnly(topAppsFromCategory("Animal", 2), new String[] {"com.bird", "com.cat", });
|
||||
assertContainsOnly(topAppsFromCategory("Animal", 1), new String[] {"com.bird", });
|
||||
assertContainsOnly(topAppsFromCategory("Animal", 3), new String[]{"com.bird", "com.cat", "com.dog"});
|
||||
assertContainsOnly(topAppsFromCategory("Animal", 2), new String[]{"com.bird", "com.cat"});
|
||||
assertContainsOnly(topAppsFromCategory("Animal", 1), new String[]{"com.bird"});
|
||||
|
||||
assertContainsOnly(topAppsFromCategory("Mineral", 2), new String[] {"com.boulder", "com.rock", });
|
||||
assertContainsOnly(topAppsFromCategory("Mineral", 2), new String[]{"com.boulder", "com.rock"});
|
||||
|
||||
assertContainsOnly(topAppsFromCategory("Vegetable", 10), new String[] {"com.banana", "com.tomato", });
|
||||
assertContainsOnly(topAppsFromCategory("Vegetable", 10), new String[]{"com.banana", "com.tomato"});
|
||||
}
|
||||
|
||||
public String[] topAppsFromCategory(String category, int numToGet) {
|
||||
List<App> apps = AppProvider.Helper.cursorToList(contentResolver.query(AppProvider.getTopFromCategoryUri(category, numToGet), Cols.ALL, null, null, Cols.NAME));
|
||||
List<App> apps = AppProvider.Helper.cursorToList(contentResolver
|
||||
.query(AppProvider.getTopFromCategoryUri(category, numToGet), Cols.ALL, null, null, Cols.NAME));
|
||||
String[] packageNames = new String[apps.size()];
|
||||
for (int i = 0; i < apps.size(); i++) {
|
||||
packageNames[i] = apps.get(i).packageName;
|
||||
@ -204,7 +204,7 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
||||
insertAppWithCategory("com.banana", "Banana", "Vegetable");
|
||||
|
||||
List<String> categories = categories();
|
||||
String[] expected = new String[] {
|
||||
String[] expected = new String[]{
|
||||
"Animal",
|
||||
"Mineral",
|
||||
"Vegetable",
|
||||
@ -221,7 +221,7 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
||||
insertAppWithCategory("com.banana.apple", "Banana", "Vegetable,Vegetable", mainRepo);
|
||||
|
||||
List<String> categories = categories();
|
||||
String[] expected = new String[] {
|
||||
String[] expected = new String[]{
|
||||
"Animal",
|
||||
"Mineral",
|
||||
"Vegetable",
|
||||
@ -232,10 +232,10 @@ public class CategoryProviderTest extends FDroidProviderTest {
|
||||
|
||||
insertAppWithCategory("com.example.game", "Game",
|
||||
"Running,Shooting,Jumping,Bleh,Sneh,Pleh,Blah,Test category," +
|
||||
"The quick brown fox jumps over the lazy dog,With apostrophe's", additionalRepo);
|
||||
"The quick brown fox jumps over the lazy dog,With apostrophe's", additionalRepo);
|
||||
|
||||
List<String> categoriesLonger = categories();
|
||||
String[] expectedLonger = new String[] {
|
||||
String[] expectedLonger = new String[]{
|
||||
"Animal",
|
||||
"Mineral",
|
||||
"Vegetable",
|
||||
|
@ -6,7 +6,6 @@ import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
@ -134,13 +133,13 @@ public class DatabaseMigration {
|
||||
}
|
||||
|
||||
private void insertRepos(SQLiteDatabase db) {
|
||||
String pubKey = "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef";
|
||||
String pubKey = "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef"; // NOCHECKSTYLE LineLength
|
||||
String fingerprint = Utils.calcFingerprint(pubKey);
|
||||
|
||||
ContentValues fdroidValues = new ContentValues();
|
||||
fdroidValues.put("address", "https://f-droid.org/repo");
|
||||
fdroidValues.put("name", "F-Droid");
|
||||
fdroidValues.put("description", "The official FDroid repository. Applications in this repository are mostly built directory from the source code. Some are official binaries built by the original application developers - these will be replaced by source-built versions over time.");
|
||||
fdroidValues.put("description", "The official FDroid repository. Applications in this repository are mostly built directory from the source code. Some are official binaries built by the original application developers - these will be replaced by source-built versions over time."); // NOCHECKSTYLE LineLength
|
||||
fdroidValues.put("pubkey", pubKey);
|
||||
fdroidValues.put("fingerprint", fingerprint);
|
||||
fdroidValues.put("maxage", 0);
|
||||
@ -152,7 +151,7 @@ public class DatabaseMigration {
|
||||
ContentValues archiveValues = new ContentValues();
|
||||
archiveValues.put("address", "https://f-droid.org/archive");
|
||||
archiveValues.put("name", "F-Droid Archive");
|
||||
archiveValues.put("description", "The archive repository of the F-Droid client. This contains older versions of applications from the main repository.");
|
||||
archiveValues.put("description", "The archive repository of the F-Droid client. This contains older versions of applications from the main repository."); // NOCHECKSTYLE LineLength
|
||||
archiveValues.put("pubkey", pubKey);
|
||||
archiveValues.put("fingerprint", fingerprint);
|
||||
archiveValues.put("maxage", 0);
|
||||
|
@ -4,7 +4,6 @@ import android.app.Application;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.fdroid.fdroid.BuildConfig;
|
||||
import org.fdroid.fdroid.TestUtils;
|
||||
import org.fdroid.fdroid.data.Schema.InstalledAppTable.Cols;
|
||||
@ -15,14 +14,14 @@ import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.fdroid.fdroid.Assert.assertIsInstalledVersionInDb;
|
||||
import static org.fdroid.fdroid.Assert.assertResultCount;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Config(constants = BuildConfig.class, application = Application.class, sdk = 24)
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class InstalledAppProviderTest extends FDroidProviderTest {
|
||||
@ -52,7 +51,8 @@ public class InstalledAppProviderTest extends FDroidProviderTest {
|
||||
assertEquals(1, foundAfter.size());
|
||||
assertEquals(100000000L, foundAfter.get("org.example.test-app").longValue());
|
||||
|
||||
Cursor cursor = contentResolver.query(InstalledAppProvider.getAppUri("org.example.test-app"), Cols.ALL, null, null, null);
|
||||
Cursor cursor = contentResolver.query(InstalledAppProvider.getAppUri("org.example.test-app"), Cols.ALL,
|
||||
null, null, null);
|
||||
assertEquals(cursor.getCount(), 1);
|
||||
|
||||
cursor.moveToFirst();
|
||||
@ -63,7 +63,8 @@ public class InstalledAppProviderTest extends FDroidProviderTest {
|
||||
assertEquals("has of test app", cursor.getString(cursor.getColumnIndex(Cols.HASH)));
|
||||
assertEquals("fake hash type", cursor.getString(cursor.getColumnIndex(Cols.HASH_TYPE)));
|
||||
assertEquals(100000000L, cursor.getLong(cursor.getColumnIndex(Cols.LAST_UPDATE_TIME)));
|
||||
assertEquals("000111222333444555666777888999aaabbbcccdddeeefff", cursor.getString(cursor.getColumnIndex(Cols.SIGNATURE)));
|
||||
assertEquals("000111222333444555666777888999aaabbbcccdddeeefff",
|
||||
cursor.getString(cursor.getColumnIndex(Cols.SIGNATURE)));
|
||||
|
||||
cursor.close();
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import static org.fdroid.fdroid.Assert.assertValidUri;
|
||||
|
||||
@Config(constants = BuildConfig.class, sdk = 24)
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@SuppressWarnings("LineLength")
|
||||
public class ProviderUriTests {
|
||||
|
||||
private ShadowContentResolver resolver;
|
||||
|
@ -142,7 +142,8 @@ public class RepoProviderTest extends FDroidProviderTest {
|
||||
for (String url : urls) {
|
||||
Repo actualRepo = RepoProvider.Helper.findByUrl(context, Uri.parse(url), COLS);
|
||||
assertNotNull("No repo matching URL " + url, actualRepo);
|
||||
assertEquals("Invalid repo for URL [" + url + "]. Expected [" + expectedRepo.address + "] but got [" + actualRepo.address + "]", expectedRepo.id, actualRepo.id);
|
||||
assertEquals("Invalid repo for URL [" + url + "]. Expected [" + expectedRepo.address + "] but got ["
|
||||
+ actualRepo.address + "]", expectedRepo.id, actualRepo.id);
|
||||
}
|
||||
|
||||
}
|
||||
@ -253,7 +254,8 @@ public class RepoProviderTest extends FDroidProviderTest {
|
||||
return insertRepo(context, address, description, fingerprint, null);
|
||||
}
|
||||
|
||||
public static Repo insertRepo(Context context, String address, String description, String fingerprint, @Nullable String name) {
|
||||
public static Repo insertRepo(Context context, String address, String description,
|
||||
String fingerprint, @Nullable String name) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RepoTable.Cols.ADDRESS, address);
|
||||
values.put(RepoTable.Cols.DESCRIPTION, description);
|
||||
|
@ -29,7 +29,7 @@ public class SanitizedFileTest {
|
||||
|
||||
assertEquals("safe", safeNotSanitized.getName());
|
||||
assertEquals("$%^safe-and_bleh.boo*@~", nonEvilNotSanitized.getName());
|
||||
assertEquals("shadow;", evilNotSanitized.getName()); // Should be ;rm /etc/shadow; but the forward slashes are naughty.
|
||||
assertEquals("shadow;", evilNotSanitized.getName());
|
||||
|
||||
SanitizedFile safeSanitized = new SanitizedFile(directory, safeFile);
|
||||
SanitizedFile nonEvilSanitized = new SanitizedFile(directory, nonEvilFile);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user