Merge branch 'switches-to-disable-mirrors' into 'master'
add switches to disable mirrors Closes #1696 See merge request fdroid/fdroidclient!795
This commit is contained in:
commit
9897c97ef8
@ -65,9 +65,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
@ -295,7 +295,7 @@ public class IndexV1Updater extends IndexUpdater {
|
|||||||
repo.description = getStringRepoValue(repoMap, "description");
|
repo.description = getStringRepoValue(repoMap, "description");
|
||||||
|
|
||||||
// ensure the canonical URL is included in the "mirrors" list as the first entry
|
// ensure the canonical URL is included in the "mirrors" list as the first entry
|
||||||
TreeSet<String> mirrors = new TreeSet<>();
|
LinkedHashSet<String> mirrors = new LinkedHashSet<>();
|
||||||
mirrors.add(repo.address);
|
mirrors.add(repo.address);
|
||||||
mirrors.addAll(getStringListRepoValue(repoMap, "mirrors"));
|
mirrors.addAll(getStringListRepoValue(repoMap, "mirrors"));
|
||||||
repo.mirrors = mirrors.toArray(new String[mirrors.size()]);
|
repo.mirrors = mirrors.toArray(new String[mirrors.size()]);
|
||||||
|
@ -97,6 +97,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
+ RepoTable.Cols.ICON + " string, "
|
+ RepoTable.Cols.ICON + " string, "
|
||||||
+ RepoTable.Cols.MIRRORS + " string, "
|
+ RepoTable.Cols.MIRRORS + " string, "
|
||||||
+ RepoTable.Cols.USER_MIRRORS + " string, "
|
+ RepoTable.Cols.USER_MIRRORS + " string, "
|
||||||
|
+ RepoTable.Cols.DISABLED_MIRRORS + " string, "
|
||||||
+ RepoTable.Cols.PUSH_REQUESTS + " integer not null default " + Repo.PUSH_REQUEST_IGNORE
|
+ RepoTable.Cols.PUSH_REQUESTS + " integer not null default " + Repo.PUSH_REQUEST_IGNORE
|
||||||
+ ");";
|
+ ");";
|
||||||
|
|
||||||
@ -223,7 +224,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
+ "primary key(" + ApkAntiFeatureJoinTable.Cols.APK_ID + ", " + ApkAntiFeatureJoinTable.Cols.ANTI_FEATURE_ID + ") "
|
+ "primary key(" + ApkAntiFeatureJoinTable.Cols.APK_ID + ", " + ApkAntiFeatureJoinTable.Cols.ANTI_FEATURE_ID + ") "
|
||||||
+ " );";
|
+ " );";
|
||||||
|
|
||||||
protected static final int DB_VERSION = 79;
|
protected static final int DB_VERSION = 80;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -448,6 +449,17 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
addLiberapayID(db, oldVersion);
|
addLiberapayID(db, oldVersion);
|
||||||
addUserMirrorsFields(db, oldVersion);
|
addUserMirrorsFields(db, oldVersion);
|
||||||
removeNotNullFromVersionName(db, oldVersion);
|
removeNotNullFromVersionName(db, oldVersion);
|
||||||
|
addDisabledMirrorsFields(db, oldVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDisabledMirrorsFields(SQLiteDatabase db, int oldVersion) {
|
||||||
|
if (oldVersion >= 80) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!columnExists(db, RepoTable.NAME, RepoTable.Cols.DISABLED_MIRRORS)) {
|
||||||
|
Utils.debugLog(TAG, "Adding " + RepoTable.Cols.DISABLED_MIRRORS + " field to " + RepoTable.NAME + " table in db.");
|
||||||
|
db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.DISABLED_MIRRORS + " string;");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeNotNullFromVersionName(SQLiteDatabase db, int oldVersion) {
|
private void removeNotNullFromVersionName(SQLiteDatabase db, int oldVersion) {
|
||||||
|
@ -86,6 +86,9 @@ public class Repo extends ValueObject {
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public int pushRequests = PUSH_REQUEST_IGNORE;
|
public int pushRequests = PUSH_REQUEST_IGNORE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The canonical URL of the repo.
|
||||||
|
*/
|
||||||
public String address;
|
public String address;
|
||||||
public String name;
|
public String name;
|
||||||
public String description;
|
public String description;
|
||||||
@ -125,8 +128,15 @@ public class Repo extends ValueObject {
|
|||||||
/**
|
/**
|
||||||
* Mirrors added by the user, either by UI input or by attaching removeable storage
|
* Mirrors added by the user, either by UI input or by attaching removeable storage
|
||||||
*/
|
*/
|
||||||
|
@JsonIgnore
|
||||||
public String[] userMirrors;
|
public String[] userMirrors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mirrors that have been manually disabled by the user.
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public String[] disabledMirrors;
|
||||||
|
|
||||||
public Repo() {
|
public Repo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,6 +203,9 @@ public class Repo extends ValueObject {
|
|||||||
case Cols.USER_MIRRORS:
|
case Cols.USER_MIRRORS:
|
||||||
userMirrors = Utils.parseCommaSeparatedString(cursor.getString(i));
|
userMirrors = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||||
break;
|
break;
|
||||||
|
case Cols.DISABLED_MIRRORS:
|
||||||
|
disabledMirrors = Utils.parseCommaSeparatedString(cursor.getString(i));
|
||||||
|
break;
|
||||||
case Cols.PUSH_REQUESTS:
|
case Cols.PUSH_REQUESTS:
|
||||||
pushRequests = cursor.getInt(i);
|
pushRequests = cursor.getInt(i);
|
||||||
break;
|
break;
|
||||||
@ -334,6 +347,10 @@ public class Repo extends ValueObject {
|
|||||||
userMirrors = Utils.parseCommaSeparatedString(values.getAsString(Cols.USER_MIRRORS));
|
userMirrors = Utils.parseCommaSeparatedString(values.getAsString(Cols.USER_MIRRORS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (values.containsKey(Cols.DISABLED_MIRRORS)) {
|
||||||
|
disabledMirrors = Utils.parseCommaSeparatedString(values.getAsString(Cols.DISABLED_MIRRORS));
|
||||||
|
}
|
||||||
|
|
||||||
if (values.containsKey(Cols.PUSH_REQUESTS)) {
|
if (values.containsKey(Cols.PUSH_REQUESTS)) {
|
||||||
pushRequests = toInt(values.getAsInteger(Cols.PUSH_REQUESTS));
|
pushRequests = toInt(values.getAsInteger(Cols.PUSH_REQUESTS));
|
||||||
}
|
}
|
||||||
@ -345,8 +362,9 @@ public class Repo extends ValueObject {
|
|||||||
* mirror list.
|
* mirror list.
|
||||||
*/
|
*/
|
||||||
public boolean hasMirrors() {
|
public boolean hasMirrors() {
|
||||||
return (mirrors != null && mirrors.length > 1)
|
List<String> mirrorList = getMirrorList();
|
||||||
|| (userMirrors != null && userMirrors.length > 0);
|
int size = mirrorList.size();
|
||||||
|
return size > 1 || (size == 1 && !mirrorList.contains(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -361,6 +379,9 @@ public class Repo extends ValueObject {
|
|||||||
allMirrors.addAll(Arrays.asList(mirrors));
|
allMirrors.addAll(Arrays.asList(mirrors));
|
||||||
}
|
}
|
||||||
allMirrors.add(address);
|
allMirrors.add(address);
|
||||||
|
if (disabledMirrors != null) {
|
||||||
|
allMirrors.removeAll(Arrays.asList(disabledMirrors));
|
||||||
|
}
|
||||||
return new ArrayList<>(allMirrors);
|
return new ArrayList<>(allMirrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,9 +403,11 @@ public class Repo extends ValueObject {
|
|||||||
/**
|
/**
|
||||||
* Get a random mirror URL from the list of mirrors for this repo. It will
|
* Get a random mirror URL from the list of mirrors for this repo. It will
|
||||||
* remove the URL in {@code mirrorToSkip} from consideration before choosing
|
* remove the URL in {@code mirrorToSkip} from consideration before choosing
|
||||||
* which mirror to return.
|
* which mirror to return. {@link #getMirrorList()} returns a list of all
|
||||||
|
* known mirrors <b>minus</b> the mirrors that have been disabled by the
|
||||||
|
* user preference, e.g. {@link #disabledMirrors}.
|
||||||
* <p>
|
* <p>
|
||||||
* The mirror logic assumes that it has a mirrors list with at least once
|
* The mirror logic assumes that it has a mirrors list with at least one
|
||||||
* valid entry in it. In the index format as defined by {@code fdroid update},
|
* valid entry in it. In the index format as defined by {@code fdroid update},
|
||||||
* there is always at least one valid URL: the canonical URL. That also means
|
* there is always at least one valid URL: the canonical URL. That also means
|
||||||
* if there is only one item in the mirrors list, there are no other URLs to try.
|
* if there is only one item in the mirrors list, there are no other URLs to try.
|
||||||
@ -394,6 +417,8 @@ public class Repo extends ValueObject {
|
|||||||
* update. That makes it possible to do the first index update via SD Card
|
* update. That makes it possible to do the first index update via SD Card
|
||||||
* or USB OTG drive.
|
* or USB OTG drive.
|
||||||
*
|
*
|
||||||
|
* @see #getMirrorList()
|
||||||
|
* @see #disabledMirrors
|
||||||
* @see FDroidApp#resetMirrorVars()
|
* @see FDroidApp#resetMirrorVars()
|
||||||
* @see FDroidApp#switchUrlToNewMirror(String, Repo)
|
* @see FDroidApp#switchUrlToNewMirror(String, Repo)
|
||||||
* @see FDroidApp#getTimeout()
|
* @see FDroidApp#getTimeout()
|
||||||
@ -403,7 +428,7 @@ public class Repo extends ValueObject {
|
|||||||
mirrorToSkip = address;
|
mirrorToSkip = address;
|
||||||
}
|
}
|
||||||
List<String> shuffledMirrors = getMirrorList();
|
List<String> shuffledMirrors = getMirrorList();
|
||||||
if (shuffledMirrors.size() > 1) {
|
if (shuffledMirrors.size() > 0) {
|
||||||
Collections.shuffle(shuffledMirrors);
|
Collections.shuffle(shuffledMirrors);
|
||||||
for (String m : shuffledMirrors) {
|
for (String m : shuffledMirrors) {
|
||||||
// Return a non default, and not last used mirror
|
// Return a non default, and not last used mirror
|
||||||
@ -419,6 +444,6 @@ public class Repo extends ValueObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null; // In case we are out of mirrors.
|
return address; // In case we are out of mirrors.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -363,12 +363,13 @@ public interface Schema {
|
|||||||
String ICON = "icon";
|
String ICON = "icon";
|
||||||
String MIRRORS = "mirrors";
|
String MIRRORS = "mirrors";
|
||||||
String USER_MIRRORS = "userMirrors";
|
String USER_MIRRORS = "userMirrors";
|
||||||
|
String DISABLED_MIRRORS = "disabledMirrors";
|
||||||
String PUSH_REQUESTS = "pushRequests";
|
String PUSH_REQUESTS = "pushRequests";
|
||||||
|
|
||||||
String[] ALL = {
|
String[] ALL = {
|
||||||
_ID, ADDRESS, NAME, DESCRIPTION, IN_USE, PRIORITY, SIGNING_CERT,
|
_ID, ADDRESS, NAME, DESCRIPTION, IN_USE, PRIORITY, SIGNING_CERT,
|
||||||
FINGERPRINT, MAX_AGE, LAST_UPDATED, LAST_ETAG, VERSION, IS_SWAP,
|
FINGERPRINT, MAX_AGE, LAST_UPDATED, LAST_ETAG, VERSION, IS_SWAP,
|
||||||
USERNAME, PASSWORD, TIMESTAMP, ICON, MIRRORS, USER_MIRRORS, PUSH_REQUESTS,
|
USERNAME, PASSWORD, TIMESTAMP, ICON, MIRRORS, USER_MIRRORS, DISABLED_MIRRORS, PUSH_REQUESTS,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,23 @@ import android.nfc.NfcAdapter;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.format.DateUtils;
|
import android.text.format.DateUtils;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.CompoundButton;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@ -38,6 +44,8 @@ import org.fdroid.fdroid.data.Repo;
|
|||||||
import org.fdroid.fdroid.data.RepoProvider;
|
import org.fdroid.fdroid.data.RepoProvider;
|
||||||
import org.fdroid.fdroid.data.Schema.RepoTable;
|
import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class RepoDetailsActivity extends AppCompatActivity {
|
public class RepoDetailsActivity extends AppCompatActivity {
|
||||||
@ -76,6 +84,8 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
|||||||
private View repoView;
|
private View repoView;
|
||||||
private String shareUrl;
|
private String shareUrl;
|
||||||
|
|
||||||
|
private MirrorAdapter adapterToNotify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Help function to make switching between two view states easier.
|
* Help function to make switching between two view states easier.
|
||||||
* Perhaps there is a better way to do this. I recall that using Adobe
|
* Perhaps there is a better way to do this. I recall that using Adobe
|
||||||
@ -103,18 +113,20 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
|||||||
repoView = findViewById(R.id.repo_view);
|
repoView = findViewById(R.id.repo_view);
|
||||||
|
|
||||||
repoId = getIntent().getLongExtra(ARG_REPO_ID, 0);
|
repoId = getIntent().getLongExtra(ARG_REPO_ID, 0);
|
||||||
final String[] projection = {
|
repo = RepoProvider.Helper.findById(this, repoId);
|
||||||
RepoTable.Cols.NAME,
|
|
||||||
RepoTable.Cols.ADDRESS,
|
|
||||||
RepoTable.Cols.FINGERPRINT,
|
|
||||||
RepoTable.Cols.MIRRORS,
|
|
||||||
RepoTable.Cols.USER_MIRRORS,
|
|
||||||
};
|
|
||||||
repo = RepoProvider.Helper.findById(this, repoId, projection);
|
|
||||||
|
|
||||||
TextView inputUrl = findViewById(R.id.input_repo_url);
|
TextView inputUrl = findViewById(R.id.input_repo_url);
|
||||||
inputUrl.setText(repo.address);
|
inputUrl.setText(repo.address);
|
||||||
|
|
||||||
|
RecyclerView officialMirrorListView = findViewById(R.id.official_mirror_list);
|
||||||
|
officialMirrorListView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
adapterToNotify = new MirrorAdapter(repo, repo.mirrors);
|
||||||
|
officialMirrorListView.setAdapter(adapterToNotify);
|
||||||
|
|
||||||
|
RecyclerView userMirrorListView = findViewById(R.id.user_mirror_list);
|
||||||
|
userMirrorListView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
userMirrorListView.setAdapter(new MirrorAdapter(repo, repo.userMirrors));
|
||||||
|
|
||||||
if (repo.address.startsWith("content://")) {
|
if (repo.address.startsWith("content://")) {
|
||||||
// no need to show a QR Code, it is not shareable
|
// no need to show a QR Code, it is not shareable
|
||||||
return;
|
return;
|
||||||
@ -324,17 +336,35 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateRepoView() {
|
private void updateRepoView() {
|
||||||
|
TextView officialMirrorsLabel = repoView.findViewById(R.id.label_official_mirrors);
|
||||||
|
RecyclerView officialMirrorList = repoView.findViewById(R.id.official_mirror_list);
|
||||||
|
if ((repo.mirrors != null && repo.mirrors.length > 1)
|
||||||
|
|| (repo.userMirrors != null && repo.userMirrors.length > 0)) {
|
||||||
|
// don't show this if there is only the canonical URL available, and no other mirrors
|
||||||
|
officialMirrorsLabel.setVisibility(View.VISIBLE);
|
||||||
|
officialMirrorList.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
officialMirrorsLabel.setVisibility(View.GONE);
|
||||||
|
officialMirrorList.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView userMirrorsLabel = repoView.findViewById(R.id.label_user_mirrors);
|
||||||
|
RecyclerView userMirrorList = repoView.findViewById(R.id.user_mirror_list);
|
||||||
|
if (repo.userMirrors != null && repo.userMirrors.length > 0) {
|
||||||
|
userMirrorsLabel.setVisibility(View.VISIBLE);
|
||||||
|
userMirrorList.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
userMirrorsLabel.setVisibility(View.GONE);
|
||||||
|
userMirrorList.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
if (repo.hasBeenUpdated()) {
|
if (repo.hasBeenUpdated()) {
|
||||||
updateViewForExistingRepo(repoView);
|
updateViewForExistingRepo(repoView);
|
||||||
} else {
|
} else {
|
||||||
updateViewForNewRepo(repoView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateViewForNewRepo(View repoView) {
|
|
||||||
setMultipleViewVisibility(repoView, HIDE_IF_EXISTS, View.VISIBLE);
|
setMultipleViewVisibility(repoView, HIDE_IF_EXISTS, View.VISIBLE);
|
||||||
setMultipleViewVisibility(repoView, SHOW_IF_EXISTS, View.GONE);
|
setMultipleViewVisibility(repoView, SHOW_IF_EXISTS, View.GONE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateViewForExistingRepo(View repoView) {
|
private void updateViewForExistingRepo(View repoView) {
|
||||||
setMultipleViewVisibility(repoView, SHOW_IF_EXISTS, View.VISIBLE);
|
setMultipleViewVisibility(repoView, SHOW_IF_EXISTS, View.VISIBLE);
|
||||||
@ -344,35 +374,6 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
|||||||
TextView numApps = repoView.findViewById(R.id.text_num_apps);
|
TextView numApps = repoView.findViewById(R.id.text_num_apps);
|
||||||
TextView lastUpdated = repoView.findViewById(R.id.text_last_update);
|
TextView lastUpdated = repoView.findViewById(R.id.text_last_update);
|
||||||
|
|
||||||
if (repo.mirrors != null) {
|
|
||||||
TextView officialMirrorsLabel = repoView.findViewById(R.id.label_official_mirrors);
|
|
||||||
officialMirrorsLabel.setVisibility(View.VISIBLE);
|
|
||||||
TextView officialMirrorsText = repoView.findViewById(R.id.text_official_mirrors);
|
|
||||||
officialMirrorsText.setVisibility(View.VISIBLE);
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
for (String url : repo.mirrors) {
|
|
||||||
builder.append("• ");
|
|
||||||
builder.append(url);
|
|
||||||
builder.append('\n');
|
|
||||||
}
|
|
||||||
builder.setLength(Math.max(builder.length() - 1, 0));
|
|
||||||
officialMirrorsText.setText(builder.toString());
|
|
||||||
}
|
|
||||||
if (repo.userMirrors != null) {
|
|
||||||
TextView userMirrorsLabel = repoView.findViewById(R.id.label_user_mirrors);
|
|
||||||
userMirrorsLabel.setVisibility(View.VISIBLE);
|
|
||||||
TextView userMirrorsText = 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');
|
|
||||||
}
|
|
||||||
builder.setLength(Math.max(builder.length() - 1, 0));
|
|
||||||
userMirrorsText.setText(builder.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
name.setText(repo.name);
|
name.setText(repo.name);
|
||||||
|
|
||||||
int appCount = RepoProvider.Helper.countAppsForRepo(this, repoId);
|
int appCount = RepoProvider.Helper.countAppsForRepo(this, repoId);
|
||||||
@ -464,4 +465,98 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
credentialsDialog.show();
|
credentialsDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class MirrorAdapter extends RecyclerView.Adapter<MirrorAdapter.MirrorViewHolder> {
|
||||||
|
private final Repo repo;
|
||||||
|
private final String[] mirrors;
|
||||||
|
|
||||||
|
class MirrorViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
View view;
|
||||||
|
|
||||||
|
MirrorViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
|
this.view = view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MirrorAdapter(Repo repo, String[] mirrors) {
|
||||||
|
this.repo = repo;
|
||||||
|
this.mirrors = mirrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public MirrorAdapter.MirrorViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.repo_item, parent, false);
|
||||||
|
return new MirrorViewHolder(itemView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull MirrorViewHolder holder, final int position) {
|
||||||
|
TextView repoNameTextView = holder.view.findViewById(R.id.repo_name);
|
||||||
|
repoNameTextView.setText(mirrors[position]);
|
||||||
|
|
||||||
|
final String itemMirror = mirrors[position];
|
||||||
|
boolean enabled = true;
|
||||||
|
if (repo.disabledMirrors != null) {
|
||||||
|
for (String disabled : repo.disabledMirrors) {
|
||||||
|
if (TextUtils.equals(itemMirror, disabled)) {
|
||||||
|
enabled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CompoundButton switchView = holder.view.findViewById(R.id.repo_switch);
|
||||||
|
switchView.setChecked(enabled);
|
||||||
|
switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||||
|
HashSet<String> disabledMirrors;
|
||||||
|
if (repo.disabledMirrors == null) {
|
||||||
|
disabledMirrors = new HashSet<>(1);
|
||||||
|
} else {
|
||||||
|
disabledMirrors = new HashSet<>(Arrays.asList(repo.disabledMirrors));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isChecked) {
|
||||||
|
disabledMirrors.remove(itemMirror);
|
||||||
|
} else {
|
||||||
|
disabledMirrors.add(itemMirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalMirrors = (repo.mirrors == null ? 0 : repo.mirrors.length)
|
||||||
|
+ (repo.userMirrors == null ? 0 : repo.userMirrors.length);
|
||||||
|
if (disabledMirrors.size() == totalMirrors) {
|
||||||
|
// if all mirrors are disabled, re-enable canonical repo as mirror
|
||||||
|
disabledMirrors.remove(repo.address);
|
||||||
|
adapterToNotify.notifyItemChanged(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (disabledMirrors.size() == 0) {
|
||||||
|
repo.disabledMirrors = null;
|
||||||
|
} else {
|
||||||
|
repo.disabledMirrors = disabledMirrors.toArray(new String[disabledMirrors.size()]);
|
||||||
|
}
|
||||||
|
final ContentValues values = new ContentValues(1);
|
||||||
|
values.put(RepoTable.Cols.DISABLED_MIRRORS,
|
||||||
|
Utils.serializeCommaSeparatedString(repo.disabledMirrors));
|
||||||
|
RepoProvider.Helper.update(RepoDetailsActivity.this, repo, values);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
View repoUnverified = holder.view.findViewById(R.id.repo_unverified);
|
||||||
|
repoUnverified.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
View repoUnsigned = holder.view.findViewById(R.id.repo_unsigned);
|
||||||
|
repoUnsigned.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
if (mirrors == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return mirrors.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
@ -83,10 +84,11 @@
|
|||||||
android:text="@string/repo_official_mirrors"
|
android:text="@string/repo_official_mirrors"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/text_official_mirrors"
|
android:id="@+id/official_mirror_list"
|
||||||
style="@style/BodyText"
|
android:layout_width="match_parent"
|
||||||
android:visibility="gone" />
|
android:layout_height="wrap_content"
|
||||||
|
tools:listitem="@layout/repo_item" />
|
||||||
|
|
||||||
<!-- mirrors added by the user -->
|
<!-- mirrors added by the user -->
|
||||||
<TextView
|
<TextView
|
||||||
@ -95,10 +97,11 @@
|
|||||||
android:text="@string/repo_user_mirrors"
|
android:text="@string/repo_user_mirrors"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<TextView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/text_user_mirrors"
|
android:id="@+id/user_mirror_list"
|
||||||
style="@style/BodyText"
|
android:layout_width="match_parent"
|
||||||
android:visibility="gone" />
|
android:layout_height="wrap_content"
|
||||||
|
tools:listitem="@layout/repo_item" />
|
||||||
|
|
||||||
<!-- The credentials used to access this repo (optional) -->
|
<!-- The credentials used to access this repo (optional) -->
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -39,8 +39,8 @@ import java.io.InputStream;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -67,6 +67,7 @@ public class IndexV1UpdaterTest extends FDroidProviderTest {
|
|||||||
public static final String TAG = "IndexV1UpdaterTest";
|
public static final String TAG = "IndexV1UpdaterTest";
|
||||||
|
|
||||||
private static final long FAKE_REPO_ID = 0xdeadbeef;
|
private static final long FAKE_REPO_ID = 0xdeadbeef;
|
||||||
|
private static final String TESTY_CANONICAL_URL = "http://testy.at.or.at/fdroid/repo";
|
||||||
private static final String TESTY_JAR = "testy.at.or.at_index-v1.jar";
|
private static final String TESTY_JAR = "testy.at.or.at_index-v1.jar";
|
||||||
private static final String TESTY_CERT = "308204e1308202c9a0030201020204483450fa300d06092a864886f70d01010b050030213110300e060355040b1307462d44726f6964310d300b06035504031304736f7661301e170d3136303832333133333131365a170d3434303130393133333131365a30213110300e060355040b1307462d44726f6964310d300b06035504031304736f766130820222300d06092a864886f70d01010105000382020f003082020a0282020100dfdcd120f3ab224999dddf4ea33ea588d295e4d7130bef48c143e9d76e5c0e0e9e5d45e64208e35feebc79a83f08939dd6a343b7d1e2179930a105a1249ccd36d88ff3feffc6e4dc53dae0163a7876dd45ecc1ddb0adf5099aa56c1a84b52affcd45d0711ffa4de864f35ac0333ebe61ea8673eeda35a88f6af678cc4d0f80b089338ac8f2a8279a64195c611d19445cab3fd1a020afed9bd739bb95142fb2c00a8f847db5ef3325c814f8eb741bacf86ed3907bfe6e4564d2de5895df0c263824e0b75407589bae2d3a4666c13b92102d8781a8ee9bb4a5a1a78c4a9c21efdaf5584da42e84418b28f5a81d0456a3dc5b420991801e6b21e38c99bbe018a5b2d690894a114bc860d35601416aa4dc52216aff8a288d4775cddf8b72d45fd2f87303a8e9c0d67e442530be28eaf139894337266e0b33d57f949256ab32083bcc545bc18a83c9ab8247c12aea037e2b68dee31c734cb1f04f241d3b94caa3a2b258ffaf8e6eae9fbbe029a934dc0a0859c5f120334812693a1c09352340a39f2a678dbc1afa2a978bfee43afefcb7e224a58af2f3d647e5745db59061236b8af6fcfd93b3602f9e456978534f3a7851e800071bf56da80401c81d91c45f82568373af0576b1cc5eef9b85654124b6319770be3cdba3fbebe3715e8918fb6c8966624f3d0e815effac3d2ee06dd34ab9c693218b2c7c06ba99d6b74d4f17b8c3cb0203010001a321301f301d0603551d0e04160414d62bee9f3798509546acc62eb1de14b08b954d4f300d06092a864886f70d01010b05000382020100743f7c5692085895f9d1fffad390fb4202c15f123ed094df259185960fd6dadf66cb19851070f180297bba4e6996a4434616573b375cfee94fee73a4505a7ec29136b7e6c22e6436290e3686fe4379d4e3140ec6a08e70cfd3ed5b634a5eb5136efaaabf5f38e0432d3d79568a556970b8cfba2972f5d23a3856d8a981b9e9bbbbb88f35e708bde9cbc5f681cbd974085b9da28911296fe2579fa64bbe9fa0b93475a7a8db051080b0c5fade0d1c018e7858cd4cbe95145b0620e2f632cbe0f8af9cbf22e2fdaa72245ae31b0877b07181cc69dd2df74454251d8de58d25e76354abe7eb690f22e59b08795a8f2c98c578e0599503d9085927634072c82c9f82abd50fd12b8fd1a9d1954eb5cc0b4cfb5796b5aaec0356643b4a65a368442d92ef94edd3ac6a2b7fe3571b8cf9f462729228aab023ef9183f73792f5379633ccac51079177d604c6bc1873ada6f07d8da6d68c897e88a5fa5d63fdb8df820f46090e0716e7562dd3c140ba279a65b996f60addb0abe29d4bf2f5abe89480771d492307b926d91f02f341b2148502903c43d40f3c6c86a811d060711f0698b384acdcc0add44eb54e42962d3d041accc715afd49407715adc09350cb55e8d9281a3b0b6b5fcd91726eede9b7c8b13afdebb2c2b377629595f1096ba62fb14946dbac5f3c5f0b4e5b712e7acc7dcf6c46cdc5e6d6dfdeee55a0c92c2d70f080ac6"; // NOCHECKSTYLE LineLength
|
private static final String TESTY_CERT = "308204e1308202c9a0030201020204483450fa300d06092a864886f70d01010b050030213110300e060355040b1307462d44726f6964310d300b06035504031304736f7661301e170d3136303832333133333131365a170d3434303130393133333131365a30213110300e060355040b1307462d44726f6964310d300b06035504031304736f766130820222300d06092a864886f70d01010105000382020f003082020a0282020100dfdcd120f3ab224999dddf4ea33ea588d295e4d7130bef48c143e9d76e5c0e0e9e5d45e64208e35feebc79a83f08939dd6a343b7d1e2179930a105a1249ccd36d88ff3feffc6e4dc53dae0163a7876dd45ecc1ddb0adf5099aa56c1a84b52affcd45d0711ffa4de864f35ac0333ebe61ea8673eeda35a88f6af678cc4d0f80b089338ac8f2a8279a64195c611d19445cab3fd1a020afed9bd739bb95142fb2c00a8f847db5ef3325c814f8eb741bacf86ed3907bfe6e4564d2de5895df0c263824e0b75407589bae2d3a4666c13b92102d8781a8ee9bb4a5a1a78c4a9c21efdaf5584da42e84418b28f5a81d0456a3dc5b420991801e6b21e38c99bbe018a5b2d690894a114bc860d35601416aa4dc52216aff8a288d4775cddf8b72d45fd2f87303a8e9c0d67e442530be28eaf139894337266e0b33d57f949256ab32083bcc545bc18a83c9ab8247c12aea037e2b68dee31c734cb1f04f241d3b94caa3a2b258ffaf8e6eae9fbbe029a934dc0a0859c5f120334812693a1c09352340a39f2a678dbc1afa2a978bfee43afefcb7e224a58af2f3d647e5745db59061236b8af6fcfd93b3602f9e456978534f3a7851e800071bf56da80401c81d91c45f82568373af0576b1cc5eef9b85654124b6319770be3cdba3fbebe3715e8918fb6c8966624f3d0e815effac3d2ee06dd34ab9c693218b2c7c06ba99d6b74d4f17b8c3cb0203010001a321301f301d0603551d0e04160414d62bee9f3798509546acc62eb1de14b08b954d4f300d06092a864886f70d01010b05000382020100743f7c5692085895f9d1fffad390fb4202c15f123ed094df259185960fd6dadf66cb19851070f180297bba4e6996a4434616573b375cfee94fee73a4505a7ec29136b7e6c22e6436290e3686fe4379d4e3140ec6a08e70cfd3ed5b634a5eb5136efaaabf5f38e0432d3d79568a556970b8cfba2972f5d23a3856d8a981b9e9bbbbb88f35e708bde9cbc5f681cbd974085b9da28911296fe2579fa64bbe9fa0b93475a7a8db051080b0c5fade0d1c018e7858cd4cbe95145b0620e2f632cbe0f8af9cbf22e2fdaa72245ae31b0877b07181cc69dd2df74454251d8de58d25e76354abe7eb690f22e59b08795a8f2c98c578e0599503d9085927634072c82c9f82abd50fd12b8fd1a9d1954eb5cc0b4cfb5796b5aaec0356643b4a65a368442d92ef94edd3ac6a2b7fe3571b8cf9f462729228aab023ef9183f73792f5379633ccac51079177d604c6bc1873ada6f07d8da6d68c897e88a5fa5d63fdb8df820f46090e0716e7562dd3c140ba279a65b996f60addb0abe29d4bf2f5abe89480771d492307b926d91f02f341b2148502903c43d40f3c6c86a811d060711f0698b384acdcc0add44eb54e42962d3d041accc715afd49407715adc09350cb55e8d9281a3b0b6b5fcd91726eede9b7c8b13afdebb2c2b377629595f1096ba62fb14946dbac5f3c5f0b4e5b712e7acc7dcf6c46cdc5e6d6dfdeee55a0c92c2d70f080ac6"; // NOCHECKSTYLE LineLength
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ public class IndexV1UpdaterTest extends FDroidProviderTest {
|
|||||||
}
|
}
|
||||||
assertEquals("No repos present", 0, RepoProvider.Helper.all(context).size());
|
assertEquals("No repos present", 0, RepoProvider.Helper.all(context).size());
|
||||||
assertEquals("No apps present", 0, AppProvider.Helper.all(context.getContentResolver()).size());
|
assertEquals("No apps present", 0, AppProvider.Helper.all(context.getContentResolver()).size());
|
||||||
Repo repo = MultiIndexUpdaterTest.createRepo("Testy", TESTY_JAR, context, TESTY_CERT);
|
Repo repo = MultiIndexUpdaterTest.createRepo("Testy", TESTY_CANONICAL_URL, context, TESTY_CERT);
|
||||||
repo.timestamp = 1481222110;
|
repo.timestamp = 1481222110;
|
||||||
IndexV1Updater updater = new IndexV1Updater(context, repo);
|
IndexV1Updater updater = new IndexV1Updater(context, repo);
|
||||||
JarFile jarFile = new JarFile(TestUtils.copyResourceToTempFile(TESTY_JAR), true);
|
JarFile jarFile = new JarFile(TestUtils.copyResourceToTempFile(TESTY_JAR), true);
|
||||||
@ -125,10 +126,9 @@ public class IndexV1UpdaterTest extends FDroidProviderTest {
|
|||||||
assertEquals("repo.icon should be set", "fdroid-icon.png", repoFromDb.icon);
|
assertEquals("repo.icon should be set", "fdroid-icon.png", repoFromDb.icon);
|
||||||
String description = "This is a repository of apps to be used with F-Droid. Applications in this repository are either official binaries built by the original application developers, or are binaries built from source by the admin of f-droid.org using the tools on https://gitlab.com/u/fdroid. "; // NOCHECKSTYLE LineLength
|
String description = "This is a repository of apps to be used with F-Droid. Applications in this repository are either official binaries built by the original application developers, or are binaries built from source by the admin of f-droid.org using the tools on https://gitlab.com/u/fdroid. "; // NOCHECKSTYLE LineLength
|
||||||
assertEquals("repo.description should be set", description, repoFromDb.description);
|
assertEquals("repo.description should be set", description, repoFromDb.description);
|
||||||
assertEquals("repo.mirrors should have items", 3, repo.mirrors.length);
|
assertEquals("repo.mirrors should have items", 2, repo.mirrors.length);
|
||||||
assertEquals("repo.mirrors first URL", "http://frkcchxlcvnb4m5a.onion/fdroid/repo", repo.mirrors[0]);
|
assertEquals("second URL in index-v1, but canonical is first", TESTY_CANONICAL_URL, repo.mirrors[0]);
|
||||||
assertEquals("repo.mirrors second URL", "http://testy.at.or.at/fdroid/repo", repo.mirrors[1]);
|
assertEquals("first URL in index-v1", "http://frkcchxlcvnb4m5a.onion/fdroid/repo", repo.mirrors[1]);
|
||||||
assertEquals("repo.mirrors third URL", "testy.at.or.at_index-v1.jar", repo.mirrors[2]);
|
|
||||||
|
|
||||||
// Make sure the per-apk anti features which are new in index v1 get added correctly.
|
// Make sure the per-apk anti features which are new in index v1 get added correctly.
|
||||||
assertEquals(0, AppProvider.Helper.findInstalledAppsWithKnownVulns(context).size());
|
assertEquals(0, AppProvider.Helper.findInstalledAppsWithKnownVulns(context).size());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user