Merge branch 'master' into 'master'
Improved support for HTTP Basic Authentication Extended DownloaderFactory to support optional username & password parameters. Extended HttpDownloader to check for HTTP 401 Authorization Required status code and send a simple HTTP Basic Authentication header with all requests. Extended ManageReposActivity to support repositories that use HTTP Basic Authentication, added a dialog to prompt for username and password. Extended RepoDetailsActivity to be able to display and modify the authentication credentials. See merge request !171
This commit is contained in:
commit
b9342e909b
60
F-Droid/res/layout/login.xml
Normal file
60
F-Droid/res/layout/login.xml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="24dp"
|
||||||
|
android:paddingStart="24dp"
|
||||||
|
android:paddingRight="24dp"
|
||||||
|
android:paddingEnd="24dp"
|
||||||
|
android:paddingTop="20dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/login_form"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/login_name" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/edit_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textNoSuggestions"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/login_password" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/edit_password"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:maxLines="1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/overwrite_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="10dp"
|
||||||
|
tools:text="This repo is already setup, this will add new key information."/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:padding="10dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:id="@+id/text_searching_for_repo"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:text="Searching for repository at\nhttps://www.example.com/fdroid/repo/" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -75,6 +75,25 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="@style/RepoDetailsBody"/>
|
style="@style/RepoDetailsBody"/>
|
||||||
|
|
||||||
|
<!-- The credentials used to access this repo (optional) -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_username"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/login_name"
|
||||||
|
style="@style/RepoDetailsCaption"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_username"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/RepoDetailsBody"/>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/button_edit_credentials"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:text="@string/repo_edit_credentials"
|
||||||
|
android:onClick="showChangePasswordDialog" />
|
||||||
|
|
||||||
<!-- Signature (or "unsigned" if none) -->
|
<!-- Signature (or "unsigned" if none) -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/label_repo_fingerprint"
|
android:id="@+id/label_repo_fingerprint"
|
||||||
|
@ -36,6 +36,12 @@
|
|||||||
<string name="local_repo_https">Use Private Connection</string>
|
<string name="local_repo_https">Use Private Connection</string>
|
||||||
<string name="local_repo_https_on">Use encrypted HTTPS:// connection for local repo</string>
|
<string name="local_repo_https_on">Use encrypted HTTPS:// connection for local repo</string>
|
||||||
|
|
||||||
|
<string name="login_title">Authentication required</string>
|
||||||
|
<string name="login_name">Username</string>
|
||||||
|
<string name="login_password">Password</string>
|
||||||
|
<string name="repo_edit_credentials">Change Password</string>
|
||||||
|
<string name="repo_error_empty_username">Empty username, credentials not changed</string>
|
||||||
|
|
||||||
<string name="search_results">Search Results</string>
|
<string name="search_results">Search Results</string>
|
||||||
<string name="app_details">App Details</string>
|
<string name="app_details">App Details</string>
|
||||||
<string name="no_such_app">No such app found.</string>
|
<string name="no_such_app">No such app found.</string>
|
||||||
|
@ -95,7 +95,10 @@ public class RepoUpdater {
|
|||||||
Downloader downloader = null;
|
Downloader downloader = null;
|
||||||
try {
|
try {
|
||||||
downloader = DownloaderFactory.create(context,
|
downloader = DownloaderFactory.create(context,
|
||||||
getIndexAddress(), File.createTempFile("index-", "-downloaded", context.getCacheDir()));
|
getIndexAddress(), File.createTempFile("index-", "-downloaded", context.getCacheDir()),
|
||||||
|
repo.username,
|
||||||
|
repo.password
|
||||||
|
);
|
||||||
downloader.setCacheTag(repo.lastetag);
|
downloader.setCacheTag(repo.lastetag);
|
||||||
downloader.downloadUninterrupted();
|
downloader.downloadUninterrupted();
|
||||||
|
|
||||||
|
@ -34,7 +34,9 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
+ "maxage integer not null default 0, "
|
+ "maxage integer not null default 0, "
|
||||||
+ "version integer not null default 0, "
|
+ "version integer not null default 0, "
|
||||||
+ "lastetag text, lastUpdated string,"
|
+ "lastetag text, lastUpdated string,"
|
||||||
+ "isSwap integer boolean default 0);";
|
+ "isSwap integer boolean default 0,"
|
||||||
|
+ "username string, password string"
|
||||||
|
+ ");";
|
||||||
|
|
||||||
private static final String CREATE_TABLE_APK =
|
private static final String CREATE_TABLE_APK =
|
||||||
"CREATE TABLE " + TABLE_APK + " ( "
|
"CREATE TABLE " + TABLE_APK + " ( "
|
||||||
@ -102,7 +104,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
+ " );";
|
+ " );";
|
||||||
private static final String DROP_TABLE_INSTALLED_APP = "DROP TABLE " + TABLE_INSTALLED_APP + ";";
|
private static final String DROP_TABLE_INSTALLED_APP = "DROP TABLE " + TABLE_INSTALLED_APP + ";";
|
||||||
|
|
||||||
private static final int DB_VERSION = 51;
|
private static final int DB_VERSION = 52;
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@ -285,6 +287,7 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
addIconUrlLargeToApp(db, oldVersion);
|
addIconUrlLargeToApp(db, oldVersion);
|
||||||
updateIconUrlLarge(db, oldVersion);
|
updateIconUrlLarge(db, oldVersion);
|
||||||
recreateInstalledCache(db, oldVersion);
|
recreateInstalledCache(db, oldVersion);
|
||||||
|
addCredentialsToRepo(db, oldVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -419,6 +422,20 @@ public class DBHelper extends SQLiteOpenHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addCredentialsToRepo(SQLiteDatabase db, int oldVersion) {
|
||||||
|
if (oldVersion < 52) {
|
||||||
|
if (!columnExists(db, TABLE_REPO, "username")) {
|
||||||
|
Utils.debugLog(TAG, "Adding username field to " + TABLE_REPO + " table in db.");
|
||||||
|
db.execSQL("alter table " + TABLE_REPO + " add column username string;");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!columnExists(db, TABLE_REPO, "password")) {
|
||||||
|
Utils.debugLog(TAG, "Adding password field to " + TABLE_REPO + " table in db.");
|
||||||
|
db.execSQL("alter table " + TABLE_REPO + " add column password string;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addChangelogToApp(SQLiteDatabase db, int oldVersion) {
|
private void addChangelogToApp(SQLiteDatabase db, int oldVersion) {
|
||||||
if (oldVersion < 48 && !columnExists(db, TABLE_APP, "changelogURL")) {
|
if (oldVersion < 48 && !columnExists(db, TABLE_APP, "changelogURL")) {
|
||||||
Utils.debugLog(TAG, "Adding changelogURL column to " + TABLE_APP);
|
Utils.debugLog(TAG, "Adding changelogURL column to " + TABLE_APP);
|
||||||
|
@ -37,6 +37,9 @@ public class Repo extends ValueObject {
|
|||||||
public Date lastUpdated;
|
public Date lastUpdated;
|
||||||
public boolean isSwap;
|
public boolean isSwap;
|
||||||
|
|
||||||
|
public String username;
|
||||||
|
public String password;
|
||||||
|
|
||||||
public Repo() {
|
public Repo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +88,12 @@ public class Repo extends ValueObject {
|
|||||||
case RepoProvider.DataColumns.IS_SWAP:
|
case RepoProvider.DataColumns.IS_SWAP:
|
||||||
isSwap = cursor.getInt(i) == 1;
|
isSwap = cursor.getInt(i) == 1;
|
||||||
break;
|
break;
|
||||||
|
case RepoProvider.DataColumns.USERNAME:
|
||||||
|
username = cursor.getString(i);
|
||||||
|
break;
|
||||||
|
case RepoProvider.DataColumns.PASSWORD:
|
||||||
|
password = cursor.getString(i);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,5 +201,13 @@ public class Repo extends ValueObject {
|
|||||||
if (values.containsKey(RepoProvider.DataColumns.IS_SWAP)) {
|
if (values.containsKey(RepoProvider.DataColumns.IS_SWAP)) {
|
||||||
isSwap = toInt(values.getAsInteger(RepoProvider.DataColumns.IS_SWAP)) == 1;
|
isSwap = toInt(values.getAsInteger(RepoProvider.DataColumns.IS_SWAP)) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (values.containsKey(RepoProvider.DataColumns.USERNAME)) {
|
||||||
|
username = values.getAsString(RepoProvider.DataColumns.USERNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.containsKey(RepoProvider.DataColumns.PASSWORD)) {
|
||||||
|
password = values.getAsString(RepoProvider.DataColumns.PASSWORD);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,10 +223,13 @@ public class RepoProvider extends FDroidProvider {
|
|||||||
String LAST_UPDATED = "lastUpdated";
|
String LAST_UPDATED = "lastUpdated";
|
||||||
String VERSION = "version";
|
String VERSION = "version";
|
||||||
String IS_SWAP = "isSwap";
|
String IS_SWAP = "isSwap";
|
||||||
|
String USERNAME = "username";
|
||||||
|
String PASSWORD = "password";
|
||||||
|
|
||||||
String[] ALL = {
|
String[] ALL = {
|
||||||
_ID, ADDRESS, NAME, DESCRIPTION, IN_USE, PRIORITY, PUBLIC_KEY,
|
_ID, ADDRESS, NAME, DESCRIPTION, IN_USE, PRIORITY, PUBLIC_KEY,
|
||||||
FINGERPRINT, MAX_AGE, LAST_UPDATED, LAST_ETAG, VERSION, IS_SWAP,
|
FINGERPRINT, MAX_AGE, LAST_UPDATED, LAST_ETAG, VERSION, IS_SWAP,
|
||||||
|
USERNAME, PASSWORD,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,5 +379,4 @@ public class RepoProvider extends FDroidProvider {
|
|||||||
getContext().getContentResolver().notifyChange(uri, null);
|
getContext().getContentResolver().notifyChange(uri, null);
|
||||||
return numRows;
|
return numRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,11 @@ public class DownloaderFactory {
|
|||||||
|
|
||||||
public static Downloader create(Context context, URL url, File destFile)
|
public static Downloader create(Context context, URL url, File destFile)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
return create(context, url, destFile, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Downloader create(Context context, URL url, File destFile, final String username, final String password)
|
||||||
|
throws IOException {
|
||||||
if (isBluetoothAddress(url)) {
|
if (isBluetoothAddress(url)) {
|
||||||
String macAddress = url.getHost().replace("-", ":");
|
String macAddress = url.getHost().replace("-", ":");
|
||||||
return new BluetoothDownloader(context, macAddress, url, destFile);
|
return new BluetoothDownloader(context, macAddress, url, destFile);
|
||||||
@ -53,7 +58,7 @@ public class DownloaderFactory {
|
|||||||
} else if (isLocalFile(url)) {
|
} else if (isLocalFile(url)) {
|
||||||
return new LocalFileDownloader(context, url, destFile);
|
return new LocalFileDownloader(context, url, destFile);
|
||||||
}
|
}
|
||||||
return new HttpDownloader(context, url, destFile);
|
return new HttpDownloader(context, url, destFile, username, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isBluetoothAddress(URL url) {
|
private static boolean isBluetoothAddress(URL url) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.fdroid.fdroid.net;
|
package org.fdroid.fdroid.net;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.fdroid.fdroid.FDroidApp;
|
import org.fdroid.fdroid.FDroidApp;
|
||||||
@ -29,11 +30,21 @@ public class HttpDownloader extends Downloader {
|
|||||||
protected static final String HEADER_FIELD_ETAG = "ETag";
|
protected static final String HEADER_FIELD_ETAG = "ETag";
|
||||||
|
|
||||||
protected HttpURLConnection connection;
|
protected HttpURLConnection connection;
|
||||||
private int statusCode = -1;
|
private final String username;
|
||||||
|
private final String password;
|
||||||
|
private int statusCode = -1;
|
||||||
|
|
||||||
HttpDownloader(Context context, URL url, File destFile)
|
HttpDownloader(Context context, URL url, File destFile)
|
||||||
throws FileNotFoundException, MalformedURLException {
|
throws FileNotFoundException, MalformedURLException {
|
||||||
|
this(context, url, destFile, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpDownloader(Context context, URL url, File destFile, final String username, final String password)
|
||||||
|
throws FileNotFoundException, MalformedURLException {
|
||||||
super(context, url, destFile);
|
super(context, url, destFile);
|
||||||
|
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,7 +55,7 @@ public class HttpDownloader extends Downloader {
|
|||||||
* same one twice, bail with an exception).
|
* same one twice, bail with an exception).
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
protected InputStream getDownloadersInputStream() throws IOException {
|
protected InputStream getDownloadersInputStream() throws IOException {
|
||||||
setupConnection();
|
setupConnection();
|
||||||
return new BufferedInputStream(connection.getInputStream());
|
return new BufferedInputStream(connection.getInputStream());
|
||||||
@ -87,10 +98,11 @@ public class HttpDownloader extends Downloader {
|
|||||||
Proxy proxy = new Proxy(Proxy.Type.HTTP, sa);
|
Proxy proxy = new Proxy(Proxy.Type.HTTP, sa);
|
||||||
connection = (HttpURLConnection) sourceUrl.openConnection(proxy);
|
connection = (HttpURLConnection) sourceUrl.openConnection(proxy);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
connection = (HttpURLConnection) sourceUrl.openConnection();
|
connection = (HttpURLConnection) sourceUrl.openConnection();
|
||||||
final String userInfo = sourceUrl.getUserInfo();
|
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) {
|
||||||
if (userInfo != null) {
|
// add authorization header from username / password if set
|
||||||
connection.setRequestProperty("Authorization", "Basic " + Base64.encodeBase64String(userInfo.getBytes()));
|
connection.setRequestProperty("Authorization", "Basic " + Base64.encodeBase64String((username + ":" + password).getBytes()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,6 @@ import android.widget.ListView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.apache.http.client.HttpClient;
|
|
||||||
import org.apache.http.client.methods.HttpHead;
|
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
|
||||||
import org.fdroid.fdroid.FDroid;
|
import org.fdroid.fdroid.FDroid;
|
||||||
import org.fdroid.fdroid.FDroidApp;
|
import org.fdroid.fdroid.FDroidApp;
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
@ -68,6 +65,7 @@ import org.fdroid.fdroid.data.Repo;
|
|||||||
import org.fdroid.fdroid.data.RepoProvider;
|
import org.fdroid.fdroid.data.RepoProvider;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
@ -451,6 +449,8 @@ public class ManageReposActivity extends ActionBarActivity {
|
|||||||
|
|
||||||
final AsyncTask<String, String, String> checker = new AsyncTask<String, String, String>() {
|
final AsyncTask<String, String, String> checker = new AsyncTask<String, String, String>() {
|
||||||
|
|
||||||
|
private int statusCode = -1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String doInBackground(String... params) {
|
protected String doInBackground(String... params) {
|
||||||
|
|
||||||
@ -485,9 +485,14 @@ public class ManageReposActivity extends ActionBarActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkForRepository(Uri indexUri) throws IOException {
|
private boolean checkForRepository(Uri indexUri) throws IOException {
|
||||||
HttpClient client = new DefaultHttpClient();
|
|
||||||
HttpHead head = new HttpHead(indexUri.toString());
|
final URL url = new URL(indexUri.toString());
|
||||||
return client.execute(head).getStatusLine().getStatusCode() == 200;
|
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("HEAD");
|
||||||
|
|
||||||
|
statusCode = connection.getResponseCode();
|
||||||
|
|
||||||
|
return statusCode == 401 || statusCode == 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -497,9 +502,45 @@ public class ManageReposActivity extends ActionBarActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(String newAddress) {
|
protected void onPostExecute(final String newAddress) {
|
||||||
|
|
||||||
if (addRepoDialog.isShowing()) {
|
if (addRepoDialog.isShowing()) {
|
||||||
createNewRepo(newAddress, fingerprint);
|
|
||||||
|
if (statusCode == 401) {
|
||||||
|
|
||||||
|
final View view = getLayoutInflater().inflate(R.layout.login, null);
|
||||||
|
final AlertDialog credentialsDialog = new AlertDialog.Builder(context).setView(view).create();
|
||||||
|
final EditText nameInput = (EditText) view.findViewById(R.id.edit_name);
|
||||||
|
final EditText passwordInput = (EditText) view.findViewById(R.id.edit_password);
|
||||||
|
|
||||||
|
credentialsDialog.setTitle(R.string.login_title);
|
||||||
|
credentialsDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
|
||||||
|
getString(R.string.cancel),
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.dismiss();
|
||||||
|
// cancel parent dialog, don't add repo
|
||||||
|
addRepoDialog.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
credentialsDialog.setButton(DialogInterface.BUTTON_POSITIVE,
|
||||||
|
getString(R.string.ok),
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
createNewRepo(newAddress, fingerprint, nameInput.getText().toString(), passwordInput.getText().toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
credentialsDialog.show();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// create repo without username/password
|
||||||
|
createNewRepo(newAddress, fingerprint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -551,17 +592,30 @@ public class ManageReposActivity extends ActionBarActivity {
|
|||||||
path, uri.getQuery(), uri.getFragment()).toString();
|
path, uri.getQuery(), uri.getFragment()).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a repository without a username or password.
|
||||||
|
*/
|
||||||
private void createNewRepo(String address, String fingerprint) {
|
private void createNewRepo(String address, String fingerprint) {
|
||||||
|
createNewRepo(address, fingerprint, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createNewRepo(String address, String fingerprint, final String username, final String password) {
|
||||||
try {
|
try {
|
||||||
address = normalizeUrl(address);
|
address = normalizeUrl(address);
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
// Leave address as it was.
|
// Leave address as it was.
|
||||||
}
|
}
|
||||||
ContentValues values = new ContentValues(2);
|
ContentValues values = new ContentValues(4);
|
||||||
values.put(RepoProvider.DataColumns.ADDRESS, address);
|
values.put(RepoProvider.DataColumns.ADDRESS, address);
|
||||||
if (!TextUtils.isEmpty(fingerprint)) {
|
if (!TextUtils.isEmpty(fingerprint)) {
|
||||||
values.put(RepoProvider.DataColumns.FINGERPRINT, fingerprint.toUpperCase(Locale.ENGLISH));
|
values.put(RepoProvider.DataColumns.FINGERPRINT, fingerprint.toUpperCase(Locale.ENGLISH));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) {
|
||||||
|
values.put(RepoProvider.DataColumns.USERNAME, username);
|
||||||
|
values.put(RepoProvider.DataColumns.PASSWORD, password);
|
||||||
|
}
|
||||||
|
|
||||||
RepoProvider.Helper.insert(context, values);
|
RepoProvider.Helper.insert(context, values);
|
||||||
finishedAddingRepo();
|
finishedAddingRepo();
|
||||||
Toast.makeText(ManageReposActivity.this, getString(R.string.repo_added, address), Toast.LENGTH_SHORT).show();
|
Toast.makeText(ManageReposActivity.this, getString(R.string.repo_added, address), Toast.LENGTH_SHORT).show();
|
||||||
|
@ -2,6 +2,7 @@ package org.fdroid.fdroid.views;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@ -21,6 +22,8 @@ import android.text.format.DateUtils;
|
|||||||
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.widget.Button;
|
||||||
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
@ -54,6 +57,9 @@ public class RepoDetailsActivity extends ActionBarActivity {
|
|||||||
R.id.text_num_apps,
|
R.id.text_num_apps,
|
||||||
R.id.label_last_update,
|
R.id.label_last_update,
|
||||||
R.id.text_last_update,
|
R.id.text_last_update,
|
||||||
|
R.id.label_username,
|
||||||
|
R.id.text_username,
|
||||||
|
R.id.button_edit_credentials,
|
||||||
R.id.label_repo_fingerprint,
|
R.id.label_repo_fingerprint,
|
||||||
R.id.text_repo_fingerprint,
|
R.id.text_repo_fingerprint,
|
||||||
R.id.text_repo_fingerprint_description,
|
R.id.text_repo_fingerprint_description,
|
||||||
@ -271,6 +277,25 @@ public class RepoDetailsActivity extends ActionBarActivity {
|
|||||||
repoFingerprintView.setText(repoFingerprint);
|
repoFingerprintView.setText(repoFingerprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupCredentials(View parent, Repo repo) {
|
||||||
|
|
||||||
|
TextView usernameLabel = (TextView) parent.findViewById(R.id.label_username);
|
||||||
|
TextView username = (TextView) parent.findViewById(R.id.text_username);
|
||||||
|
Button changePassword = (Button) parent.findViewById(R.id.button_edit_credentials);
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(repo.username)) {
|
||||||
|
usernameLabel.setVisibility(View.GONE);
|
||||||
|
username.setVisibility(View.GONE);
|
||||||
|
username.setText("");
|
||||||
|
changePassword.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
usernameLabel.setVisibility(View.VISIBLE);
|
||||||
|
username.setVisibility(View.VISIBLE);
|
||||||
|
username.setText(repo.username);
|
||||||
|
changePassword.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateRepoView() {
|
private void updateRepoView() {
|
||||||
|
|
||||||
if (repo.hasBeenUpdated()) {
|
if (repo.hasBeenUpdated()) {
|
||||||
@ -301,6 +326,7 @@ public class RepoDetailsActivity extends ActionBarActivity {
|
|||||||
|
|
||||||
setupDescription(repoView, repo);
|
setupDescription(repoView, repo);
|
||||||
setupRepoFingerprint(repoView, repo);
|
setupRepoFingerprint(repoView, repo);
|
||||||
|
setupCredentials(repoView, repo);
|
||||||
|
|
||||||
// Repos that existed before this feature was supported will have an
|
// Repos that existed before this feature was supported will have an
|
||||||
// "Unknown" last update until next time they update...
|
// "Unknown" last update until next time they update...
|
||||||
@ -335,4 +361,54 @@ public class RepoDetailsActivity extends ActionBarActivity {
|
|||||||
).show();
|
).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showChangePasswordDialog(final View parentView) {
|
||||||
|
|
||||||
|
final View view = getLayoutInflater().inflate(R.layout.login, null);
|
||||||
|
final AlertDialog credentialsDialog = new AlertDialog.Builder(this).setView(view).create();
|
||||||
|
final EditText nameInput = (EditText) view.findViewById(R.id.edit_name);
|
||||||
|
final EditText passwordInput = (EditText) view.findViewById(R.id.edit_password);
|
||||||
|
|
||||||
|
nameInput.setText(repo.username);
|
||||||
|
passwordInput.requestFocus();
|
||||||
|
|
||||||
|
credentialsDialog.setTitle(R.string.repo_edit_credentials);
|
||||||
|
credentialsDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
|
||||||
|
getString(R.string.cancel),
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
credentialsDialog.setButton(DialogInterface.BUTTON_POSITIVE,
|
||||||
|
getString(R.string.ok),
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
|
||||||
|
final String name = nameInput.getText().toString();
|
||||||
|
final String password = passwordInput.getText().toString();
|
||||||
|
|
||||||
|
if (!TextUtils.isEmpty(name)) {
|
||||||
|
|
||||||
|
final ContentValues values = new ContentValues(2);
|
||||||
|
values.put(RepoProvider.DataColumns.USERNAME, name);
|
||||||
|
values.put(RepoProvider.DataColumns.PASSWORD, password);
|
||||||
|
|
||||||
|
RepoProvider.Helper.update(RepoDetailsActivity.this, repo, values);
|
||||||
|
|
||||||
|
updateRepoView();
|
||||||
|
|
||||||
|
dialog.dismiss();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Toast.makeText(RepoDetailsActivity.this, R.string.repo_error_empty_username, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
credentialsDialog.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user