diff --git a/F-Droid/res/layout/addrepo.xml b/F-Droid/res/layout/addrepo.xml
index 1fa9ae01f..d94d86a20 100644
--- a/F-Droid/res/layout/addrepo.xml
+++ b/F-Droid/res/layout/addrepo.xml
@@ -42,13 +42,8 @@
android:id="@+id/overwrite_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:drawableLeft="@android:drawable/ic_dialog_alert"
- android:drawableStart="@android:drawable/ic_dialog_alert"
- android:drawablePadding="20dp"
- android:padding="20dp"
- android:text="@string/repo_delete_to_overwrite"
- android:textAppearance="@android:style/TextAppearance.Medium"
- android:visibility="gone" />
+ android:padding="10dp"
+ tools:text="This repo is already setup, this will add new key information."/>
diff --git a/F-Droid/res/values/strings.xml b/F-Droid/res/values/strings.xml
index 7730fc03f..c362c228e 100644
--- a/F-Droid/res/values/strings.xml
+++ b/F-Droid/res/values/strings.xml
@@ -92,11 +92,11 @@
Repository address
Fingerprint (optional)
- This repo already exists!
+ This repo already exists
This repo is already setup, this will add new key information.
This repo is already setup, confirm that you want to re-enable it.
- The incoming repo is already setup and enabled!
- You must first delete this repo before you can add one with a different key!
+ The incoming repo is already setup and enabled.
+ You must first delete this repo before you can add one with a different key.
Ignoring malformed repo URI: %s
The list of used repositories has
diff --git a/F-Droid/src/org/fdroid/fdroid/views/ManageReposActivity.java b/F-Droid/src/org/fdroid/fdroid/views/ManageReposActivity.java
index 32d48da2c..15912d2d1 100644
--- a/F-Droid/src/org/fdroid/fdroid/views/ManageReposActivity.java
+++ b/F-Droid/src/org/fdroid/fdroid/views/ManageReposActivity.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.ColorStateList;
import android.database.Cursor;
import android.net.Uri;
import android.net.wifi.WifiInfo;
@@ -33,6 +34,7 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
@@ -40,7 +42,9 @@ import android.support.v4.app.NavUtils;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.ActionBarActivity;
+import android.text.Editable;
import android.text.TextUtils;
+import android.text.TextWatcher;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
@@ -92,16 +96,17 @@ public class ManageReposActivity extends ActionBarActivity {
private static final String DEFAULT_NEW_REPO_TEXT = "https://";
- private enum PositiveAction {
- ADD_NEW, ENABLE, IGNORE
+ private enum AddRepoState {
+ DOESNT_EXIST, EXISTS_FINGERPRINT_MISMATCH, EXISTS_FINGERPRINT_MATCH,
+ EXISTS_DISABLED, EXISTS_ENABLED, EXISTS_UPGRADABLE_TO_SIGNED
}
- private PositiveAction positiveAction;
-
private UpdateService.UpdateReceiver updateHandler = null;
private static boolean changed = false;
+ private RepoListFragment listFragment;
+
/**
* True if activity started with an intent such as from QR code. False if
* opened from, e.g. the main menu.
@@ -129,8 +134,10 @@ public class ManageReposActivity extends ActionBarActivity {
setContentView(new LinearLayout(this));
}
+ listFragment = new RepoListFragment();
+
fm.beginTransaction()
- .add(android.R.id.content, new RepoListFragment())
+ .add(android.R.id.content, listFragment)
.commit();
}
@@ -323,6 +330,12 @@ public class ManageReposActivity extends ActionBarActivity {
private final Context context;
private final AlertDialog addRepoDialog;
+ private final TextView overwriteMessage;
+ private final ColorStateList defaultTextColour;
+ private final Button addButton;
+
+ private AddRepoState addRepoState;
+
public AddRepo(String newAddress, String newFingerprint) {
context = ManageReposActivity.this;
@@ -332,13 +345,6 @@ public class ManageReposActivity extends ActionBarActivity {
final EditText uriEditText = (EditText) view.findViewById(R.id.edit_uri);
final EditText fingerprintEditText = (EditText) view.findViewById(R.id.edit_fingerprint);
- // If the "add new repo" dialog is launched by an action outside of
- // FDroid, i.e. a URL, then check to see if any existing repos match,
- // and change the action accordingly.
- final Repo repo = (newAddress != null && isImportingRepo)
- ? RepoProvider.Helper.findByAddress(context, newAddress)
- : null;
-
addRepoDialog.setIcon(android.R.drawable.ic_menu_add);
addRepoDialog.setTitle(getString(R.string.repo_add_title));
@@ -382,64 +388,36 @@ public class ManageReposActivity extends ActionBarActivity {
public void onClick(View v) {
String fp = fingerprintEditText.getText().toString();
+ String url = uriEditText.getText().toString();
- // the DB uses null for no fingerprint but the above
- // code returns "" rather than null if its blank
- if (fp.equals(""))
- fp = null;
+ switch(addRepoState) {
+ case DOESNT_EXIST:
+ prepareToCreateNewRepo(url, fp);
+ break;
- if (positiveAction == PositiveAction.ADD_NEW)
- prepareToCreateNewRepo(uriEditText.getText().toString(), fp);
- else if (positiveAction == PositiveAction.ENABLE) {
- enableExistingRepo(repo);
- finishedAddingRepo();
+ case EXISTS_DISABLED:
+ case EXISTS_UPGRADABLE_TO_SIGNED:
+ case EXISTS_FINGERPRINT_MATCH:
+ updateAndEnableExistingRepo(url, fp);
+ finishedAddingRepo();
+ break;
+
+ default:
+ finishedAddingRepo();
+ break;
}
}
}
);
- final TextView overwriteMessage = (TextView) view.findViewById(R.id.overwrite_message);
+ addButton = addRepoDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ overwriteMessage = (TextView) view.findViewById(R.id.overwrite_message);
overwriteMessage.setVisibility(View.GONE);
- if (repo == null) {
- // no existing repo, add based on what we have
- positiveAction = PositiveAction.ADD_NEW;
- } else {
- // found the address in the DB of existing repos
- final Button addButton = addRepoDialog.getButton(DialogInterface.BUTTON_POSITIVE);
- addRepoDialog.setTitle(R.string.repo_exists);
- overwriteMessage.setVisibility(View.VISIBLE);
- if (newFingerprint != null)
- newFingerprint = newFingerprint.toUpperCase(Locale.ENGLISH);
- if (repo.fingerprint == null && newFingerprint != null) {
- // we're upgrading from unsigned to signed repo
- overwriteMessage.setText(R.string.repo_exists_add_fingerprint);
- addButton.setText(R.string.add_key);
- positiveAction = PositiveAction.ADD_NEW;
- } else if (newFingerprint == null || newFingerprint.equals(repo.fingerprint)) {
- // this entry already exists and is not enabled, offer to enable it
- if (repo.inuse) {
- addRepoDialog.dismiss();
- Toast.makeText(context, R.string.repo_exists_and_enabled, Toast.LENGTH_LONG).show();
- return;
- } else {
- overwriteMessage.setText(R.string.repo_exists_enable);
- addButton.setText(R.string.enable);
- positiveAction = PositiveAction.ENABLE;
- }
- } else {
- // same address with different fingerprint, this could be
- // malicious, so force the user to manually delete the repo
- // before adding this one
- overwriteMessage.setTextColor(getResources().getColor(R.color.red));
- overwriteMessage.setText(R.string.repo_delete_to_overwrite);
- addButton.setText(R.string.overwrite);
- addButton.setEnabled(false);
- positiveAction = PositiveAction.IGNORE;
- }
- }
+ defaultTextColour = overwriteMessage.getTextColors();
- if (newFingerprint != null)
+ if (newFingerprint != null) {
fingerprintEditText.setText(newFingerprint);
+ }
if (newAddress != null) {
// This trick of emptying text then appending, rather than just setting in
@@ -447,6 +425,100 @@ public class ManageReposActivity extends ActionBarActivity {
uriEditText.setText("");
uriEditText.append(newAddress);
}
+
+ final TextWatcher textChangedListener = new TextWatcher() {
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ validateRepoDetails(uriEditText.getText().toString(), fingerprintEditText.getText().toString());
+ }
+ };
+
+ uriEditText.addTextChangedListener(textChangedListener);
+ fingerprintEditText.addTextChangedListener(textChangedListener);
+ validateRepoDetails(newAddress == null ? "" : newAddress, newFingerprint == null ? "" : newFingerprint);
+ }
+
+ /**
+ * 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.
+ */
+ private void validateRepoDetails(@NonNull final String uri, @NonNull String fingerprint) {
+
+ final Repo repo = uri.length() > 0 ? RepoProvider.Helper.findByAddress(context, uri) : null;
+
+ if (repo == null) {
+ repoDoesntExist();
+ } else {
+ if (repo.fingerprint == null && fingerprint.length() > 0) {
+ upgradingToSigned();
+ } else if (repo.fingerprint != null && !repo.fingerprint.equalsIgnoreCase(fingerprint)) {
+ repoFingerprintDoesntMatch();
+ } 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) {
+ repoExistsAndEnabled();
+ } else {
+ repoExistsAndDisabled();
+ }
+ }
+ }
+ }
+
+ private void repoDoesntExist() {
+ updateUi(AddRepoState.DOESNT_EXIST, 0, false, R.string.repo_add_add, true);
+ }
+
+ /**
+ * Same address with different fingerprint, this could be malicious, so display a message
+ * force the user to manually delete the repo before adding this one.
+ */
+ private void repoFingerprintDoesntMatch() {
+ updateUi(AddRepoState.EXISTS_FINGERPRINT_MISMATCH, R.string.repo_delete_to_overwrite,
+ true, R.string.overwrite, false);
+ }
+
+ private void repoExistsAndDisabled() {
+ updateUi(AddRepoState.EXISTS_DISABLED,
+ R.string.repo_exists_enable, false, R.string.enable, true);
+ }
+
+ private void repoExistsAndEnabled() {
+ updateUi(AddRepoState.EXISTS_ENABLED, R.string.repo_exists_and_enabled, false,
+ R.string.ok, true);
+ }
+
+ private void upgradingToSigned() {
+ updateUi(AddRepoState.EXISTS_UPGRADABLE_TO_SIGNED, R.string.repo_exists_add_fingerprint,
+ false, R.string.add_key, true);
+ }
+
+ private void updateUi(AddRepoState state, int messageRes, boolean redMessage, int addTextRes, boolean addEnabled) {
+ if (addRepoState != state) {
+ addRepoState = state;
+
+ if (messageRes > 0) {
+ overwriteMessage.setText(messageRes);
+ overwriteMessage.setVisibility(View.VISIBLE);
+ if (redMessage) {
+ overwriteMessage.setTextColor(getResources().getColor(R.color.red));
+ } else {
+ overwriteMessage.setTextColor(defaultTextColour);
+ }
+ } else {
+ overwriteMessage.setVisibility(View.GONE);
+ }
+
+ addButton.setText(addTextRes);
+ addButton.setEnabled(addEnabled);
+ }
}
/**
@@ -548,11 +620,23 @@ public class ManageReposActivity extends ActionBarActivity {
/**
* Seeing as this repo already exists, we will force it to be enabled again.
*/
- private void enableExistingRepo(Repo repo) {
- ContentValues values = new ContentValues(1);
+ private void updateAndEnableExistingRepo(String url, String fingerprint) {
+ if (fingerprint != null) {
+ fingerprint = fingerprint.trim();
+ if (fingerprint.length() == 0) {
+ fingerprint = null;
+ } else {
+ fingerprint = fingerprint.toUpperCase(Locale.ENGLISH);
+ }
+ }
+
+ Log.d(TAG, "Enabling existing repo: " + url);
+ Repo repo = RepoProvider.Helper.findByAddress(context, url);
+ ContentValues values = new ContentValues(2);
values.put(RepoProvider.DataColumns.IN_USE, 1);
+ values.put(RepoProvider.DataColumns.FINGERPRINT, fingerprint);
RepoProvider.Helper.update(context, repo, values);
- repo.inuse = true;
+ listFragment.notifyDataSetChanged();
finishedAddingRepo();
}
@@ -743,5 +827,15 @@ public class ManageReposActivity extends ActionBarActivity {
intent.putExtra(RepoDetailsFragment.ARG_REPO_ID, repo.getId());
startActivityForResult(intent, SHOW_REPO_DETAILS);
}
+
+ /**
+ * This is necessary because even though the list will listen to content changes
+ * in the RepoProvider, it doesn't update the list items if they are changed (but not
+ * added or removed. The example which made this necessary was enabling an existing
+ * repo, and wanting the switch to be changed to on).
+ */
+ private void notifyDataSetChanged() {
+ getLoaderManager().restartLoader(0, null, this);
+ }
}
}