support adding custom mirrors to any existing repo, via "App Repo"
This lets people add any URL as a mirror to an existing repo. The UX is people add URLs via any of the normal ways of adding a new repo via Intents, like clicking URLs, QRCodes, etc.
This commit is contained in:
parent
89e04cc078
commit
2f0cb30ad0
@ -88,35 +88,36 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
+ RepoTable.Cols.TIMESTAMP + " integer not null default 0, "
|
||||
+ RepoTable.Cols.ICON + " string, "
|
||||
+ RepoTable.Cols.MIRRORS + " string, "
|
||||
+ RepoTable.Cols.USER_MIRRORS + " string, "
|
||||
+ RepoTable.Cols.PUSH_REQUESTS + " integer not null default " + Repo.PUSH_REQUEST_IGNORE
|
||||
+ ");";
|
||||
|
||||
static final String CREATE_TABLE_APK =
|
||||
"CREATE TABLE " + ApkTable.NAME + " ( "
|
||||
+ ApkTable.Cols.APP_ID + " integer not null, "
|
||||
+ ApkTable.Cols.VERSION_NAME + " text not null, "
|
||||
+ ApkTable.Cols.REPO_ID + " integer not null, "
|
||||
+ ApkTable.Cols.HASH + " text not null, "
|
||||
+ ApkTable.Cols.VERSION_CODE + " int not null,"
|
||||
+ ApkTable.Cols.NAME + " text not null, "
|
||||
+ ApkTable.Cols.SIZE + " int not null, "
|
||||
+ ApkTable.Cols.SIGNATURE + " string, "
|
||||
+ ApkTable.Cols.SOURCE_NAME + " string, "
|
||||
+ ApkTable.Cols.MIN_SDK_VERSION + " integer, "
|
||||
+ ApkTable.Cols.TARGET_SDK_VERSION + " integer, "
|
||||
+ ApkTable.Cols.MAX_SDK_VERSION + " integer, "
|
||||
+ ApkTable.Cols.OBB_MAIN_FILE + " string, "
|
||||
+ ApkTable.Cols.OBB_MAIN_FILE_SHA256 + " string, "
|
||||
+ ApkTable.Cols.OBB_PATCH_FILE + " string, "
|
||||
+ ApkTable.Cols.OBB_PATCH_FILE_SHA256 + " string, "
|
||||
+ ApkTable.Cols.REQUESTED_PERMISSIONS + " string, "
|
||||
+ ApkTable.Cols.FEATURES + " string, "
|
||||
+ ApkTable.Cols.NATIVE_CODE + " string, "
|
||||
+ ApkTable.Cols.HASH_TYPE + " string, "
|
||||
+ ApkTable.Cols.ADDED_DATE + " string, "
|
||||
+ ApkTable.Cols.IS_COMPATIBLE + " int not null, "
|
||||
+ ApkTable.Cols.INCOMPATIBLE_REASONS + " text"
|
||||
+ ");";
|
||||
+ ApkTable.Cols.APP_ID + " integer not null, "
|
||||
+ ApkTable.Cols.VERSION_NAME + " text not null, "
|
||||
+ ApkTable.Cols.REPO_ID + " integer not null, "
|
||||
+ ApkTable.Cols.HASH + " text not null, "
|
||||
+ ApkTable.Cols.VERSION_CODE + " int not null,"
|
||||
+ ApkTable.Cols.NAME + " text not null, "
|
||||
+ ApkTable.Cols.SIZE + " int not null, "
|
||||
+ ApkTable.Cols.SIGNATURE + " string, "
|
||||
+ ApkTable.Cols.SOURCE_NAME + " string, "
|
||||
+ ApkTable.Cols.MIN_SDK_VERSION + " integer, "
|
||||
+ ApkTable.Cols.TARGET_SDK_VERSION + " integer, "
|
||||
+ ApkTable.Cols.MAX_SDK_VERSION + " integer, "
|
||||
+ ApkTable.Cols.OBB_MAIN_FILE + " string, "
|
||||
+ ApkTable.Cols.OBB_MAIN_FILE_SHA256 + " string, "
|
||||
+ ApkTable.Cols.OBB_PATCH_FILE + " string, "
|
||||
+ ApkTable.Cols.OBB_PATCH_FILE_SHA256 + " string, "
|
||||
+ ApkTable.Cols.REQUESTED_PERMISSIONS + " string, "
|
||||
+ ApkTable.Cols.FEATURES + " string, "
|
||||
+ ApkTable.Cols.NATIVE_CODE + " string, "
|
||||
+ ApkTable.Cols.HASH_TYPE + " string, "
|
||||
+ ApkTable.Cols.ADDED_DATE + " string, "
|
||||
+ ApkTable.Cols.IS_COMPATIBLE + " int not null, "
|
||||
+ ApkTable.Cols.INCOMPATIBLE_REASONS + " text"
|
||||
+ ");";
|
||||
|
||||
static final String CREATE_TABLE_APP_METADATA = "CREATE TABLE " + AppMetadataTable.NAME
|
||||
+ " ( "
|
||||
@ -181,7 +182,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
* app metadata id, because it can instead look through the primary key index. This can be
|
||||
* observed by flipping the order of the primary key columns, and noting the resulting sqlite
|
||||
* logs along the lines of:
|
||||
* E/SQLiteLog(14164): (284) automatic index on fdroid_categoryAppMetadataJoin(appMetadataId)
|
||||
* E/SQLiteLog(14164): (284) automatic index on fdroid_categoryAppMetadataJoin(appMetadataId)
|
||||
*/
|
||||
static final String CREATE_TABLE_CAT_JOIN = "CREATE TABLE " + CatJoinTable.NAME
|
||||
+ " ( "
|
||||
@ -214,7 +215,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
+ "primary key(" + ApkAntiFeatureJoinTable.Cols.APK_ID + ", " + ApkAntiFeatureJoinTable.Cols.ANTI_FEATURE_ID + ") "
|
||||
+ " );";
|
||||
|
||||
protected static final int DB_VERSION = 77;
|
||||
protected static final int DB_VERSION = 78;
|
||||
|
||||
private final Context context;
|
||||
|
||||
@ -321,6 +322,17 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
addApkAntiFeatures(db, oldVersion);
|
||||
addIgnoreVulnPref(db, oldVersion);
|
||||
addLiberapayID(db, oldVersion);
|
||||
addUserMirrorsFields(db, oldVersion);
|
||||
}
|
||||
|
||||
private void addUserMirrorsFields(SQLiteDatabase db, int oldVersion) {
|
||||
if (oldVersion >= 78) {
|
||||
return;
|
||||
}
|
||||
if (!columnExists(db, RepoTable.NAME, RepoTable.Cols.USER_MIRRORS)) {
|
||||
Utils.debugLog(TAG, "Adding " + RepoTable.Cols.USER_MIRRORS + " field to " + RepoTable.NAME + " table in db.");
|
||||
db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.USER_MIRRORS + " string;");
|
||||
}
|
||||
}
|
||||
|
||||
private void addLiberapayID(SQLiteDatabase db, int oldVersion) {
|
||||
@ -581,7 +593,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
updateRepoPriority(db, gpPubKey, gpArchiveAddress, 4);
|
||||
|
||||
int priority = 5;
|
||||
String[] projection = new String[] {RepoTable.Cols.SIGNING_CERT, RepoTable.Cols.ADDRESS};
|
||||
String[] projection = new String[]{RepoTable.Cols.SIGNING_CERT, RepoTable.Cols.ADDRESS};
|
||||
|
||||
// Order by ID, because that is a good analogy for the order in which they were added.
|
||||
// The order in which they were added is likely the order they present in the ManageRepos activity.
|
||||
@ -606,7 +618,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
RepoTable.NAME,
|
||||
values,
|
||||
RepoTable.Cols.SIGNING_CERT + " = ? AND " + RepoTable.Cols.ADDRESS + " = ?",
|
||||
new String[] {signingCert, address}
|
||||
new String[]{signingCert, address}
|
||||
);
|
||||
}
|
||||
|
||||
@ -630,15 +642,15 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
Utils.debugLog(TAG, "Migrating app preferences to separate table");
|
||||
db.execSQL(
|
||||
"INSERT INTO " + AppPrefsTable.NAME + " ("
|
||||
+ AppPrefsTable.Cols.PACKAGE_NAME + ", "
|
||||
+ AppPrefsTable.Cols.IGNORE_THIS_UPDATE + ", "
|
||||
+ AppPrefsTable.Cols.IGNORE_ALL_UPDATES
|
||||
+ ") SELECT "
|
||||
+ "id, "
|
||||
+ "ignoreThisUpdate, "
|
||||
+ "ignoreAllUpdates "
|
||||
+ "FROM " + AppMetadataTable.NAME + " "
|
||||
+ "WHERE ignoreThisUpdate > 0 OR ignoreAllUpdates > 0"
|
||||
+ AppPrefsTable.Cols.PACKAGE_NAME + ", "
|
||||
+ AppPrefsTable.Cols.IGNORE_THIS_UPDATE + ", "
|
||||
+ AppPrefsTable.Cols.IGNORE_ALL_UPDATES
|
||||
+ ") SELECT "
|
||||
+ "id, "
|
||||
+ "ignoreThisUpdate, "
|
||||
+ "ignoreAllUpdates "
|
||||
+ "FROM " + AppMetadataTable.NAME + " "
|
||||
+ "WHERE ignoreThisUpdate > 0 OR ignoreAllUpdates > 0"
|
||||
);
|
||||
|
||||
resetTransient(db);
|
||||
@ -687,7 +699,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
|
||||
db.execSQL(createTableDdl);
|
||||
|
||||
String nonPackageNameFields = TextUtils.join(", ", new String[] {
|
||||
String nonPackageNameFields = TextUtils.join(", ", new String[]{
|
||||
ApkTable.Cols.APP_ID,
|
||||
ApkTable.Cols.VERSION_NAME,
|
||||
ApkTable.Cols.REPO_ID,
|
||||
@ -766,7 +778,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
List<Repo> oldrepos = new ArrayList<>();
|
||||
Cursor cursor = db.query(RepoTable.NAME,
|
||||
new String[] {RepoTable.Cols.ADDRESS, RepoTable.Cols.IN_USE, RepoTable.Cols.SIGNING_CERT},
|
||||
new String[]{RepoTable.Cols.ADDRESS, RepoTable.Cols.IN_USE, RepoTable.Cols.SIGNING_CERT},
|
||||
null, null, null, null, null);
|
||||
if (cursor != null) {
|
||||
if (cursor.getCount() > 0) {
|
||||
@ -847,7 +859,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
List<Repo> oldrepos = new ArrayList<>();
|
||||
Cursor cursor = db.query(RepoTable.NAME,
|
||||
new String[] {RepoTable.Cols.ADDRESS, RepoTable.Cols.SIGNING_CERT},
|
||||
new String[]{RepoTable.Cols.ADDRESS, RepoTable.Cols.SIGNING_CERT},
|
||||
null, null, null, null, null);
|
||||
if (cursor != null) {
|
||||
if (cursor.getCount() > 0) {
|
||||
@ -865,7 +877,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
for (final Repo repo : oldrepos) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RepoTable.Cols.FINGERPRINT, Utils.calcFingerprint(repo.signingCertificate));
|
||||
db.update(RepoTable.NAME, values, RepoTable.Cols.ADDRESS + " = ?", new String[] {repo.address});
|
||||
db.update(RepoTable.NAME, values, RepoTable.Cols.ADDRESS + " = ?", new String[]{repo.address});
|
||||
}
|
||||
}
|
||||
|
||||
@ -954,7 +966,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
|
||||
db.execSQL(createTableDdl);
|
||||
|
||||
String nonIdFields = TextUtils.join(", ", new String[] {
|
||||
String nonIdFields = TextUtils.join(", ", new String[]{
|
||||
RepoTable.Cols.ADDRESS,
|
||||
RepoTable.Cols.NAME,
|
||||
RepoTable.Cols.DESCRIPTION,
|
||||
@ -1235,8 +1247,8 @@ public class DBHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
|
||||
private static boolean tableExists(SQLiteDatabase db, String table) {
|
||||
Cursor cursor = db.query("sqlite_master", new String[] {"name"},
|
||||
"type = 'table' AND name = ?", new String[] {table}, null, null, null);
|
||||
Cursor cursor = db.query("sqlite_master", new String[]{"name"},
|
||||
"type = 'table' AND name = ?", new String[]{table}, null, null, null);
|
||||
|
||||
boolean exists = cursor.getCount() > 0;
|
||||
cursor.close();
|
||||
|
@ -26,13 +26,13 @@ package org.fdroid.fdroid.data;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Schema.RepoTable.Cols;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@ -94,6 +94,11 @@ public class Repo extends ValueObject {
|
||||
/** Official mirrors of this repo, considered automatically interchangeable */
|
||||
public String[] mirrors;
|
||||
|
||||
/**
|
||||
* Mirrors added by the user, either by UI input or by attaching removeable storage
|
||||
*/
|
||||
public String[] userMirrors;
|
||||
|
||||
/** How to treat push requests included in this repo's index XML */
|
||||
public int pushRequests = PUSH_REQUEST_IGNORE;
|
||||
|
||||
@ -160,6 +165,9 @@ public class Repo extends ValueObject {
|
||||
case Cols.MIRRORS:
|
||||
mirrors = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||
break;
|
||||
case Cols.USER_MIRRORS:
|
||||
userMirrors = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||
break;
|
||||
case Cols.PUSH_REQUESTS:
|
||||
pushRequests = cursor.getInt(i);
|
||||
break;
|
||||
@ -297,26 +305,43 @@ public class Repo extends ValueObject {
|
||||
mirrors = Utils.parseCommaSeparatedString(values.getAsString(Cols.MIRRORS));
|
||||
}
|
||||
|
||||
if (values.containsKey(Cols.USER_MIRRORS)) {
|
||||
userMirrors = Utils.parseCommaSeparatedString(values.getAsString(Cols.USER_MIRRORS));
|
||||
}
|
||||
|
||||
if (values.containsKey(Cols.PUSH_REQUESTS)) {
|
||||
pushRequests = toInt(values.getAsInteger(Cols.PUSH_REQUESTS));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasMirrors() {
|
||||
return mirrors != null && mirrors.length > 1;
|
||||
return (mirrors != null && mirrors.length > 1)
|
||||
|| (userMirrors != null && userMirrors.length > 0);
|
||||
}
|
||||
|
||||
public List<String> getMirrorList() {
|
||||
final ArrayList<String> allMirrors = new ArrayList<String>();
|
||||
if (userMirrors != null) {
|
||||
allMirrors.addAll(Arrays.asList(userMirrors));
|
||||
}
|
||||
if (mirrors != null) {
|
||||
allMirrors.addAll(Arrays.asList(mirrors));
|
||||
}
|
||||
return allMirrors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of available mirrors, including the canonical repo.
|
||||
*/
|
||||
public int getMirrorCount() {
|
||||
int count = 0;
|
||||
if (mirrors != null && mirrors.length > 1) {
|
||||
for (String m: mirrors) {
|
||||
if (!m.equals(address)) {
|
||||
if (FDroidApp.isUsingTor()) {
|
||||
for (String m : getMirrorList()) {
|
||||
if (!m.equals(address)) {
|
||||
if (FDroidApp.isUsingTor()) {
|
||||
count++;
|
||||
} else {
|
||||
if (!m.contains(".onion")) {
|
||||
count++;
|
||||
} else {
|
||||
if (!m.contains(".onion")) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -328,7 +353,7 @@ public class Repo extends ValueObject {
|
||||
if (TextUtils.isEmpty(lastWorkingMirror)) {
|
||||
lastWorkingMirror = address;
|
||||
}
|
||||
List<String> shuffledMirrors = Arrays.asList(mirrors);
|
||||
List<String> shuffledMirrors = getMirrorList();
|
||||
Collections.shuffle(shuffledMirrors);
|
||||
if (shuffledMirrors.size() > 1) {
|
||||
for (String m : shuffledMirrors) {
|
||||
|
@ -362,12 +362,13 @@ public interface Schema {
|
||||
String TIMESTAMP = "timestamp";
|
||||
String ICON = "icon";
|
||||
String MIRRORS = "mirrors";
|
||||
String USER_MIRRORS = "userMirrors";
|
||||
String PUSH_REQUESTS = "pushRequests";
|
||||
|
||||
String[] ALL = {
|
||||
_ID, ADDRESS, NAME, DESCRIPTION, IN_USE, PRIORITY, SIGNING_CERT,
|
||||
FINGERPRINT, MAX_AGE, LAST_UPDATED, LAST_ETAG, VERSION, IS_SWAP,
|
||||
USERNAME, PASSWORD, TIMESTAMP, ICON, MIRRORS, PUSH_REQUESTS,
|
||||
USERNAME, PASSWORD, TIMESTAMP, ICON, MIRRORS, USER_MIRRORS, PUSH_REQUESTS,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -61,12 +61,15 @@ import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
@SuppressWarnings("LineLength")
|
||||
@ -76,7 +79,7 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
private static final String DEFAULT_NEW_REPO_TEXT = "https://";
|
||||
|
||||
private enum AddRepoState {
|
||||
DOESNT_EXIST, EXISTS_FINGERPRINT_MISMATCH, EXISTS_FINGERPRINT_MATCH,
|
||||
DOESNT_EXIST, EXISTS_FINGERPRINT_MISMATCH, EXISTS_ADD_MIRROR,
|
||||
EXISTS_DISABLED, EXISTS_ENABLED, EXISTS_UPGRADABLE_TO_SIGNED, INVALID_URL,
|
||||
IS_SWAP
|
||||
}
|
||||
@ -213,18 +216,35 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
private class AddRepo {
|
||||
|
||||
private final Context context;
|
||||
private final HashMap<String, Repo> urlRepoMap = new HashMap<>();
|
||||
private final HashMap<String, Repo> fingerprintRepoMap = new HashMap<>();
|
||||
private final AlertDialog addRepoDialog;
|
||||
|
||||
private final TextView overwriteMessage;
|
||||
private final ColorStateList defaultTextColour;
|
||||
private final Button addButton;
|
||||
|
||||
private AddRepoState addRepoState;
|
||||
|
||||
/**
|
||||
* Create new instance, setup GUI, and build maps for quickly looking
|
||||
* up repos based on URL or fingerprint. These need to be in maps
|
||||
* since the user input is validated as they are typing. This also
|
||||
* checks that the repo type matches, e.g. "repo" or "archive".
|
||||
*/
|
||||
AddRepo(String newAddress, String newFingerprint, final String username, final String password) {
|
||||
|
||||
context = ManageReposActivity.this;
|
||||
|
||||
for (Repo repo : RepoProvider.Helper.all(context)) {
|
||||
urlRepoMap.put(repo.address, repo);
|
||||
for (String url : repo.getMirrorList()) {
|
||||
urlRepoMap.put(url, repo);
|
||||
}
|
||||
if (TextUtils.equals(getRepoType(newAddress), getRepoType(repo.address))) {
|
||||
fingerprintRepoMap.put(repo.fingerprint, repo);
|
||||
}
|
||||
}
|
||||
|
||||
final View view = getLayoutInflater().inflate(R.layout.addrepo, null);
|
||||
addRepoDialog = new AlertDialog.Builder(context).setView(view).create();
|
||||
final EditText uriEditText = (EditText) view.findViewById(R.id.edit_uri);
|
||||
@ -297,7 +317,7 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
|
||||
case EXISTS_DISABLED:
|
||||
case EXISTS_UPGRADABLE_TO_SIGNED:
|
||||
case EXISTS_FINGERPRINT_MATCH:
|
||||
case EXISTS_ADD_MIRROR:
|
||||
updateAndEnableExistingRepo(url, fp);
|
||||
finishedAddingRepo();
|
||||
break;
|
||||
@ -347,9 +367,31 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
validateRepoDetails(newAddress == null ? "" : newAddress, newFingerprint == null ? "" : newFingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the repo type as represented by the final segment of the path. This is
|
||||
* a bit trickier with {@code content://} URLs, since they might have
|
||||
* encoded "/" chars in it, for example:
|
||||
* {@code content://authority/tree/313E-1F1C%3A/document/313E-1F1C%3Aguardianproject.info%2Ffdroid%2Frepo}
|
||||
*/
|
||||
private String getRepoType(String url) {
|
||||
String last = Uri.parse(url).getLastPathSegment();
|
||||
if (last == null) {
|
||||
return "";
|
||||
} else {
|
||||
return new File(last).getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the repo and the fingerprint against existing repositories, to see if this
|
||||
* repo matches and display a relevant message to the user if that is the case.
|
||||
* repo matches and display a relevant message to the user if that is the case. There
|
||||
* are many different cases to handle:
|
||||
* <ul>
|
||||
* <li> a signed repo with a {@link Repo#address URL} and fingerprint that matches
|
||||
* <li> a signed repo with a matching fingerprint and URL that matches a mirror
|
||||
* <li> a signed repo with a matching fingerprint, but the URL doesn't match any known mirror
|
||||
* <li>an unsigned repo and no fingerprint was supplied
|
||||
* </ul>
|
||||
*/
|
||||
private void validateRepoDetails(@NonNull String uri, @NonNull String fingerprint) {
|
||||
|
||||
@ -361,7 +403,10 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
// to the user until they try to save the repo.
|
||||
}
|
||||
|
||||
final Repo repo = !TextUtils.isEmpty(uri) ? RepoProvider.Helper.findByAddress(context, uri) : null;
|
||||
Repo repo = fingerprintRepoMap.get(fingerprint);
|
||||
if (repo == null) {
|
||||
repo = urlRepoMap.get(uri);
|
||||
}
|
||||
|
||||
if (repo == null) {
|
||||
repoDoesntExist(repo);
|
||||
@ -373,9 +418,10 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
} else if (repo.fingerprint != null && !repo.fingerprint.equalsIgnoreCase(fingerprint)) {
|
||||
repoFingerprintDoesntMatch(repo);
|
||||
} else {
|
||||
// Could be either an unsigned repo, and no fingerprint was supplied,
|
||||
// or it could be a signed repo with a matching fingerprint.
|
||||
if (repo.inuse) {
|
||||
if (!TextUtils.equals(repo.address, uri)
|
||||
&& !repo.getMirrorList().contains(uri)) {
|
||||
repoExistsAddMirror(repo);
|
||||
} else if (repo.inuse) {
|
||||
repoExistsAndEnabled(repo);
|
||||
} else {
|
||||
repoExistsAndDisabled(repo);
|
||||
@ -659,11 +705,34 @@ public class ManageReposActivity extends AppCompatActivity implements LoaderMana
|
||||
}
|
||||
|
||||
Utils.debugLog(TAG, "Enabling existing repo: " + url);
|
||||
Repo repo = RepoProvider.Helper.findByAddress(context, url);
|
||||
Repo repo = fingerprintRepoMap.get(fingerprint);
|
||||
if (repo == null) {
|
||||
repo = RepoProvider.Helper.findByAddress(context, url);
|
||||
}
|
||||
|
||||
ContentValues values = new ContentValues(2);
|
||||
values.put(RepoTable.Cols.IN_USE, 1);
|
||||
values.put(RepoTable.Cols.FINGERPRINT, fingerprint);
|
||||
if (!TextUtils.equals(url, repo.address)) {
|
||||
boolean addUserMirror = true;
|
||||
for (String mirror : repo.getMirrorList()) {
|
||||
if (TextUtils.equals(mirror, url)) {
|
||||
addUserMirror = false;
|
||||
}
|
||||
}
|
||||
if (addUserMirror) {
|
||||
if (repo.userMirrors == null) {
|
||||
repo.userMirrors = new String[]{url};
|
||||
} else {
|
||||
int last = repo.userMirrors.length;
|
||||
repo.userMirrors = Arrays.copyOf(repo.userMirrors, last);
|
||||
repo.userMirrors[last] = url;
|
||||
}
|
||||
values.put(RepoTable.Cols.USER_MIRRORS, Utils.serializeCommaSeparatedString(repo.userMirrors));
|
||||
}
|
||||
}
|
||||
RepoProvider.Helper.update(context, repo, values);
|
||||
|
||||
notifyDataSetChanged();
|
||||
finishedAddingRepo();
|
||||
}
|
||||
|
@ -109,6 +109,7 @@ public class RepoDetailsActivity extends ActionBarActivity {
|
||||
RepoTable.Cols.ADDRESS,
|
||||
RepoTable.Cols.FINGERPRINT,
|
||||
RepoTable.Cols.MIRRORS,
|
||||
RepoTable.Cols.USER_MIRRORS,
|
||||
};
|
||||
repo = RepoProvider.Helper.findById(this, repoId, projection);
|
||||
|
||||
@ -340,6 +341,19 @@ public class RepoDetailsActivity extends ActionBarActivity {
|
||||
}
|
||||
officialMirrorsText.setText(builder.toString());
|
||||
}
|
||||
if (repo.userMirrors != null) {
|
||||
TextView userMirrorsLabel = (TextView) repoView.findViewById(R.id.label_user_mirrors);
|
||||
userMirrorsLabel.setVisibility(View.VISIBLE);
|
||||
TextView userMirrorsText = (TextView) repoView.findViewById(R.id.text_user_mirrors);
|
||||
userMirrorsText.setVisibility(View.VISIBLE);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String url : repo.userMirrors) {
|
||||
builder.append("◦ ");
|
||||
builder.append(url);
|
||||
builder.append('\n');
|
||||
}
|
||||
userMirrorsText.setText(builder.toString());
|
||||
}
|
||||
|
||||
name.setText(repo.name);
|
||||
|
||||
|
@ -116,6 +116,7 @@ This often occurs with apps installed via Google Play or other sources, if they
|
||||
<string name="no">No</string>
|
||||
<string name="repo_add_title">Add new repository</string>
|
||||
<string name="repo_add_add">Add</string>
|
||||
<string name="repo_add_mirror">Add mirror</string>
|
||||
<string name="links">Links</string>
|
||||
<string name="versions">Versions</string>
|
||||
<string name="more">More</string>
|
||||
@ -138,6 +139,7 @@ This often occurs with apps installed via Google Play or other sources, if they
|
||||
<string name="repo_exists_enable">%1$s is already setup, confirm that you want to re-enable it.</string>
|
||||
<string name="repo_exists_and_enabled">%1$s is already setup and enabled.</string>
|
||||
<string name="repo_delete_to_overwrite">First delete %1$s in order to add this with a conflicting key.</string>
|
||||
<string name="repo_exists_add_mirror">This is a copy of %1$s, add it as a mirror?</string>
|
||||
<string name="bad_fingerprint">Bad fingerprint</string>
|
||||
<string name="invalid_url">This is not a valid URL.</string>
|
||||
<string name="malformed_repo_uri">Ignoring malformed repo URI: %s</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user