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:
parent
a0015cda32
commit
48fd6d287d
@ -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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -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
|
||||||
|
@ -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';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
|
@ -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,6 +35,7 @@ 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";
|
||||||
@ -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,6 +313,7 @@ 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 apk The apk to add.
|
||||||
* @param status The current status of the app
|
* @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)
|
||||||
@ -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) {
|
||||||
|
@ -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";
|
||||||
|
@ -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("/", "-");
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
@ -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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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"><uses-sdk> element</a>
|
* @see <a href="https://developer.android.com/guide/topics/manifest/uses-sdk-element.html"><uses-sdk></a>
|
||||||
*/
|
*/
|
||||||
private static int[] getMinTargetMaxSdkVersions(Context context, String packageName) {
|
private static int[] getMinTargetMaxSdkVersions(Context context, String packageName) {
|
||||||
int minSdkVersion = Apk.SDK_VERSION_MIN_VALUE;
|
int minSdkVersion = Apk.SDK_VERSION_MIN_VALUE;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
@ -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);
|
||||||
@ -31,7 +31,8 @@ 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)) {
|
||||||
|
@ -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";
|
||||||
|
@ -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 + " = ?";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
@ -27,7 +27,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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";
|
||||||
|
@ -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".
|
||||||
@ -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";
|
||||||
@ -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();
|
||||||
@ -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));
|
||||||
|
@ -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";
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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:
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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";
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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";
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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.");
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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";
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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> {
|
||||||
|
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -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)
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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";
|
||||||
|
@ -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();
|
||||||
|
@ -10,7 +10,6 @@ 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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
@ -38,7 +36,8 @@ import org.fdroid.fdroid.views.apps.FeatureImage;
|
|||||||
* + {@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) {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,14 +35,14 @@ 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)
|
||||||
@ -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);
|
||||||
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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() {
|
||||||
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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>
|
||||||
|
* This includes new installs and updates.
|
||||||
|
* <ul>
|
||||||
|
* <li>Reminders to users that they can donate to apps (only shown infrequently after several updates)</li>
|
||||||
|
* <li>A list of apps which are eligible to be updated (for when the "Automatic Updates" option is disabled),
|
||||||
|
* including:
|
||||||
* + A summary of all apps to update including an "Update all" button and a "Show apps" button.
|
* + 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.
|
* + 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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
@ -128,7 +126,8 @@ 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());
|
||||||
}
|
}
|
||||||
@ -137,7 +136,8 @@ public class Assert {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user