enforce max line length at 118

gitlab's diff views wrap badly when lines are longer than 118.  Android
Studio places a grey line in the UI at 120.

@SuppressWarnings("LineLength") is added to a bunch of files to prevent
making this commit huge.  People can remove that as they work on those
files, and fix the issues then.

I also ran Android Studio's default Ctrl-Alt-L code formatter, where it was
easy to do, and I was already in the file.
This commit is contained in:
Hans-Christoph Steiner 2017-06-06 16:11:46 +02:00
parent a0015cda32
commit 48fd6d287d
107 changed files with 535 additions and 373 deletions

View File

@ -54,7 +54,8 @@ public class HttpDownloaderTest {
httpDownloader.setListener(new ProgressListener() { httpDownloader.setListener(new ProgressListener() {
@Override @Override
public void onProgress(URL sourceUrl, int bytesRead, int totalBytes) { 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; receivedProgress = true;
} }
}); });

View File

@ -107,6 +107,7 @@ import java.util.Map;
* @author Brad Drehmer * @author Brad Drehmer
* @author gcstang * @author gcstang
*/ */
@SuppressWarnings("LineLength")
public class IntentIntegrator { public class IntentIntegrator {
public static final int REQUEST_CODE = 0x0000c0de; // Only use bottom 16 bits public static final int REQUEST_CODE = 0x0000c0de; // Only use bottom 16 bits

View File

@ -83,7 +83,8 @@ public final class IntentResult {
@Override @Override
public String toString() { public String toString() {
int rawBytesLength = rawBytes == null ? 0 : rawBytes.length; 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';
} }
} }

View File

@ -74,6 +74,7 @@ import org.fdroid.fdroid.views.apps.FeatureImage;
import java.util.Iterator; import java.util.Iterator;
@SuppressWarnings("LineLength")
public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog.ShareChooserDialogListener, AppDetailsRecyclerViewAdapter.AppDetailsRecyclerViewAdapterCallbacks { public class AppDetails2 extends AppCompatActivity implements ShareChooserDialog.ShareChooserDialogListener, AppDetailsRecyclerViewAdapter.AppDetailsRecyclerViewAdapterCallbacks {
public static final String EXTRA_APPID = "appid"; public static final String EXTRA_APPID = "appid";

View File

@ -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 true;
} }
return false; return false;

View File

@ -13,7 +13,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.TaskStackBuilder; import android.support.v4.app.TaskStackBuilder;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider; 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 * and {@code versionCode} since there could be different copies of the same
* APK on different servers, signed by different keys, or even different builds. * APK on different servers, signed by different keys, or even different builds.
*/ */
@SuppressWarnings("LineLength")
public final class AppUpdateStatusManager { public final class AppUpdateStatusManager {
private static final String TAG = "AppUpdateStatusManager"; private static final String TAG = "AppUpdateStatusManager";
/** /**
* Broadcast when: * Broadcast when:
* * The user clears the list of installed apps from notification manager. * * 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. * * 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. * * 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. * * 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"; public static final String BROADCAST_APPSTATUS_LIST_CHANGED = "org.fdroid.fdroid.installer.appstatus.listchange";
@ -61,9 +61,9 @@ public final class AppUpdateStatusManager {
/** /**
* Broadcast when: * Broadcast when:
* * The associated app has the {@link Status#Installed} status, and the user either visits * * 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. * that apps details page or clears the individual notification for the app.
* * The download for an app is cancelled. * * The download for an app is cancelled.
*/ */
public static final String BROADCAST_APPSTATUS_REMOVED = "org.fdroid.fdroid.installer.appstatus.appchange.remove"; 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. * Dumps some information about the status for debugging purposes.
*/ */
public String toString() { public String toString() {
return app.packageName + " [Status: " + status + ", Progress: " + progressCurrent + " / " + progressMax + "]"; return app.packageName + " [Status: " + status
+ ", Progress: " + progressCurrent + " / " + progressMax + "]";
} }
protected AppUpdateStatus(Parcel in) { protected AppUpdateStatus(Parcel in) {
@ -191,7 +192,9 @@ public final class AppUpdateStatusManager {
private final HashMap<String, AppUpdateStatus> appMapping = new HashMap<>(); private final HashMap<String, AppUpdateStatus> appMapping = new HashMap<>();
private boolean isBatchUpdating; private boolean isBatchUpdating;
/** @see #isPendingInstall(String) */ /**
* @see #isPendingInstall(String)
*/
private final SharedPreferences apksPendingInstall; private final SharedPreferences apksPendingInstall;
private AppUpdateStatusManager(Context context) { private AppUpdateStatusManager(Context context) {
@ -215,6 +218,7 @@ public final class AppUpdateStatusManager {
/** /**
* Get all entries associated with a package name. There may be several. * Get all entries associated with a package name. There may be several.
*
* @param packageName Package name of the app * @param packageName Package name of the app
* @return A list of entries, or an empty list * @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). * 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) * @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) { public void addApk(Apk apk, @NonNull Status status, @Nullable PendingIntent pendingIntent) {
@ -433,7 +438,7 @@ public final class AppUpdateStatusManager {
void clearAllUpdates() { void clearAllUpdates() {
synchronized (appMapping) { 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(); Map.Entry<String, AppUpdateStatus> entry = it.next();
if (entry.getValue().status != Status.Installed) { if (entry.getValue().status != Status.Installed) {
it.remove(); it.remove();
@ -445,7 +450,7 @@ public final class AppUpdateStatusManager {
void clearAllInstalled() { void clearAllInstalled() {
synchronized (appMapping) { 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(); Map.Entry<String, AppUpdateStatus> entry = it.next();
if (entry.getValue().status == Status.Installed) { if (entry.getValue().status == Status.Installed) {
it.remove(); it.remove();
@ -517,6 +522,7 @@ public final class AppUpdateStatusManager {
* being more permanent than the notification info. As such, the different clients should be * 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 * aware of their requirements when invoking general-sounding methods like "addApk()", rather
* than this class trying to second-guess why they added an apk. * than this class trying to second-guess why they added an apk.
*
* @see #isPendingInstall(String) * @see #isPendingInstall(String)
*/ */
public void markAsPendingInstall(String uniqueKey) { public void markAsPendingInstall(String uniqueKey) {

View File

@ -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 * run on a background thread, as it hits the disk a bit to figure out the hash of each downloaded
* file. * file.
*/ */
@SuppressWarnings("LineLength")
public class AppUpdateStatusService extends IntentService { public class AppUpdateStatusService extends IntentService {
private static final String TAG = "AppUpdateStatusService"; private static final String TAG = "AppUpdateStatusService";

View File

@ -290,7 +290,7 @@ public class FDroidApp extends Application {
String fileNameToSanitize; String fileNameToSanitize;
Uri uri = Uri.parse(imageUri); Uri uri = Uri.parse(imageUri);
if (TextUtils.isEmpty(uri.getPath())) { 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("[:/]", ""); fileNameToSanitize = imageUri.replaceAll("[:/]", "");
} else { } else {
fileNameToSanitize = uri.getPath().replace("/", "-"); fileNameToSanitize = uri.getPath().replace("/", "-");

View File

@ -33,6 +33,7 @@ import org.fdroid.fdroid.views.main.MainActivity;
import java.util.ArrayList; import java.util.ArrayList;
@SuppressWarnings("LineLength")
class NotificationHelper { class NotificationHelper {
static final String BROADCAST_NOTIFICATIONS_ALL_UPDATES_CLEARED = "org.fdroid.fdroid.installer.notifications.allupdates.cleared"; static final String BROADCAST_NOTIFICATIONS_ALL_UPDATES_CLEARED = "org.fdroid.fdroid.installer.notifications.allupdates.cleared";

View File

@ -5,6 +5,7 @@ import android.content.SharedPreferences;
import android.os.Build; import android.os.Build;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
import info.guardianproject.netcipher.NetCipher;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Proxy; import java.net.Proxy;
@ -16,8 +17,6 @@ import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import info.guardianproject.netcipher.NetCipher;
/** /**
* Handles shared preferences for FDroid, looking after the names of * Handles shared preferences for FDroid, looking after the names of
* preferences, default values and caching. Needs to be setup in the FDroidApp * 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() { public boolean filterAppsWithAntiFeatures() {
if (!isInitialized(PREF_HIDE_ANTI_FEATURE_APPS)) { if (!isInitialized(PREF_HIDE_ANTI_FEATURE_APPS)) {
initialize(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; return filterAppsWithAntiFeatures;
} }

View File

@ -56,6 +56,7 @@ import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@SuppressWarnings("LineLength")
public class UpdateService extends IntentService { public class UpdateService extends IntentService {
private static final String TAG = "UpdateService"; private static final String TAG = "UpdateService";

View File

@ -244,7 +244,8 @@ public class Apk extends ValueObject implements Comparable<Apk>, Parcelable {
private void checkRepoAddress() { private void checkRepoAddress() {
if (repoAddress == null || apkName == null) { 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.");
} }
} }

View File

@ -20,6 +20,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@SuppressWarnings("LineLength")
public class ApkProvider extends FDroidProvider { public class ApkProvider extends FDroidProvider {
private static final String TAG = "ApkProvider"; private static final String TAG = "ApkProvider";
@ -88,7 +89,8 @@ public class ApkProvider extends FDroidProvider {
return cursorToList(cursor); 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); final Uri uri = getApkFromAnyRepoUri(packageName, versionCode);
return findByUri(context, uri, projection); 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 * 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 * {@link org.fdroid.fdroid.data.ApkProvider#MAX_APKS_TO_QUERY}. Instead of using
* this directly, think about 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) { static Uri getContentUri(List<Apk> apks) {
return getContentUri().buildUpon() return getContentUri().buildUpon()

View File

@ -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 * {@code AndroidManifest.xml}. If {@code targetSdkVersion} is not set, then it is
* equal to {@code minSdkVersion} * equal to {@code minSdkVersion}
* *
* @see <a href="https://developer.android.com/guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt; element</a> * @see <a href="https://developer.android.com/guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk&gt;</a>
*/ */
private static int[] getMinTargetMaxSdkVersions(Context context, String packageName) { private static int[] getMinTargetMaxSdkVersions(Context context, String packageName) {
int minSdkVersion = Apk.SDK_VERSION_MIN_VALUE; int minSdkVersion = Apk.SDK_VERSION_MIN_VALUE;

View File

@ -7,14 +7,14 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.fdroid.fdroid.data.Schema.AppPrefsTable; import org.fdroid.fdroid.data.Schema.AppPrefsTable;
import org.fdroid.fdroid.data.Schema.AppPrefsTable.Cols; import org.fdroid.fdroid.data.Schema.AppPrefsTable.Cols;
public class AppPrefsProvider extends FDroidProvider { public class AppPrefsProvider extends FDroidProvider {
public static final class Helper { public static final class Helper {
private Helper() { } private Helper() {
}
public static void update(Context context, App app, AppPrefs prefs) { public static void update(Context context, App app, AppPrefs prefs) {
ContentValues values = new ContentValues(3); ContentValues values = new ContentValues(3);
@ -37,7 +37,8 @@ public class AppPrefsProvider extends FDroidProvider {
@Nullable @Nullable
public static AppPrefs getPrefsOrNull(Context context, App app) { 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) { if (cursor == null) {
return null; return null;
} }
@ -114,7 +115,8 @@ public class AppPrefsProvider extends FDroidProvider {
} }
@Override @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) { if (MATCHER.match(uri) != CODE_SINGLE) {
throw new UnsupportedOperationException("Invalid URI for app content provider: " + uri); throw new UnsupportedOperationException("Invalid URI for app content provider: " + uri);
} }

View File

@ -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 * 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. * in the result set should be populated from the repository with the best priority.
*/ */
@SuppressWarnings("LineLength")
public class AppProvider extends FDroidProvider { public class AppProvider extends FDroidProvider {
private static final String TAG = "AppProvider"; private static final String TAG = "AppProvider";

View File

@ -6,17 +6,17 @@ import android.content.UriMatcher;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.NonNull; 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.CatJoinTable;
import org.fdroid.fdroid.data.Schema.CategoryTable; 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.CategoryTable.Cols;
import org.fdroid.fdroid.data.Schema.PackageTable;
public class CategoryProvider extends FDroidProvider { public class CategoryProvider extends FDroidProvider {
public static final class Helper { public static final class Helper {
private Helper() { } private Helper() {
}
public static long ensureExists(Context context, String category) { public static long ensureExists(Context context, String category) {
long id = getCategoryId(context, category); long id = getCategoryId(context, category);
@ -30,8 +30,9 @@ public class CategoryProvider extends FDroidProvider {
} }
public static long getCategoryId(Context context, String category) { public static long getCategoryId(Context context, String category) {
String[] projection = new String[] {Cols.ROW_ID}; String[] projection = new String[]{Cols.ROW_ID};
Cursor cursor = context.getContentResolver().query(getCategoryUri(category), projection, null, null, null); Cursor cursor = context.getContentResolver().query(getCategoryUri(category), projection,
null, null, null);
if (cursor == null) { if (cursor == null) {
return 0; return 0;
} }
@ -70,8 +71,10 @@ public class CategoryProvider extends FDroidProvider {
public void setOnlyCategoriesWithApps() { public void setOnlyCategoriesWithApps() {
// Make sure that metadata from the preferred repository is used to determine if // Make sure that metadata from the preferred repository is used to determine if
// there is an app present or not. // there is an app present or not.
join(AppMetadataTable.NAME, "app", "app." + AppMetadataTable.Cols.ROW_ID + " = " + CatJoinTable.NAME + "." + CatJoinTable.Cols.APP_METADATA_ID); join(AppMetadataTable.NAME, "app", "app." + AppMetadataTable.Cols.ROW_ID
join(PackageTable.NAME, "pkg", "pkg." + PackageTable.Cols.PREFERRED_METADATA + " = " + "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 @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); QuerySelection selection = new QuerySelection(customSelection, selectionArgs);
boolean onlyCategoriesWithApps = false; boolean onlyCategoriesWithApps = false;
switch (MATCHER.match(uri)) { switch (MATCHER.match(uri)) {

View File

@ -45,6 +45,7 @@ import org.fdroid.fdroid.data.Schema.RepoTable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@SuppressWarnings("LineLength")
class DBHelper extends SQLiteOpenHelper { class DBHelper extends SQLiteOpenHelper {
private static final String TAG = "DBHelper"; private static final String TAG = "DBHelper";

View File

@ -163,6 +163,7 @@ public abstract class FDroidProvider extends ContentProvider {
* when all you have is the package name. * when all you have is the package name.
*/ */
protected static String getPackageIdFromPackageNameQuery() { 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 + " = ?";
} }
} }

View File

@ -11,7 +11,6 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Schema.InstalledAppTable; 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 PROVIDER_NAME = "InstalledAppProvider";
private static final String PATH_SEARCH = "search"; 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); private static final UriMatcher MATCHER = new UriMatcher(-1);
@ -100,9 +99,9 @@ public class InstalledAppProvider extends FDroidProvider {
public static Uri getSearchUri(String keywords) { public static Uri getSearchUri(String keywords) {
return getContentUri().buildUpon() return getContentUri().buildUpon()
.appendPath(PATH_SEARCH) .appendPath(PATH_SEARCH)
.appendPath(keywords) .appendPath(keywords)
.build(); .build();
} }
public static String getApplicationLabel(Context context, String packageName) { public static String getApplicationLabel(Context context, String packageName) {
@ -146,7 +145,8 @@ public class InstalledAppProvider extends FDroidProvider {
} }
@Override @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) { if (sortOrder == null) {
sortOrder = Cols.APPLICATION_LABEL; sortOrder = Cols.APPLICATION_LABEL;
} }
@ -170,7 +170,8 @@ public class InstalledAppProvider extends FDroidProvider {
throw new UnsupportedOperationException(message); 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); cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor; return cursor;
} }
@ -207,7 +208,8 @@ public class InstalledAppProvider extends FDroidProvider {
*/ */
@Override @Override
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { 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.");
} }
/** /**

View File

@ -41,6 +41,7 @@ import rx.subjects.PublishSubject;
* {@link #deleteAppFromDb(Context, String)} are both static methods to enable easy testing * {@link #deleteAppFromDb(Context, String)} are both static methods to enable easy testing
* of this stuff. * of this stuff.
*/ */
@SuppressWarnings("LineLength")
public class InstalledAppProviderService extends IntentService { public class InstalledAppProviderService extends IntentService {
private static final String TAG = "InstalledAppProviderSer"; private static final String TAG = "InstalledAppProviderSer";
@ -93,7 +94,8 @@ public class InstalledAppProviderService extends IntentService {
.subscribe(new Action1<String>() { .subscribe(new Action1<String>() {
@Override @Override
public void call(String packageName) { public void call(String packageName) {
getContentResolver().notifyChange(AppProvider.getHighestPriorityMetadataUri(packageName), null); getContentResolver()
.notifyChange(AppProvider.getHighestPriorityMetadataUri(packageName), null);
} }
}); });
} }

View File

@ -19,7 +19,8 @@ import org.fdroid.fdroid.Utils;
* LEFT JOIN fdroid_apk ON (fdroid_apk.appId = fdroid_app.rowid) * 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_repo ON (fdroid_apk.repo = fdroid_repo._id)
* LEFT JOIN fdroid_installedApp AS installed ON (installed.appId = fdroid_app.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 * WHERE
* fdroid_repo.isSwap = 0 OR fdroid_repo.isSwap IS NULL * fdroid_repo.isSwap = 0 OR fdroid_repo.isSwap IS NULL
* GROUP BY fdroid_app.rowid * GROUP BY fdroid_app.rowid

View File

@ -5,14 +5,14 @@ import android.content.Context;
import android.content.UriMatcher; import android.content.UriMatcher;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import org.fdroid.fdroid.data.Schema.PackageTable; import org.fdroid.fdroid.data.Schema.PackageTable;
import org.fdroid.fdroid.data.Schema.PackageTable.Cols; import org.fdroid.fdroid.data.Schema.PackageTable.Cols;
public class PackageProvider extends FDroidProvider { public class PackageProvider extends FDroidProvider {
public static final class Helper { public static final class Helper {
private Helper() { } private Helper() {
}
public static long ensureExists(Context context, String packageName) { public static long ensureExists(Context context, String packageName) {
long id = getPackageId(context, packageName); long id = getPackageId(context, packageName);
@ -26,8 +26,9 @@ public class PackageProvider extends FDroidProvider {
} }
public static long getPackageId(Context context, String packageName) { public static long getPackageId(Context context, String packageName) {
String[] projection = new String[] {Cols.ROW_ID}; String[] projection = new String[]{Cols.ROW_ID};
Cursor cursor = context.getContentResolver().query(getPackageUri(packageName), projection, null, null, null); Cursor cursor = context.getContentResolver().query(getPackageUri(packageName), projection,
null, null, null);
if (cursor == null) { if (cursor == null) {
return 0; return 0;
} }
@ -122,7 +123,8 @@ public class PackageProvider extends FDroidProvider {
} }
@Override @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) { if (MATCHER.match(uri) != CODE_SINGLE) {
throw new UnsupportedOperationException("Invalid URI for content provider: " + uri); throw new UnsupportedOperationException("Invalid URI for content provider: " + uri);
} }

View File

@ -47,7 +47,7 @@ abstract class QueryBuilder {
} }
protected final void appendField(String field, String tableAlias, protected final void appendField(String field, String tableAlias,
String fieldAlias) { String fieldAlias) {
StringBuilder fieldBuilder = new StringBuilder(); StringBuilder fieldBuilder = new StringBuilder();
@ -121,17 +121,17 @@ abstract class QueryBuilder {
private void joinWithType(String type, String table, String alias, String condition) { private void joinWithType(String type, String table, String alias, String condition) {
tables.append(' ') tables.append(' ')
.append(type) .append(type)
.append(" JOIN ") .append(" JOIN ")
.append(table); .append(table);
if (alias != null) { if (alias != null) {
tables.append(" AS ").append(alias); tables.append(" AS ").append(alias);
} }
tables.append(" ON (") tables.append(" ON (")
.append(condition) .append(condition)
.append(')'); .append(')');
} }
private String distinctSql() { private String distinctSql() {
@ -166,6 +166,7 @@ abstract class QueryBuilder {
} }
public String toString() { public String toString() {
return "SELECT " + distinctSql() + fieldsSql() + " FROM " + tablesSql() + whereSql() + groupBySql() + orderBySql() + limitSql(); return "SELECT " + distinctSql() + fieldsSql() + " FROM " + tablesSql()
+ whereSql() + groupBySql() + orderBySql() + limitSql();
} }
} }

View File

@ -18,6 +18,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@SuppressWarnings("LineLength")
public class RepoPersister { public class RepoPersister {
private static final String TAG = "RepoPersister"; private static final String TAG = "RepoPersister";

View File

@ -10,7 +10,6 @@ import android.net.Uri;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Schema.RepoTable; import org.fdroid.fdroid.data.Schema.RepoTable;
import org.fdroid.fdroid.data.Schema.RepoTable.Cols; 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 static final String TAG = "RepoProvider.Helper";
private Helper() { } private Helper() {
}
/** /**
* Find by the content URI of a repo ({@link RepoProvider#getContentUri(long)}). * 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 * 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 * 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. * could serve the file at the given URL.
* * <p>
* For any given HTTP resource requested by F-Droid, it should belong to a repository. * 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 * 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 * repository. Therefore, that repository must exist in the database. The way to find out
* which repository a particular URL came from requires some consideration: * which repository a particular URL came from requires some consideration:
* * Repositories can exist at particular paths on a server (e.g. /fdroid/repo) * <li>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>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 * 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 * 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". * 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. * each of the CRUD methods available in the helper class.
*/ */
public static Uri insert(Context context, public static Uri insert(Context context,
ContentValues values) { ContentValues values) {
ContentResolver resolver = context.getContentResolver(); ContentResolver resolver = context.getContentResolver();
Uri uri = RepoProvider.getContentUri(); Uri uri = RepoProvider.getContentUri();
return resolver.insert(uri, values); return resolver.insert(uri, values);
@ -258,7 +259,8 @@ public class RepoProvider extends FDroidProvider {
ContentResolver resolver = context.getContentResolver(); ContentResolver resolver = context.getContentResolver();
final String[] projection = {Cols.LAST_UPDATED}; final String[] projection = {Cols.LAST_UPDATED};
final String selection = Cols.IN_USE + " = 1"; 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; Date lastUpdate = null;
if (cursor != null) { if (cursor != null) {
@ -347,7 +349,8 @@ public class RepoProvider extends FDroidProvider {
} }
@Override @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)) { if (TextUtils.isEmpty(sortOrder)) {
sortOrder = Cols.PRIORITY + " ASC"; sortOrder = Cols.PRIORITY + " ASC";
@ -360,7 +363,7 @@ public class RepoProvider extends FDroidProvider {
case CODE_SINGLE: case CODE_SINGLE:
selection = (selection == null ? "" : selection + " AND ") + selection = (selection == null ? "" : selection + " AND ") +
Cols._ID + " = " + uri.getLastPathSegment(); Cols._ID + " = " + uri.getLastPathSegment();
break; break;
case CODE_ALL_EXCEPT_SWAP: case CODE_ALL_EXCEPT_SWAP:
@ -372,7 +375,8 @@ public class RepoProvider extends FDroidProvider {
throw new UnsupportedOperationException("Invalid URI for repo content provider: " + uri); 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); cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor; return cursor;
} }
@ -415,7 +419,8 @@ public class RepoProvider extends FDroidProvider {
} }
private int getMaxPriority() { 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(); cursor.moveToFirst();
int max = cursor.getInt(0); int max = cursor.getInt(0);
cursor.close(); cursor.close();
@ -432,7 +437,7 @@ public class RepoProvider extends FDroidProvider {
return 0; return 0;
case CODE_SINGLE: case CODE_SINGLE:
selection = selection.add(Cols._ID + " = ?", new String[] {uri.getLastPathSegment()}); selection = selection.add(Cols._ID + " = ?", new String[]{uri.getLastPathSegment()});
break; break;
default: default:
@ -464,7 +469,8 @@ public class RepoProvider extends FDroidProvider {
// to be recalculated. // to be recalculated.
boolean priorityChanged = false; boolean priorityChanged = false;
if (values.containsKey(Cols.PRIORITY)) { 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) { if (priorityCursor.getCount() > 0) {
priorityCursor.moveToFirst(); priorityCursor.moveToFirst();
int oldPriority = priorityCursor.getInt(priorityCursor.getColumnIndex(Cols.PRIORITY)); int oldPriority = priorityCursor.getInt(priorityCursor.getColumnIndex(Cols.PRIORITY));

View File

@ -13,6 +13,7 @@ import java.util.List;
/** /**
* This class does all of its operations in a temporary sqlite table. * This class does all of its operations in a temporary sqlite table.
*/ */
@SuppressWarnings("LineLength")
public class TempApkProvider extends ApkProvider { public class TempApkProvider extends ApkProvider {
private static final String PROVIDER_NAME = "TempApkProvider"; private static final String PROVIDER_NAME = "TempApkProvider";

View File

@ -8,9 +8,6 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteException;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import java.util.List;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Schema.ApkTable; import org.fdroid.fdroid.data.Schema.ApkTable;
import org.fdroid.fdroid.data.Schema.AppMetadataTable; 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.CatJoinTable;
import org.fdroid.fdroid.data.Schema.PackageTable; import org.fdroid.fdroid.data.Schema.PackageTable;
import java.util.List;
/** /**
* This class does all of its operations in a temporary sqlite table. * This class does all of its operations in a temporary sqlite table.
*/ */
@SuppressWarnings("LineLength")
public class TempAppProvider extends AppProvider { public class TempAppProvider extends AppProvider {
/** /**
@ -94,7 +94,7 @@ public class TempAppProvider extends AppProvider {
} }
private AppQuerySelection queryRepo(long repoId) { 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 + " = ? "; String selection = getTableName() + "." + Cols.REPO_ID + " = ? ";
return new AppQuerySelection(selection, args); return new AppQuerySelection(selection, args);
} }
@ -111,7 +111,8 @@ public class TempAppProvider extends AppProvider {
TempApkProvider.Helper.init(context); 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); Uri uri = getAppsUri(packageNames, repoId);
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
return AppProvider.Helper.cursorToList(cursor); return AppProvider.Helper.cursorToList(cursor);
@ -167,7 +168,8 @@ public class TempAppProvider extends AppProvider {
values.remove(Cols.Package.PACKAGE_NAME); values.remove(Cols.Package.PACKAGE_NAME);
if (values.containsKey(Cols.ForWriting.Categories.CATEGORIES)) { 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); ensureCategories(categories, packageName, repoId);
values.remove(Cols.ForWriting.Categories.CATEGORIES); values.remove(Cols.ForWriting.Categories.CATEGORIES);
} }
@ -192,7 +194,8 @@ public class TempAppProvider extends AppProvider {
} }
@Override @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); AppQuerySelection selection = new AppQuerySelection(customSelection, selectionArgs);
switch (MATCHER.match(uri)) { switch (MATCHER.match(uri)) {
case APPS: case APPS:

View File

@ -23,9 +23,7 @@ import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.net.Uri; import android.net.Uri;
import com.nostra13.universalimageloader.utils.StorageUtils; import com.nostra13.universalimageloader.utils.StorageUtils;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.fdroid.fdroid.Hasher; import org.fdroid.fdroid.Hasher;
import org.fdroid.fdroid.data.Apk; 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 * verify the hash after copying. This is because we are copying from an installed apk, which
* other apps do not have permission to modify. * 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; ApplicationInfo appInfo = packageInfo.applicationInfo;
CharSequence name = context.getPackageManager().getApplicationLabel(appInfo); CharSequence name = context.getPackageManager().getApplicationLabel(appInfo);
String apkFileName = name + "-" + packageInfo.versionName + ".apk"; String apkFileName = name + "-" + packageInfo.versionName + ".apk";
@ -60,7 +59,8 @@ public class ApkCache {
*/ */
public static SanitizedFile copyApkFromCacheToFiles(Context context, File apkFile, Apk expectedApk) public static SanitizedFile copyApkFromCacheToFiles(Context context, File apkFile, Apk expectedApk)
throws IOException { 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 name = app == null ? expectedApk.packageName : app.name;
String apkFileName = name + "-" + expectedApk.versionName + ".apk"; String apkFileName = name + "-" + expectedApk.versionName + ".apk";
return copyApkToFiles(context, apkFile, apkFileName, true, expectedApk.hash, expectedApk.hashType); 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. * 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 * @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, * 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 * if the app was installed from part of the system where it can't be tampered
* with (e.g. installed apks on disk) then * 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 { throws IOException {
SanitizedFile sanitizedApkFile = new SanitizedFile(context.getFilesDir(), destinationName); SanitizedFile sanitizedApkFile = new SanitizedFile(context.getFilesDir(), destinationName);

View File

@ -24,7 +24,6 @@ import android.content.Context;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.Signature; import android.content.pm.Signature;
import org.acra.ACRA; import org.acra.ACRA;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.spongycastle.util.encoders.Hex; import org.spongycastle.util.encoders.Hex;
@ -54,7 +53,8 @@ class ApkSignatureVerifier {
public boolean hasFDroidSignature(File apkFile) { public boolean hasFDroidSignature(File apkFile) {
if (!apkFile.exists()) { if (!apkFile.exists()) {
ACRA.getErrorReporter().handleException( 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 false
); );
@ -77,7 +77,8 @@ class ApkSignatureVerifier {
private byte[] getApkSignature(File apkFile) { private byte[] getApkSignature(File apkFile) {
final String pkgPath = apkFile.getAbsolutePath(); final String pkgPath = apkFile.getAbsolutePath();
if (!apkFile.exists()) { 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); PackageInfo pkgInfo = pm.getPackageArchiveInfo(pkgPath, PackageManager.GET_SIGNATURES);

View File

@ -30,7 +30,6 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.Apk;
@ -40,8 +39,10 @@ import org.fdroid.fdroid.data.Apk;
public class DefaultInstallerActivity extends FragmentActivity { public class DefaultInstallerActivity extends FragmentActivity {
private static final String TAG = "DefaultInstallerActivit"; private static final String TAG = "DefaultInstallerActivit";
static final String ACTION_INSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.INSTALL_PACKAGE"; static final String ACTION_INSTALL_PACKAGE
static final String ACTION_UNINSTALL_PACKAGE = "org.fdroid.fdroid.installer.DefaultInstaller.action.UNINSTALL_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_INSTALL = 0;
private static final int REQUEST_CODE_UNINSTALL = 1; private static final int REQUEST_CODE_UNINSTALL = 1;

View File

@ -62,6 +62,7 @@ import java.io.IOException;
* *
* @see <a href="https://developer.android.com/google/play/expansion-files.html">APK Expansion Files</a> * @see <a href="https://developer.android.com/google/play/expansion-files.html">APK Expansion Files</a>
*/ */
@SuppressWarnings("LineLength")
public class InstallManagerService extends Service { public class InstallManagerService extends Service {
private static final String TAG = "InstallManagerService"; private static final String TAG = "InstallManagerService";

View File

@ -45,6 +45,7 @@ import java.io.IOException;
/** /**
* Handles the actual install process. Subclasses implement the details. * Handles the actual install process. Subclasses implement the details.
*/ */
@SuppressWarnings("LineLength")
public abstract class Installer { public abstract class Installer {
private static final String TAG = "Installer"; private static final String TAG = "Installer";

View File

@ -66,8 +66,10 @@ public class PrivilegedInstaller extends Installer {
private static final String TAG = "PrivilegedInstaller"; private static final String TAG = "PrivilegedInstaller";
private static final String PRIVILEGED_EXTENSION_SERVICE_INTENT = "org.fdroid.fdroid.privileged.IPrivilegedService"; private static final String PRIVILEGED_EXTENSION_SERVICE_INTENT
public static final String PRIVILEGED_EXTENSION_PACKAGE_NAME = "org.fdroid.fdroid.privileged"; = "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_NO = 0;
public static final int IS_EXTENSION_INSTALLED_YES = 1; public static final int IS_EXTENSION_INSTALLED_YES = 1;

View File

@ -54,6 +54,7 @@ import kellinwood.security.zipsigner.ZipSigner;
// TODO Address exception handling in a uniform way throughout // TODO Address exception handling in a uniform way throughout
@SuppressWarnings("LineLength")
public final class LocalRepoKeyStore { public final class LocalRepoKeyStore {
private static final String TAG = "LocalRepoKeyStore"; private static final String TAG = "LocalRepoKeyStore";

View File

@ -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 * 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. * and the relevant .apk and icon files available.
*/ */
@SuppressWarnings("LineLength")
public final class LocalRepoManager { public final class LocalRepoManager {
private static final String TAG = "LocalRepoManager"; private static final String TAG = "LocalRepoManager";

View File

@ -65,6 +65,7 @@ import rx.schedulers.Schedulers;
* Central service which manages all of the different moving parts of swap which are required * Central service which manages all of the different moving parts of swap which are required
* to enable p2p swapping of apps. * to enable p2p swapping of apps.
*/ */
@SuppressWarnings("LineLength")
public class SwapService extends Service { public class SwapService extends Service {
private static final String TAG = "SwapService"; private static final String TAG = "SwapService";

View File

@ -16,6 +16,7 @@ import rx.Subscriber;
import rx.functions.Action0; import rx.functions.Action0;
import rx.subscriptions.Subscriptions; import rx.subscriptions.Subscriptions;
@SuppressWarnings("LineLength")
final class BluetoothFinder extends PeerFinder { final class BluetoothFinder extends PeerFinder {
public static Observable<Peer> createBluetoothObservable(final Context context) { public static Observable<Peer> createBluetoothObservable(final Context context) {

View File

@ -31,7 +31,9 @@ public class BluetoothPeer implements Peer {
@Override @Override
public boolean equals(Object peer) { 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 @Override

View File

@ -19,6 +19,7 @@ import rx.Subscriber;
import rx.functions.Action0; import rx.functions.Action0;
import rx.subscriptions.Subscriptions; import rx.subscriptions.Subscriptions;
@SuppressWarnings("LineLength")
final class BonjourFinder extends PeerFinder implements ServiceListener { final class BonjourFinder extends PeerFinder implements ServiceListener {
public static Observable<Peer> createBonjourObservable(final Context context) { public static Observable<Peer> createBonjourObservable(final Context context) {

View File

@ -13,6 +13,7 @@ import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapService; import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.net.bluetooth.BluetoothServer; import org.fdroid.fdroid.net.bluetooth.BluetoothServer;
@SuppressWarnings("LineLength")
public final class BluetoothSwap extends SwapType { public final class BluetoothSwap extends SwapType {
private static final String TAG = "BluetoothSwap"; private static final String TAG = "BluetoothSwap";

View File

@ -3,20 +3,18 @@ package org.fdroid.fdroid.localrepo.type;
import android.content.Context; import android.content.Context;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapService; import org.fdroid.fdroid.localrepo.SwapService;
import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.HashMap; 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. * 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(); InetAddress address = getDeviceAddress();
if (address == null) { 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; return;
} }
@ -103,7 +102,8 @@ public class BonjourBroadcast extends SwapType {
if (FDroidApp.ipAddressString != null) { if (FDroidApp.ipAddressString != null) {
try { try {
return InetAddress.getByName(FDroidApp.ipAddressString); return InetAddress.getByName(FDroidApp.ipAddressString);
} catch (UnknownHostException ignored) { } } catch (UnknownHostException ignored) {
}
} }
return null; return null;

View File

@ -26,6 +26,7 @@ import rx.functions.Action1;
import rx.functions.Func2; import rx.functions.Func2;
import rx.schedulers.Schedulers; import rx.schedulers.Schedulers;
@SuppressWarnings("LineLength")
public class WifiSwap extends SwapType { public class WifiSwap extends SwapType {
private static final String TAG = "WifiSwap"; private static final String TAG = "WifiSwap";

View File

@ -143,7 +143,8 @@ public abstract class Downloader {
* keeping track of the number of bytes that have flowed through for the * keeping track of the number of bytes that have flowed through for the
* progress counter. * 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(); Timer timer = new Timer();
try { try {
bytesRead = 0; bytesRead = 0;

View File

@ -131,13 +131,15 @@ public class DownloaderService extends Service {
Utils.debugLog(TAG, "Cancelling download of " + uriString); Utils.debugLog(TAG, "Cancelling download of " + uriString);
Integer whatToRemove = uriString.hashCode(); Integer whatToRemove = uriString.hashCode();
if (serviceHandler.hasMessages(whatToRemove)) { 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); serviceHandler.removeMessages(whatToRemove);
sendBroadcast(intent.getData(), Downloader.ACTION_INTERRUPTED); sendBroadcast(intent.getData(), Downloader.ACTION_INTERRUPTED);
} else if (isActive(uriString)) { } else if (isActive(uriString)) {
downloader.cancelDownload(); downloader.cancelDownload();
} else { } 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())) { } else if (ACTION_QUEUE.equals(intent.getAction())) {
Message msg = serviceHandler.obtainMessage(); Message msg = serviceHandler.obtainMessage();

View File

@ -93,7 +93,8 @@ public class LocalHTTPD extends NanoHTTPD {
session.parseBody(new HashMap<String, String>()); session.parseBody(new HashMap<String, String>());
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "An error occured while parsing the POST body", 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) { } catch (ResponseException re) {
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage()); return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
} }
@ -108,8 +109,10 @@ public class LocalHTTPD extends NanoHTTPD {
switch (uri.getPath()) { switch (uri.getPath()) {
case "/request-swap": case "/request-swap":
if (!session.getParms().containsKey("repo")) { if (!session.getParms().containsKey("repo")) {
Log.e(TAG, "Malformed /request-swap request to local repo HTTP server. Should have posted a 'repo' parameter."); Log.e(TAG, "Malformed /request-swap request to local repo HTTP server."
return new Response(Response.Status.BAD_REQUEST, MIME_PLAINTEXT, "Requires 'repo' parameter to be posted."); + " 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")); requestSwap(session.getParms().get("repo"));
return new Response(Response.Status.OK, MIME_PLAINTEXT, "Swap request received."); return new Response(Response.Status.OK, MIME_PLAINTEXT, "Swap request received.");

View File

@ -41,6 +41,7 @@ import java.util.Locale;
* changed. Having the {@code Thread} also makes it easy to kill work * changed. Having the {@code Thread} also makes it easy to kill work
* that is in progress. * that is in progress.
*/ */
@SuppressWarnings("LineLength")
public class WifiStateChangeService extends IntentService { public class WifiStateChangeService extends IntentService {
private static final String TAG = "WifiStateChangeService"; private static final String TAG = "WifiStateChangeService";

View File

@ -39,7 +39,7 @@ public class BluetoothClient {
throw e1; 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<?> clazz = socket.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[]{Integer.TYPE}; Class<?>[] paramTypes = new Class<?>[]{Integer.TYPE};

View File

@ -26,6 +26,7 @@ import fi.iki.elonen.NanoHTTPD;
* Act as a layer on top of LocalHTTPD server, by forwarding requests served * Act as a layer on top of LocalHTTPD server, by forwarding requests served
* over bluetooth to that server. * over bluetooth to that server.
*/ */
@SuppressWarnings("LineLength")
public class BluetoothServer extends Thread { public class BluetoothServer extends Thread {
private static final String TAG = "BluetoothServer"; private static final String TAG = "BluetoothServer";

View File

@ -18,7 +18,7 @@ public final class Request {
public interface Methods { public interface Methods {
String HEAD = "HEAD"; String HEAD = "HEAD";
String GET = "GET"; String GET = "GET";
} }
private String method; private String method;
@ -73,10 +73,12 @@ public final class Request {
Utils.debugLog(TAG, "Read " + headers.size() + " headers"); Utils.debugLog(TAG, "Read " + headers.size() + " headers");
if (method.equals(Methods.HEAD)) { 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); 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()); return new Response(responseCode, headers, connection.getInputStream());
} }
@ -102,8 +104,8 @@ public final class Request {
return false; return false;
} }
method = parts[0].toUpperCase(Locale.ENGLISH); method = parts[0].toUpperCase(Locale.ENGLISH);
path = parts[1]; path = parts[1];
headers = readHeaders(); headers = readHeaders();
return true; return true;
} }

View File

@ -1,7 +1,6 @@
package org.fdroid.fdroid.net.bluetooth.httpish; package org.fdroid.fdroid.net.bluetooth.httpish;
import android.util.Log; import android.util.Log;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.net.bluetooth.BluetoothConnection; import org.fdroid.fdroid.net.bluetooth.BluetoothConnection;
import org.fdroid.fdroid.net.bluetooth.FileDetails; import org.fdroid.fdroid.net.bluetooth.FileDetails;
@ -99,7 +98,8 @@ public class Response {
public InputStream toContentStream() throws UnsupportedOperationException { public InputStream toContentStream() throws UnsupportedOperationException {
if (contentStream == null) { 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; return contentStream;
} }
@ -136,7 +136,8 @@ public class Response {
private int fileSize = -1; private int fileSize = -1;
private String etag; private String etag;
public Builder() { } public Builder() {
}
public Builder(InputStream contentStream) { public Builder(InputStream contentStream) {
this.contentStream = contentStream; this.contentStream = contentStream;

View File

@ -37,6 +37,7 @@ import eu.chainfire.libsuperuser.Shell;
* http://omerjerk.in/2014/08/how-to-install-an-app-to-system-partition/ * 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 * https://github.com/omerjerk/RemoteDroid/blob/master/app/src/main/java/in/omerjerk/remotedroid/app/MainActivity.java
*/ */
@SuppressWarnings("LineLength")
abstract class InstallExtension { abstract class InstallExtension {
final Context context; final Context context;

View File

@ -42,10 +42,9 @@ import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.Preferences.Theme; import org.fdroid.fdroid.Preferences.Theme;
import org.fdroid.fdroid.R;
import java.text.Collator; import java.text.Collator;
import java.util.ArrayList; import java.util.ArrayList;
@ -70,9 +69,9 @@ import java.util.Set;
* Based on AOSP core/java/android/widget/AppSecurityPermissions * Based on AOSP core/java/android/widget/AppSecurityPermissions
* latest included commit: a3f68ef2f6811cf72f1282214c0883db5a30901d * latest included commit: a3f68ef2f6811cf72f1282214c0883db5a30901d
* <p/> * <p/>
* To update this file: * To update this file, Start from latest included commit and include changes
* - Open https://github.com/android/platform_frameworks_base/commits/master/core/java/android/widget/AppSecurityPermissions.java * until the newest commit with care:
* - 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 { public class AppSecurityPermissions {
@ -92,6 +91,7 @@ public class AppSecurityPermissions {
// PermissionGroupInfo implements Parcelable but its Parcel constructor is private and thus cannot be extended. // PermissionGroupInfo implements Parcelable but its Parcel constructor is private and thus cannot be extended.
@SuppressLint("ParcelCreator") @SuppressLint("ParcelCreator")
@SuppressWarnings("LineLength")
static class MyPermissionGroupInfo extends PermissionGroupInfo { static class MyPermissionGroupInfo extends PermissionGroupInfo {
CharSequence label; CharSequence label;
@ -402,8 +402,8 @@ public class AppSecurityPermissions {
} }
} }
private PermissionItemView getPermissionItemView(MyPermissionGroupInfo grp, private PermissionItemView getPermissionItemView(MyPermissionGroupInfo grp, MyPermissionInfo perm,
MyPermissionInfo perm, boolean first, CharSequence newPermPrefix) { boolean first, CharSequence newPermPrefix) {
PermissionItemView permView = (PermissionItemView) inflater.inflate( PermissionItemView permView = (PermissionItemView) inflater.inflate(
Build.VERSION.SDK_INT >= 17 && Build.VERSION.SDK_INT >= 17 &&
(perm.flags & PermissionInfo.FLAG_COSTS_MONEY) != 0 (perm.flags & PermissionInfo.FLAG_COSTS_MONEY) != 0

View File

@ -36,11 +36,9 @@ import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TabHost; import android.widget.TabHost;
import android.widget.TextView; import android.widget.TextView;
import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageScaleType; import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.Apk;
@ -119,7 +117,8 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
scrollView.addView(perms.getPermissionsView( scrollView.addView(perms.getPermissionsView(
AppSecurityPermissions.WHICH_NEW)); AppSecurityPermissions.WHICH_NEW));
} else { } 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( adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator(
getText(R.string.newPerms)), scrollView); getText(R.string.newPerms)), scrollView);
@ -191,7 +190,8 @@ public class InstallConfirmActivity extends FragmentActivity implements OnCancel
intent = getIntent(); intent = getIntent();
Uri uri = intent.getData(); Uri uri = intent.getData();
Apk apk = ApkProvider.Helper.findByUri(this, uri, Schema.ApkTable.Cols.ALL); 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); appDiff = new AppDiff(getPackageManager(), apk);

View File

@ -53,6 +53,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@SuppressWarnings("LineLength")
public class AppDetailsRecyclerViewAdapter public class AppDetailsRecyclerViewAdapter
extends RecyclerView.Adapter<RecyclerView.ViewHolder> { extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

View File

@ -8,7 +8,6 @@ import android.support.v4.content.LocalBroadcastManager;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService; import org.fdroid.fdroid.UpdateService;
@ -53,7 +52,8 @@ public class BannerUpdatingRepos extends android.support.v7.widget.AppCompatText
return; 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()); setBannerIsVisible(UpdateService.isUpdating());
} }

View File

@ -7,6 +7,7 @@ import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
@SuppressWarnings("LineLength")
public class LinearLayoutManagerSnapHelper extends LinearSnapHelper { public class LinearLayoutManagerSnapHelper extends LinearSnapHelper {
private View lastSavedTarget; private View lastSavedTarget;

View File

@ -50,7 +50,6 @@ import android.widget.EditText;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService; import org.fdroid.fdroid.UpdateService;
@ -70,6 +69,7 @@ import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.util.Locale; import java.util.Locale;
@SuppressWarnings("LineLength")
public class ManageReposActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>, RepoAdapter.EnabledListener { public class ManageReposActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>, RepoAdapter.EnabledListener {
private static final String TAG = "ManageReposActivity"; 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, * 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 * depending on if the incoming address is the same as a previous repo). It is responsible
* for managing the lifecycle of adding a repo: * for managing the lifecycle of adding a repo:
* * Showing the add dialog * <li>Showing the add dialog
* * Deciding whether to add a new repo or update an existing one * <li>Deciding whether to add a new repo or update an existing one
* * Search for repos at common suffixes (/, /fdroid/repo, /repo) * <li>Search for repos at common suffixes (/, /fdroid/repo, /repo)
*/ */
private class AddRepo { private class AddRepo {
@ -314,10 +314,12 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
final TextWatcher textChangedListener = new TextWatcher() { final TextWatcher textChangedListener = new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) { } public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override @Override
public void afterTextChanged(Editable s) { 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 * 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, * 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. * 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. * 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 * 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. * slashes in the path and replaces them with one. Finally, it removes trailing slashes.

View File

@ -406,7 +406,8 @@ public class RepoDetailsActivity extends ActionBarActivity {
} else { } 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();
} }
} }
}); });

View File

@ -1,6 +1,7 @@
package org.fdroid.fdroid.views; package org.fdroid.fdroid.views;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView; 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.R;
import org.fdroid.fdroid.data.App; 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 String[] screenshots;
private final DisplayImageOptions displayImageOptions; private final DisplayImageOptions displayImageOptions;
private View selectedView; private View selectedView;
@ -28,8 +30,9 @@ public class ScreenShotsRecyclerViewAdapter extends RecyclerView.Adapter<Recycle
super(); super();
screenshots = app.getAllScreenshots(context); screenshots = app.getAllScreenshots(context);
selectedPosition = 0; selectedPosition = 0;
selectedItemElevation = context.getResources().getDimensionPixelSize(R.dimen.details_screenshot_selected_elevation); Resources r = context.getResources();
unselectedItemMargin = context.getResources().getDimensionPixelSize(R.dimen.details_screenshot_margin); selectedItemElevation = r.getDimensionPixelSize(R.dimen.details_screenshot_selected_elevation);
unselectedItemMargin = r.getDimensionPixelSize(R.dimen.details_screenshot_margin);
displayImageOptions = new DisplayImageOptions.Builder() displayImageOptions = new DisplayImageOptions.Builder()
.cacheInMemory(true) .cacheInMemory(true)
.cacheOnDisk(true) .cacheOnDisk(true)

View File

@ -20,7 +20,6 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
@ -156,7 +155,9 @@ public class ShareChooserDialog extends BottomSheetDialogFragment {
@Override @Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) { 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); 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(); ShareChooserDialog d = new ShareChooserDialog();
d.setListener(listener); d.setListener(listener);
Bundle args = new Bundle(); Bundle args = new Bundle();

View File

@ -17,16 +17,18 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.Schema; 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_CATEGORY
public static final String EXTRA_SEARCH_TERMS = "org.fdroid.fdroid.views.apps.AppListActivity.EXTRA_SEARCH_TERMS"; = "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 RecyclerView appView;
private AppListAdapter appAdapter; private AppListAdapter appAdapter;

View File

@ -4,7 +4,6 @@ import android.app.Activity;
import android.database.Cursor; import android.database.Cursor;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.App;
@ -26,7 +25,8 @@ class AppListAdapter extends RecyclerView.Adapter<AppListItemController> {
@Override @Override
public AppListItemController onCreateViewHolder(ViewGroup parent, int viewType) { 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 @Override

View File

@ -46,6 +46,7 @@ import java.io.File;
import java.util.Iterator; import java.util.Iterator;
// TODO: Support cancelling of downloads by tapping the install button a second time. // TODO: Support cancelling of downloads by tapping the install button a second time.
@SuppressWarnings("LineLength")
public class AppListItemController extends RecyclerView.ViewHolder { public class AppListItemController extends RecyclerView.ViewHolder {
private static final String TAG = "AppListItemController"; private static final String TAG = "AppListItemController";

View File

@ -10,7 +10,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.text.style.ReplacementSpan; import android.text.style.ReplacementSpan;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.categories.CategoryController; import org.fdroid.fdroid.views.categories.CategoryController;
@ -74,7 +73,8 @@ public class CategorySpan extends ReplacementSpan {
} }
@Override @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); CharSequence categoryName = getCategoryName(text, start, end);
if (categoryName == null) { if (categoryName == null) {
return; return;
@ -94,7 +94,8 @@ public class CategorySpan extends ReplacementSpan {
canvas.save(); canvas.save();
canvas.translate(x, bottom - height + TEXT_BELOW_PADDING * density); 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. // The shadow below the entire category chip.
canvas.save(); canvas.save();

View File

@ -10,17 +10,16 @@ import android.text.Spanned;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.text.style.TtsSpan; import android.text.style.TtsSpan;
import android.widget.EditText; import android.widget.EditText;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
/** /**
* The search input treats text before the first colon as a category name. Text after this colon * 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. * (or all text if there is no colon) is the free text search terms.
* The behaviour of this search input is: * The behaviour of this search input is:
* * Replacing anything before the first colon with a {@link CategorySpan} that renders a "Chip" * * 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. * 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 * * Removing the trailing ":" from a category chip will cause it to remove the entire category
* from the input. * from the input.
*/ */
public class CategoryTextWatcher implements TextWatcher { public class CategoryTextWatcher implements TextWatcher {
@ -35,7 +34,8 @@ public class CategoryTextWatcher implements TextWatcher {
private int removeTo = -1; private int removeTo = -1;
private boolean requiresSpanRecalculation = false; 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.context = context;
this.widget = widget; this.widget = widget;
this.listener = listener; this.listener = listener;
@ -75,8 +75,10 @@ public class CategoryTextWatcher implements TextWatcher {
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) { public void onTextChanged(CharSequence s, int start, int before, int count) {
boolean addingOrReplacing = count > 0; boolean addingOrReplacing = count > 0;
boolean addingColon = addingOrReplacing && s.subSequence(start, start + count).toString().indexOf(':') >= 0; boolean addingColon = addingOrReplacing
boolean addingFirstColon = addingColon && s.subSequence(0, start).toString().indexOf(':') == -1; && s.subSequence(start, start + count).toString().indexOf(':') >= 0;
boolean addingFirstColon = addingColon
&& s.subSequence(0, start).toString().indexOf(':') == -1;
if (addingFirstColon) { if (addingFirstColon) {
requiresSpanRecalculation = true; requiresSpanRecalculation = true;
} }
@ -99,7 +101,8 @@ public class CategoryTextWatcher implements TextWatcher {
int colonIndex = searchText.toString().indexOf(':'); int colonIndex = searchText.toString().indexOf(':');
String category = colonIndex == -1 ? null : searchText.subSequence(0, colonIndex).toString(); 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); 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 // For accessibility reasons, make this more clear to screen readers that the
// span we just added semantically represents a category. // span we just added semantically represents a category.
CharSequence categoryName = textToSpannify.subSequence(0, colonIndex); 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); textToSpannify.setSpan(ttsSpan, 0, 0, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} }
} }

View File

@ -50,6 +50,7 @@ import java.util.Random;
* *
* It is suggested that you obtain the Palette from the icon of an app. * It is suggested that you obtain the Palette from the icon of an app.
*/ */
@SuppressWarnings("LineLength")
public class FeatureImage extends AppCompatImageView { public class FeatureImage extends AppCompatImageView {
private static final int NUM_SQUARES_WIDE = 4; private static final int NUM_SQUARES_WIDE = 4;

View File

@ -18,12 +18,10 @@ import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.fdroid.fdroid.AppDetails2; import org.fdroid.fdroid.AppDetails2;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; 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 * The {@link AppCardController} can bind an app to several different layouts, as long as the layout
* contains the following elements: * contains the following elements:
* + {@link R.id#icon} ({@link ImageView}, required) * + {@link R.id#icon} ({@link ImageView}, required)
* + {@link R.id#summary} ({@link TextView}, required) * + {@link R.id#summary} ({@link TextView}, required)
* + {@link R.id#new_tag} ({@link TextView}, optional) * + {@link R.id#new_tag} ({@link TextView}, optional)
* + {@link R.id#featured_image} ({@link ImageView}, 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. * 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.setColour(ContextCompat.getColor(activity, R.color.fdroid_blue));
featuredImage.setImageDrawable(null); 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 // 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 // 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 // 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 // from that icon and assign to the `FeatureImage` (or whether we should wait for the
// feature image to be loaded). // feature image to be loaded).
if (!TextUtils.isEmpty(app.featureGraphic)) { 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 intent = new Intent(activity, AppDetails2.class);
intent.putExtra(AppDetails2.EXTRA_APPID, currentApp.packageName); intent.putExtra(AppDetails2.EXTRA_APPID, currentApp.packageName);
if (Build.VERSION.SDK_INT >= 21) { 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>). @SuppressWarnings("unchecked") // the right type is passed as 2nd varargs arg: Pair<View, String>
Bundle bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, iconTransitionPair).toBundle(); Bundle b = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, iconTransitionPair).toBundle();
activity.startActivity(intent, b);
activity.startActivity(intent, bundle);
} else { } else {
activity.startActivity(intent); activity.startActivity(intent);
} }
@ -180,7 +181,10 @@ public class AppCardController extends RecyclerView.ViewHolder implements ImageL
@Override @Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { 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() { new Palette.Builder(loadedImage).generate(new Palette.PaletteAsyncListener() {
@Override @Override
public void onGenerated(Palette palette) { public void onGenerated(Palette palette) {

View File

@ -4,7 +4,6 @@ import android.app.Activity;
import android.database.Cursor; import android.database.Cursor;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.App;
@ -19,7 +18,8 @@ class AppPreviewAdapter extends RecyclerView.Adapter<AppCardController> {
@Override @Override
public AppCardController onCreateViewHolder(ViewGroup parent, int viewType) { 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 @Override

View File

@ -5,7 +5,6 @@ import android.support.annotation.NonNull;
import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import java.util.Collections; import java.util.Collections;
@ -26,7 +25,8 @@ public class CategoryAdapter extends RecyclerView.Adapter<CategoryController> {
@Override @Override
public CategoryController onCreateViewHolder(ViewGroup parent, int viewType) { 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 @Override

View File

@ -1,8 +1,9 @@
package org.fdroid.fdroid.views.categories; package org.fdroid.fdroid.views.categories;
import android.app.Activity; import android.app.Activity;
import android.content.Intent;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Color; import android.graphics.Color;
@ -20,12 +21,10 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageScaleType; import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer; import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.AppProvider;
import org.fdroid.fdroid.data.Schema; 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 * @param requiresLowerCaseId Previously categories were translated using strings such as "category_Reading"
* the "Reading" category. Now we also need to have drawable resources such as * 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 * "category_reading". Note how drawables must have only lower case letters, whereas
* we already have upper case letters in strings.xml. Hence this flag. * 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("'", ""); String suffix = categoryName.replace(" & ", "_").replace(" ", "_").replace("'", "");
if (requiresLowerCaseId) { if (requiresLowerCaseId) {
suffix = suffix.toLowerCase(Locale.ENGLISH); suffix = suffix.toLowerCase(Locale.ENGLISH);
@ -178,8 +178,11 @@ public class CategoryController extends RecyclerView.ViewHolder implements Loade
cursor.moveToFirst(); cursor.moveToFirst();
int numAppsInCategory = cursor.getInt(0); int numAppsInCategory = cursor.getInt(0);
viewAll.setVisibility(View.VISIBLE); viewAll.setVisibility(View.VISIBLE);
viewAll.setText(activity.getResources().getQuantityString(R.plurals.button_view_all_apps_in_category, numAppsInCategory, numAppsInCategory)); Resources r = activity.getResources();
viewAll.setContentDescription(activity.getResources().getQuantityString(R.plurals.tts_view_all_in_category, numAppsInCategory, numAppsInCategory, currentCategory)); 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 * 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. * 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
* @see org.fdroid.fdroid.R.dimen#category_preview__app_list__padding__horizontal__first * @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 @Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 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); Resources r = context.getResources();
int horizontalPaddingFirst = (int) context.getResources().getDimension(R.dimen.category_preview__app_list__padding__horizontal__first); 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; boolean isLtr = ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_LTR;
int itemPosition = parent.getChildLayoutPosition(view); int itemPosition = parent.getChildLayoutPosition(view);
boolean first = itemPosition == 0; boolean first = itemPosition == 0;

View File

@ -30,22 +30,22 @@ public class PreferencesFragment extends PreferenceFragment
implements SharedPreferences.OnSharedPreferenceChangeListener { implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String[] SUMMARIES_TO_UPDATE = { private static final String[] SUMMARIES_TO_UPDATE = {
Preferences.PREF_UPD_INTERVAL, Preferences.PREF_UPD_INTERVAL,
Preferences.PREF_UPD_WIFI_ONLY, Preferences.PREF_UPD_WIFI_ONLY,
Preferences.PREF_UPD_NOTIFY, Preferences.PREF_UPD_NOTIFY,
Preferences.PREF_ROOTED, Preferences.PREF_ROOTED,
Preferences.PREF_HIDE_ANTI_FEATURE_APPS, Preferences.PREF_HIDE_ANTI_FEATURE_APPS,
Preferences.PREF_INCOMP_VER, Preferences.PREF_INCOMP_VER,
Preferences.PREF_THEME, Preferences.PREF_THEME,
Preferences.PREF_IGN_TOUCH, Preferences.PREF_IGN_TOUCH,
Preferences.PREF_LOCAL_REPO_NAME, Preferences.PREF_LOCAL_REPO_NAME,
Preferences.PREF_LANGUAGE, Preferences.PREF_LANGUAGE,
Preferences.PREF_KEEP_CACHE_TIME, Preferences.PREF_KEEP_CACHE_TIME,
Preferences.PREF_EXPERT, Preferences.PREF_EXPERT,
Preferences.PREF_PRIVILEGED_INSTALLER, Preferences.PREF_PRIVILEGED_INSTALLER,
Preferences.PREF_ENABLE_PROXY, Preferences.PREF_ENABLE_PROXY,
Preferences.PREF_PROXY_HOST, Preferences.PREF_PROXY_HOST,
Preferences.PREF_PROXY_PORT, Preferences.PREF_PROXY_PORT,
}; };
private static final int REQUEST_INSTALL_ORBOT = 0x1234; private static final int REQUEST_INSTALL_ORBOT = 0x1234;
@ -180,8 +180,10 @@ public class PreferencesFragment extends PreferenceFragment
break; break;
case Preferences.PREF_PRIVILEGED_INSTALLER: 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. // We may have removed this preference if it is not suitable to show the user.
final CheckBoxPreference pref = (CheckBoxPreference) findPreference(Preferences.PREF_PRIVILEGED_INSTALLER); // So lets check it is here first.
final CheckBoxPreference pref = (CheckBoxPreference) findPreference(
Preferences.PREF_PRIVILEGED_INSTALLER);
if (pref != null) { if (pref != null) {
checkSummary(key, R.string.system_installer_on); checkSummary(key, R.string.system_installer_on);
} }

View File

@ -12,15 +12,13 @@ import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Toast; import android.widget.Toast;
import android.support.v7.widget.RecyclerView;
import com.ashokvarma.bottomnavigation.BadgeItem; import com.ashokvarma.bottomnavigation.BadgeItem;
import com.ashokvarma.bottomnavigation.BottomNavigationBar; import com.ashokvarma.bottomnavigation.BottomNavigationBar;
import com.ashokvarma.bottomnavigation.BottomNavigationItem; import com.ashokvarma.bottomnavigation.BottomNavigationItem;
import org.fdroid.fdroid.AppDetails2; import org.fdroid.fdroid.AppDetails2;
import org.fdroid.fdroid.AppUpdateStatusManager; import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.FDroidApp; 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. * Main view shown to users upon starting F-Droid.
* * <p>
* Shows a bottom navigation bar, with the following entries: * Shows a bottom navigation bar, with the following entries:
* + Whats new * + Whats new
* + Categories list * + Categories list
* + App swap * + App swap
* + Updates * + Updates
* + Settings * + Settings
* * <p>
* Users navigate between items by using the bottom navigation bar, or by swiping left and right. * 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 * When switching from one screen to the next, we stay within this activity. The new screen will
* get inflated (if required) * get inflated (if required)
*/ */
public class MainActivity extends AppCompatActivity implements BottomNavigationBar.OnTabSelectedListener { 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)) .addItem(new BottomNavigationItem(R.drawable.ic_settings, R.string.menu_settings))
.initialise(); .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); updateableAppsFilter.addAction(AppUpdateStatusManager.BROADCAST_APPSTATUS_CHANGED);
LocalBroadcastManager.getInstance(this).registerReceiver(onUpdateableAppsChanged, updateableAppsFilter); 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. * 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" * The ones we are interested in are those which would result in the "items requiring user interaction"
* to increase or decrease: * to increase or decrease:
* * Bulk updates of ready-to-install-apps (relating to {@link org.fdroid.fdroid.AppUpdateStatusService}. * * Bulk updates of ready-to-install-apps (relating to {@link org.fdroid.fdroid.AppUpdateStatusService}.
* * Change in status to: * * Change in status to:
* * {@link AppUpdateStatusManager.Status#ReadyToInstall} (Causes the count to go UP by one) * * {@link AppUpdateStatusManager.Status#ReadyToInstall} (Causes the count to go UP by one)
* * {@link AppUpdateStatusManager.Status#Installed} (Causes the count to go DOWN by one) * * {@link AppUpdateStatusManager.Status#Installed} (Causes the count to go DOWN by one)
*/ */
private final BroadcastReceiver onUpdateableAppsChanged = new BroadcastReceiver() { private final BroadcastReceiver onUpdateableAppsChanged = new BroadcastReceiver() {
@Override @Override
@ -362,14 +361,18 @@ public class MainActivity extends AppCompatActivity implements BottomNavigationB
AppUpdateStatusManager manager = AppUpdateStatusManager.getInstance(context); AppUpdateStatusManager manager = AppUpdateStatusManager.getInstance(context);
if (AppUpdateStatusManager.BROADCAST_APPSTATUS_LIST_CHANGED.equals(intent.getAction()) && 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; updateBadge = true;
} }
// Check if we have moved into the ReadyToInstall or Installed state. // 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); 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; updateBadge = true;
} }

View File

@ -83,7 +83,8 @@ class MainViewAdapter extends RecyclerView.Adapter<MainViewController> {
private MainViewController createEmptyView() { private MainViewController createEmptyView() {
FrameLayout frame = new FrameLayout(activity); 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); return new MainViewController(activity, frame);
} }

View File

@ -9,11 +9,10 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.fragments.PreferencesFragment; 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.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 * 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 // To allow for whitelabel versions of F-Droid, make sure not to hardcode "F-Droid" into our
// translation here. // translation here.
TextView subtext = (TextView) swapView.findViewById(R.id.text2); 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); Button startButton = (Button) swapView.findViewById(R.id.button);
startButton.setOnClickListener(new View.OnClickListener() { 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 * 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. * 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 * 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 * 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 * put a settings fragment in there at arbitrary times. Usually it wont be the same view we

View File

@ -7,16 +7,17 @@ import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.views.fragments.PreferencesFragment; import org.fdroid.fdroid.views.fragments.PreferencesFragment;
@SuppressWarnings("LineLength")
/** /**
* When attached to the window, the {@link PreferencesFragment} will be added. When detached from * When attached to the window, the {@link PreferencesFragment} will be added. When detached from
* the window, the fragment will be removed. * 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 * 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). * 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. * @see android.support.v4.app.FragmentStatePagerAdapter Much of the code here was ported from this class.
*/ */
public class SettingsView extends FrameLayout { public class SettingsView extends FrameLayout {

View File

@ -14,7 +14,6 @@ import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService; import org.fdroid.fdroid.UpdateService;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
@ -55,7 +54,8 @@ class WhatsNewViewBinder implements LoaderManager.LoaderCallbacks<Cursor> {
appList.setLayoutManager(layoutManager); appList.setLayoutManager(layoutManager);
appList.setAdapter(whatsNewAdapter); 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() { swipeToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override @Override
public void onRefresh() { public void onRefresh() {

View File

@ -19,7 +19,6 @@ import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SwapService; 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) { public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
inflater.inflate(R.menu.swap_next, menu); inflater.inflate(R.menu.swap_next, menu);
MenuItem next = menu.findItem(R.id.action_next); 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() { next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
@ -119,7 +119,7 @@ public class JoinWifiView extends RelativeLayout implements SwapWorkflowActivity
return true; return true;
} }
}); });
return true; return true;
} }
@Override @Override

View File

@ -12,7 +12,6 @@ import android.view.MenuItem;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.Preferences;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.localrepo.SwapService; 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) { public boolean buildMenu(Menu menu, @NonNull MenuInflater inflater) {
inflater.inflate(R.menu.swap_skip, menu); inflater.inflate(R.menu.swap_skip, menu);
MenuItem next = menu.findItem(R.id.action_next); 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() { next.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {

View File

@ -77,7 +77,8 @@ public class SelectAppsView extends ListView implements
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
adapter = new AppListAdapter(this, getContext(), 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); setAdapter(adapter);
setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
@ -124,7 +125,8 @@ public class SelectAppsView extends ListView implements
@Override @Override
public int getPreviousStep() { 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; return getState().isConnectingWithPeer() ? SwapService.STEP_INTRO : SwapService.STEP_JOIN_WIFI;
} }

View File

@ -27,20 +27,19 @@ import android.widget.ListView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import cc.mvdan.accesspoint.WifiApControl;
import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.FDroidApp;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.localrepo.SwapService; import org.fdroid.fdroid.localrepo.SwapService;
import org.fdroid.fdroid.localrepo.peers.Peer; import org.fdroid.fdroid.localrepo.peers.Peer;
import org.fdroid.fdroid.net.WifiStateChangeService; import org.fdroid.fdroid.net.WifiStateChangeService;
import java.util.ArrayList;
import cc.mvdan.accesspoint.WifiApControl;
import rx.Subscriber; import rx.Subscriber;
import rx.Subscription; import rx.Subscription;
import java.util.ArrayList;
@SuppressWarnings("LineLength")
public class StartSwapView extends RelativeLayout implements SwapWorkflowActivity.InnerView { public class StartSwapView extends RelativeLayout implements SwapWorkflowActivity.InnerView {
private static final String TAG = "StartSwapView"; private static final String TAG = "StartSwapView";
@ -78,12 +77,14 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
@Override @Override
public View getView(int position, View convertView, ViewGroup parent) { public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) { 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); Peer peer = getItem(position);
((TextView) convertView.findViewById(R.id.peer_name)).setText(peer.getName()); ((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; 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 * Remove relevant listeners/subscriptions/etc so that they do not receive and process events
* when this view is not in use. * when this view is not in use.
* * <p>
* TODO: Not sure if this is the best place to handle being removed from the view. * TODO: Not sure if this is the best place to handle being removed from the view.
*/ */
@Override @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 * 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 * being notified. This enables the UI to be updated without triggering further enable/disable
* events being queued. * events being queued.
* * <p>
* This is required because the SwitchCompat and its parent classes will always try to notify * 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). * 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 * 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 * 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. * ensuring the enabled state of the switch.
@ -408,10 +409,10 @@ public class StartSwapView extends RelativeLayout implements SwapWorkflowActivit
/** /**
* When the wifi switch is: * When the wifi switch is:
* * <p>
* Toggled on: Ask the swap service to ensure wifi swap is running. * 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. * 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 * Both of these actions will be performed in a background thread which will send broadcast
* intents when they are completed. * intents when they are completed.
*/ */

View File

@ -132,7 +132,7 @@ public class SwapAppsView extends ListView implements
private void pollForUpdates() { private void pollForUpdates() {
if (adapter.getCount() > 1 || 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."); Utils.debugLog(TAG, "Not polling for new apps from swap repo, because we already have more than one.");
return; return;
} }
@ -194,7 +194,8 @@ public class SwapAppsView extends ListView implements
? AppProvider.getRepoUri(repo) ? AppProvider.getRepoUri(repo)
: AppProvider.getSearchUri(repo, currentFilterString); : 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 @Override
@ -305,7 +306,8 @@ public class SwapAppsView extends ListView implements
this.app = app; this.app = app;
Context context = getContext(); 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(); String urlString = apk.getUrl();
// TODO unregister receivers? or will they just die with this instance // TODO unregister receivers? or will they just die with this instance

View File

@ -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 * 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. * device to download and install, and 2) Prepare your own list of apps to share.
*/ */
@SuppressWarnings("LineLength")
public class SwapWorkflowActivity extends AppCompatActivity { public class SwapWorkflowActivity extends AppCompatActivity {
/** /**

View File

@ -13,9 +13,7 @@ import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.hannesdorfmann.adapterdelegates3.AdapterDelegatesManager; import com.hannesdorfmann.adapterdelegates3.AdapterDelegatesManager;
import org.fdroid.fdroid.AppUpdateStatusManager; import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.AppProvider;
@ -34,31 +32,38 @@ import java.util.Set;
/** /**
* Manages the following types of information: * Manages the following types of information:
* * Apps marked for downloading (while the user is offline) * <ul>
* * Currently downloading apps * <li>Apps marked for downloading (while the user is offline)</li>
* * Apps which have been downloaded (and need further action to install). This includes new installs and updates. * <li>Currently downloading apps</li>
* * Reminders to users that they can donate to apps (only shown infrequently after several updates) * <li>Apps which have been downloaded (and need further action to install)</li>
* * A list of apps which are eligible to be updated (for when the "Automatic Updates" option is disabled), including: * </ul>
* + A summary of all apps to update including an "Update all" button and a "Show apps" button. * This includes new installs and updates.
* + Once "Show apps" is expanded then each app is shown along with its own download button. * <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 * 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}). * around the piece of data it wants to render ({@link AppStatus}, {@link UpdateableApp}).
* Instead of juggling the various viewTypes * Instead of juggling the various viewTypes
* to find out which position in the adapter corresponds to which view type, this is handled by * to find out which position in the adapter corresponds to which view type, this is handled by
* the {@link UpdatesAdapter#delegatesManager}. * the {@link UpdatesAdapter#delegatesManager}.
* * <p>
* There are a series of type-safe lists which hold the specific data this adapter is interested in. * 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 * 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 * 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 * 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 * 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). * 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 * 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. * 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 AdapterDelegatesManager<List<AppUpdateData>> delegatesManager = new AdapterDelegatesManager<>();
private final List<AppUpdateData> items = new ArrayList<>(); private final List<AppUpdateData> items = new ArrayList<>();
@ -221,7 +226,8 @@ public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
} }
@Override @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. * If this adapter is "active" then it is part of the current UI that the user is looking to.

View File

@ -4,9 +4,7 @@ import android.app.Activity;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.hannesdorfmann.adapterdelegates3.AdapterDelegate; import com.hannesdorfmann.adapterdelegates3.AdapterDelegate;
import org.fdroid.fdroid.AppUpdateStatusManager; import org.fdroid.fdroid.AppUpdateStatusManager;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.App; 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. * 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 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 { public class AppStatus extends AppUpdateData {
@ -44,11 +44,13 @@ public class AppStatus extends AppUpdateData {
@NonNull @NonNull
@Override @Override
protected RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) { 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 @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); AppStatus app = (AppStatus) items.get(position);
((AppListItemController) holder).bindModel(app.status.app); ((AppListItemController) holder).bindModel(app.status.app);
} }

View File

@ -3,8 +3,10 @@ package org.fdroid.fdroid.views.updates.items;
import android.app.Activity; import android.app.Activity;
/** /**
* Used as a common base class for all data types in the {@link org.fdroid.fdroid.views.updates.UpdatesAdapter}. * Used as a common base class for all data types in the {@link
* Doesn't have any functionality of its own, but allows the {@link org.fdroid.fdroid.views.updates.UpdatesAdapter#delegatesManager} * 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}. * to specify a data type more specific than just {@link Object}.
*/ */
public abstract class AppUpdateData { public abstract class AppUpdateData {

View File

@ -4,9 +4,7 @@ import android.app.Activity;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.hannesdorfmann.adapterdelegates3.AdapterDelegate; import com.hannesdorfmann.adapterdelegates3.AdapterDelegate;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.views.apps.AppListItemController; 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. * 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 UpdateableApp The data that is bound to this view.
* @see R.layout#updateable_app_list_item The view that this binds to. * @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} * @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 @NonNull
@Override @Override
protected RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) { 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 @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); UpdateableApp app = (UpdateableApp) items.get(position);
((AppListItemController) holder).bindModel(app.app); ((AppListItemController) holder).bindModel(app.app);
} }

View File

@ -10,9 +10,7 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.hannesdorfmann.adapterdelegates3.AdapterDelegate; import com.hannesdorfmann.adapterdelegates3.AdapterDelegate;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.UpdateService; import org.fdroid.fdroid.UpdateService;
import org.fdroid.fdroid.views.updates.UpdatesAdapter; 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 * 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. * a toggle to show or hide the list of each individual item.
*
* @see R.layout#updates_header The view that this binds to. * @see R.layout#updates_header The view that this binds to.
* @see UpdateableAppsHeader The data that is bound to this view. * @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 List<UpdateableApp> apps;
public final UpdatesAdapter adapter; public final UpdatesAdapter adapter;
public UpdateableAppsHeader(Activity activity, UpdatesAdapter updatesAdapter, List<UpdateableApp> updateableApps) { public UpdateableAppsHeader(Activity activity,
UpdatesAdapter updatesAdapter, List<UpdateableApp> updateableApps) {
super(activity); super(activity);
apps = updateableApps; apps = updateableApps;
adapter = updatesAdapter; adapter = updatesAdapter;
@ -57,7 +57,8 @@ public class UpdateableAppsHeader extends AppUpdateData {
} }
@Override @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); UpdateableAppsHeader app = (UpdateableAppsHeader) items.get(position);
((ViewHolder) holder).bindHeader(app); ((ViewHolder) holder).bindHeader(app);
} }
@ -87,7 +88,9 @@ public class UpdateableAppsHeader extends AppUpdateData {
public void bindHeader(UpdateableAppsHeader header) { public void bindHeader(UpdateableAppsHeader header) {
this.header = 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()); List<String> appNames = new ArrayList<>(header.apps.size());
for (UpdateableApp app : header.apps) { for (UpdateableApp app : header.apps) {

View File

@ -2,6 +2,7 @@ package org.fdroid.fdroid.views.whatsnew;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.Rect; import android.graphics.Rect;
import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewCompat;
@ -9,7 +10,6 @@ import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.fdroid.fdroid.R; import org.fdroid.fdroid.R;
import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.views.categories.AppCardController; 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. * 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. * 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__horizontal
* @see org.fdroid.fdroid.R.dimen#whats_new__padding__app_card__vertical * @see org.fdroid.fdroid.R.dimen#whats_new__padding__app_card__vertical
*/ */
@ -121,8 +122,9 @@ public class WhatsNewAdapter extends RecyclerView.Adapter<AppCardController> {
@Override @Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view); int position = parent.getChildAdapterPosition(view);
int horizontalPadding = (int) context.getResources().getDimension(R.dimen.whats_new__padding__app_card__horizontal); Resources resources = context.getResources();
int verticalPadding = (int) context.getResources().getDimension(R.dimen.whats_new__padding__app_card__vertical); 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; int relativePositionInCycle = position % 5;
if (position == 0) { if (position == 0) {

View File

@ -6,8 +6,9 @@ import java.net.URLConnection;
import java.net.URLStreamHandler; import java.net.URLStreamHandler;
/** /**
* This class is added so that the bluetooth:// scheme we use for the {@link org.fdroid.fdroid.net.BluetoothDownloader} * This class is added so that the bluetooth:// scheme we use for the {@link
* is not treated as invalid by the {@link URL} class. * org.fdroid.fdroid.net.BluetoothDownloader} is not treated as invalid by
* the {@link URL} class.
*/ */
public class Handler extends URLStreamHandler { public class Handler extends URLStreamHandler {
@Override @Override

View File

@ -4,9 +4,7 @@ import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import org.fdroid.fdroid.data.ApkProvider; import org.fdroid.fdroid.data.ApkProvider;
import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.App;
import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.data.AppProvider;
@ -118,7 +116,7 @@ public class Assert {
} }
public static void assertInvalidUri(ShadowContentResolver resolver, Uri uri) { 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); assertNull(cursor);
} }
@ -128,16 +126,18 @@ public class Assert {
cursor.close(); 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); assertValidUri(resolver, actualUri, projection);
assertEquals(expectedUri, actualUri.toString()); assertEquals(expectedUri, actualUri.toString());
} }
public static void assertResultCount(ShadowContentResolver resolver, int expectedCount, Uri uri) { 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); Cursor cursor = resolver.query(uri, projection, null, null, null);
assertResultCount(expectedCount, cursor); assertResultCount(expectedCount, cursor);
cursor.close(); cursor.close();
@ -153,7 +153,8 @@ public class Assert {
assertEquals(expectedCount, result.getCount()); 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); Uri uri = InstalledAppProvider.getAppUri(appId);
String[] projection = { String[] projection = {
@ -198,14 +199,17 @@ public class Assert {
Uri uri = AppProvider.getContentUri(); Uri uri = AppProvider.getContentUri();
context.getContentResolver().insert(uri, values); 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) { 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) { if (app == null) {
insertApp(context, packageName, packageName); 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); assertNotNull(app);
return app; return app;
@ -215,7 +219,8 @@ public class Assert {
return insertApk(context, ensureApp(context, packageName), versionCode); 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); return insertApk(context, ensureApp(context, packageName), versionCode, additionalValues);
} }

View File

@ -55,12 +55,14 @@ public class TestUtils {
} }
/** /**
* The way that Robolectric has to implement shadows for Android classes such as {@link android.content.ContentProvider} * The way that Robolectric has to implement shadows for Android classes
* is by using a special annotation that means the classes will implement the correct methods at runtime. * such as {@link android.content.ContentProvider} is by using a special
* However this means that the shadow of a content provider does not actually extend * annotation that means the classes will implement the correct methods at
* {@link android.content.ContentProvider}. As such, we need to do some special mocking using * runtime. However this means that the shadow of a content provider does
* Mockito in order to provide a {@link ContextWrapper} which is able to return a proper * not actually extend {@link android.content.ContentProvider}. As such,
* content resolver that delegates to the Robolectric shadow object. * 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) { public static ContextWrapper createContextWithContentResolver(ShadowContentResolver contentResolver) {
final ContentResolver resolver = mock(ContentResolver.class, AdditionalAnswers.delegatesTo(contentResolver)); final ContentResolver resolver = mock(ContentResolver.class, AdditionalAnswers.delegatesTo(contentResolver));

View File

@ -18,6 +18,7 @@ import static org.junit.Assert.assertTrue;
@Config(constants = BuildConfig.class, sdk = 24) @Config(constants = BuildConfig.class, sdk = 24)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@SuppressWarnings("LineLength")
public class UtilsTest { public class UtilsTest {
String fdroidFingerprint = "43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB"; String fdroidFingerprint = "43238D512C1E5EB2D6569F4A3AFBF5523418B82E0A3ED1552770ABB9A9C9CCAB";

View File

@ -30,6 +30,7 @@ import static org.junit.Assert.assertTrue;
@Config(constants = BuildConfig.class, application = Application.class, sdk = 24) @Config(constants = BuildConfig.class, application = Application.class, sdk = 24)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@SuppressWarnings("LineLength")
public class AppProviderTest extends FDroidProviderTest { public class AppProviderTest extends FDroidProviderTest {
private static final String[] PROJ = Cols.ALL; private static final String[] PROJ = Cols.ALL;

View File

@ -5,7 +5,6 @@ import android.content.ContentResolver;
import android.content.ContentValues; import android.content.ContentValues;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
import org.fdroid.fdroid.data.Schema.AppMetadataTable.Cols; 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.dog.rock.apple", "Dog-Rock-Apple", "Animal,Mineral,Vegetable", mainRepo);
insertAppWithCategory("com.banana.apple", "Banana", "Vegetable,Vegetable", mainRepo); insertAppWithCategory("com.banana.apple", "Banana", "Vegetable,Vegetable", mainRepo);
String[] expectedFDroid = new String[] { String[] expectedFDroid = new String[]{
"Animal", "Animal",
"Mineral", "Mineral",
"Security", "Security",
@ -54,13 +53,13 @@ public class CategoryProviderTest extends FDroidProviderTest {
"Writing", "Writing",
}; };
String[] expectedGP = new String[] { String[] expectedGP = new String[]{
"GuardianProject", "GuardianProject",
"Office", "Office",
}; };
// We overwrite "Security" + "Writing" with "GuardianProject" + "Office" // We overwrite "Security" + "Writing" with "GuardianProject" + "Office"
String[] expectedBoth = new String[] { String[] expectedBoth = new String[]{
"Animal", "Animal",
"Mineral", "Mineral",
"Vegetable", "Vegetable",
@ -90,16 +89,16 @@ public class CategoryProviderTest extends FDroidProviderTest {
insertAppWithCategory("com.banana", "Banana", "Food"); insertAppWithCategory("com.banana", "Banana", "Food");
insertAppWithCategory("com.dog-food", "Dog Food", "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",
"com.dog-statue", "com.dog-statue",
}); });
assertPackagesInUri(AppProvider.getSearchUri("dog", "Food"), new String[] { assertPackagesInUri(AppProvider.getSearchUri("dog", "Food"), new String[]{
"com.dog-food", "com.dog-food",
}); });
assertPackagesInUri(AppProvider.getSearchUri("dog", null), new String[] { assertPackagesInUri(AppProvider.getSearchUri("dog", null), new String[]{
"com.dog", "com.dog",
"com.dog-statue", "com.dog-statue",
"com.dog-food", "com.dog-food",
@ -116,14 +115,14 @@ public class CategoryProviderTest extends FDroidProviderTest {
insertAppWithCategory("com.rock", "Rock", "Mineral"); insertAppWithCategory("com.rock", "Rock", "Mineral");
insertAppWithCategory("com.banana", "Banana", "Food"); insertAppWithCategory("com.banana", "Banana", "Food");
assertPackagesInCategory("Animal", new String[] { assertPackagesInCategory("Animal", new String[]{
"com.dog", "com.dog",
"com.cat", "com.cat",
"com.crow", "com.crow",
"com.chicken", "com.chicken",
}); });
assertPackagesInCategory("animal", new String[] { assertPackagesInCategory("animal", new String[]{
"com.dog", "com.dog",
"com.cat", "com.cat",
"com.crow", "com.crow",
@ -136,12 +135,12 @@ public class CategoryProviderTest extends FDroidProviderTest {
"com.bird-statue", "com.bird-statue",
}); });
assertPackagesInCategory("Food", new String[] { assertPackagesInCategory("Food", new String[]{
"com.chicken", "com.chicken",
"com.banana", "com.banana",
}); });
assertPackagesInCategory("Mineral", new String[] { assertPackagesInCategory("Mineral", new String[]{
"com.rock", "com.rock",
"com.bird-statue", "com.bird-statue",
}); });
@ -178,17 +177,18 @@ public class CategoryProviderTest extends FDroidProviderTest {
insertAppWithCategory("com.banana", "Banana", "Vegetable"); insertAppWithCategory("com.banana", "Banana", "Vegetable");
insertAppWithCategory("com.tomato", "Tomato", "Vegetable"); insertAppWithCategory("com.tomato", "Tomato", "Vegetable");
assertContainsOnly(topAppsFromCategory("Animal", 3), new String[] {"com.bird", "com.cat", "com.dog", }); 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", 2), new String[]{"com.bird", "com.cat"});
assertContainsOnly(topAppsFromCategory("Animal", 1), new String[] {"com.bird", }); 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) { 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()]; String[] packageNames = new String[apps.size()];
for (int i = 0; i < apps.size(); i++) { for (int i = 0; i < apps.size(); i++) {
packageNames[i] = apps.get(i).packageName; packageNames[i] = apps.get(i).packageName;
@ -204,7 +204,7 @@ public class CategoryProviderTest extends FDroidProviderTest {
insertAppWithCategory("com.banana", "Banana", "Vegetable"); insertAppWithCategory("com.banana", "Banana", "Vegetable");
List<String> categories = categories(); List<String> categories = categories();
String[] expected = new String[] { String[] expected = new String[]{
"Animal", "Animal",
"Mineral", "Mineral",
"Vegetable", "Vegetable",
@ -221,7 +221,7 @@ public class CategoryProviderTest extends FDroidProviderTest {
insertAppWithCategory("com.banana.apple", "Banana", "Vegetable,Vegetable", mainRepo); insertAppWithCategory("com.banana.apple", "Banana", "Vegetable,Vegetable", mainRepo);
List<String> categories = categories(); List<String> categories = categories();
String[] expected = new String[] { String[] expected = new String[]{
"Animal", "Animal",
"Mineral", "Mineral",
"Vegetable", "Vegetable",
@ -232,10 +232,10 @@ public class CategoryProviderTest extends FDroidProviderTest {
insertAppWithCategory("com.example.game", "Game", insertAppWithCategory("com.example.game", "Game",
"Running,Shooting,Jumping,Bleh,Sneh,Pleh,Blah,Test category," + "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(); List<String> categoriesLonger = categories();
String[] expectedLonger = new String[] { String[] expectedLonger = new String[]{
"Animal", "Animal",
"Mineral", "Mineral",
"Vegetable", "Vegetable",

View File

@ -6,7 +6,6 @@ import android.content.Context;
import android.content.ContextWrapper; import android.content.ContextWrapper;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.Utils;
@ -134,13 +133,13 @@ public class DatabaseMigration {
} }
private void insertRepos(SQLiteDatabase db) { private void insertRepos(SQLiteDatabase db) {
String pubKey = "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef"; String pubKey = "3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef"; // NOCHECKSTYLE LineLength
String fingerprint = Utils.calcFingerprint(pubKey); String fingerprint = Utils.calcFingerprint(pubKey);
ContentValues fdroidValues = new ContentValues(); ContentValues fdroidValues = new ContentValues();
fdroidValues.put("address", "https://f-droid.org/repo"); fdroidValues.put("address", "https://f-droid.org/repo");
fdroidValues.put("name", "F-Droid"); 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("pubkey", pubKey);
fdroidValues.put("fingerprint", fingerprint); fdroidValues.put("fingerprint", fingerprint);
fdroidValues.put("maxage", 0); fdroidValues.put("maxage", 0);
@ -152,7 +151,7 @@ public class DatabaseMigration {
ContentValues archiveValues = new ContentValues(); ContentValues archiveValues = new ContentValues();
archiveValues.put("address", "https://f-droid.org/archive"); archiveValues.put("address", "https://f-droid.org/archive");
archiveValues.put("name", "F-Droid 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("pubkey", pubKey);
archiveValues.put("fingerprint", fingerprint); archiveValues.put("fingerprint", fingerprint);
archiveValues.put("maxage", 0); archiveValues.put("maxage", 0);

View File

@ -4,7 +4,6 @@ import android.app.Application;
import android.content.ContentValues; import android.content.ContentValues;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.BuildConfig;
import org.fdroid.fdroid.TestUtils; import org.fdroid.fdroid.TestUtils;
import org.fdroid.fdroid.data.Schema.InstalledAppTable.Cols; import org.fdroid.fdroid.data.Schema.InstalledAppTable.Cols;
@ -15,14 +14,14 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import java.util.Map;
import static org.fdroid.fdroid.Assert.assertIsInstalledVersionInDb; import static org.fdroid.fdroid.Assert.assertIsInstalledVersionInDb;
import static org.fdroid.fdroid.Assert.assertResultCount; import static org.fdroid.fdroid.Assert.assertResultCount;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.Map;
@Config(constants = BuildConfig.class, application = Application.class, sdk = 24) @Config(constants = BuildConfig.class, application = Application.class, sdk = 24)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class InstalledAppProviderTest extends FDroidProviderTest { public class InstalledAppProviderTest extends FDroidProviderTest {
@ -52,7 +51,8 @@ public class InstalledAppProviderTest extends FDroidProviderTest {
assertEquals(1, foundAfter.size()); assertEquals(1, foundAfter.size());
assertEquals(100000000L, foundAfter.get("org.example.test-app").longValue()); 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); assertEquals(cursor.getCount(), 1);
cursor.moveToFirst(); cursor.moveToFirst();
@ -63,7 +63,8 @@ public class InstalledAppProviderTest extends FDroidProviderTest {
assertEquals("has of test app", cursor.getString(cursor.getColumnIndex(Cols.HASH))); assertEquals("has of test app", cursor.getString(cursor.getColumnIndex(Cols.HASH)));
assertEquals("fake hash type", cursor.getString(cursor.getColumnIndex(Cols.HASH_TYPE))); assertEquals("fake hash type", cursor.getString(cursor.getColumnIndex(Cols.HASH_TYPE)));
assertEquals(100000000L, cursor.getLong(cursor.getColumnIndex(Cols.LAST_UPDATE_TIME))); 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(); cursor.close();
} }

View File

@ -22,6 +22,7 @@ import static org.fdroid.fdroid.Assert.assertValidUri;
@Config(constants = BuildConfig.class, sdk = 24) @Config(constants = BuildConfig.class, sdk = 24)
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@SuppressWarnings("LineLength")
public class ProviderUriTests { public class ProviderUriTests {
private ShadowContentResolver resolver; private ShadowContentResolver resolver;

View File

@ -142,7 +142,8 @@ public class RepoProviderTest extends FDroidProviderTest {
for (String url : urls) { for (String url : urls) {
Repo actualRepo = RepoProvider.Helper.findByUrl(context, Uri.parse(url), COLS); Repo actualRepo = RepoProvider.Helper.findByUrl(context, Uri.parse(url), COLS);
assertNotNull("No repo matching URL " + url, actualRepo); 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); 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(); ContentValues values = new ContentValues();
values.put(RepoTable.Cols.ADDRESS, address); values.put(RepoTable.Cols.ADDRESS, address);
values.put(RepoTable.Cols.DESCRIPTION, description); values.put(RepoTable.Cols.DESCRIPTION, description);

View File

@ -29,7 +29,7 @@ public class SanitizedFileTest {
assertEquals("safe", safeNotSanitized.getName()); assertEquals("safe", safeNotSanitized.getName());
assertEquals("$%^safe-and_bleh.boo*@~", nonEvilNotSanitized.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 safeSanitized = new SanitizedFile(directory, safeFile);
SanitizedFile nonEvilSanitized = new SanitizedFile(directory, nonEvilFile); SanitizedFile nonEvilSanitized = new SanitizedFile(directory, nonEvilFile);

Some files were not shown because too many files have changed in this diff Show More