Create new repos using RxJava instead of AsyncTask.

This commit is contained in:
Isira Seneviratne 2020-10-25 08:38:58 +05:30 committed by Hans-Christoph Steiner
parent e1ca1552f7
commit 242662d02a

View File

@ -19,7 +19,6 @@
package org.fdroid.fdroid.views; package org.fdroid.fdroid.views;
import android.annotation.SuppressLint;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.ContentResolver; import android.content.ContentResolver;
@ -32,13 +31,13 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.text.Editable; import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
@ -87,6 +86,12 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class ManageReposActivity extends AppCompatActivity public class ManageReposActivity extends AppCompatActivity
implements LoaderManager.LoaderCallbacks<Cursor>, RepoAdapter.EnabledListener { implements LoaderManager.LoaderCallbacks<Cursor>, RepoAdapter.EnabledListener {
private static final String TAG = "ManageReposActivity"; private static final String TAG = "ManageReposActivity";
@ -107,6 +112,8 @@ public class ManageReposActivity extends AppCompatActivity
*/ */
private boolean finishAfterAddingRepo; private boolean finishAfterAddingRepo;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
FDroidApp fdroidApp = (FDroidApp) getApplication(); FDroidApp fdroidApp = (FDroidApp) getApplication();
@ -154,6 +161,12 @@ public class ManageReposActivity extends AppCompatActivity
}); });
} }
@Override
protected void onDestroy() {
compositeDisposable.dispose();
super.onDestroy();
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater(); MenuInflater menuInflater = getMenuInflater();
@ -571,10 +584,8 @@ public class ManageReposActivity extends AppCompatActivity
/** /**
* Adds a new repo to the database. * Adds a new repo to the database.
*/ */
@SuppressLint("StaticFieldLeak")
private void prepareToCreateNewRepo(final String originalAddress, final String fingerprint, private void prepareToCreateNewRepo(final String originalAddress, final String fingerprint,
final String username, final String password) { final String username, final String password) {
final View addRepoForm = addRepoDialog.findViewById(R.id.add_repo_form); final View addRepoForm = addRepoDialog.findViewById(R.id.add_repo_form);
addRepoForm.setVisibility(View.GONE); addRepoForm.setVisibility(View.GONE);
final View positiveButton = addRepoDialog.getButton(AlertDialog.BUTTON_POSITIVE); final View positiveButton = addRepoDialog.getButton(AlertDialog.BUTTON_POSITIVE);
@ -586,84 +597,62 @@ public class ManageReposActivity extends AppCompatActivity
final Button skip = addRepoDialog.getButton(AlertDialog.BUTTON_NEGATIVE); final Button skip = addRepoDialog.getButton(AlertDialog.BUTTON_NEGATIVE);
skip.setText(R.string.skip); skip.setText(R.string.skip);
final AsyncTask<String, String, String> checker = new AsyncTask<String, String, String>() { final int REFRESH_DIALOG = Integer.MAX_VALUE;
final Disposable disposable = Single.fromCallable(() -> {
private int statusCode = -1; int statusCode = -1;
private static final int REFRESH_DIALOG = Integer.MAX_VALUE;
@Override
protected String doInBackground(String... params) {
final String originalAddress = params[0];
if (fingerprintRepoMap.containsKey(fingerprint)) { if (fingerprintRepoMap.containsKey(fingerprint)) {
statusCode = REFRESH_DIALOG; statusCode = REFRESH_DIALOG;
return originalAddress; return Pair.create(statusCode, originalAddress);
} }
if (originalAddress.startsWith(ContentResolver.SCHEME_CONTENT) if (originalAddress.startsWith(ContentResolver.SCHEME_CONTENT)
|| originalAddress.startsWith(ContentResolver.SCHEME_FILE)) { || originalAddress.startsWith(ContentResolver.SCHEME_FILE)) {
// TODO check whether there is read access // TODO check whether there is read access
return originalAddress; return Pair.create(statusCode, originalAddress);
} }
final String[] pathsToCheck = {"", "fdroid/repo", "repo"}; final String[] pathsToCheck = {"", "fdroid/repo", "repo"};
for (final String path : pathsToCheck) { for (final String path : pathsToCheck) {
Utils.debugLog(TAG, "Check for repo at " + originalAddress + " with suffix '" + path + "'"); Utils.debugLog(TAG, "Check for repo at " + originalAddress + " with suffix '" + path + "'");
Uri.Builder builder = Uri.parse(originalAddress).buildUpon().appendEncodedPath(path); Uri.Builder builder = Uri.parse(originalAddress).buildUpon().appendEncodedPath(path);
final String addressWithoutIndex = builder.build().toString(); final String addressWithoutIndex = builder.build().toString();
publishProgress(addressWithoutIndex); runOnUiThread(() -> textSearching.setText(getString(R.string.repo_searching_address, addressWithoutIndex)));
if (urlRepoMap.containsKey(addressWithoutIndex)) { if (urlRepoMap.containsKey(addressWithoutIndex)) {
statusCode = REFRESH_DIALOG; statusCode = REFRESH_DIALOG;
return addressWithoutIndex; return Pair.create(statusCode, addressWithoutIndex);
} }
final Uri uri = builder.appendPath(IndexUpdater.SIGNED_FILE_NAME).build(); final Uri uri = builder.appendPath(IndexUpdater.SIGNED_FILE_NAME).build();
try { try {
if (checkForRepository(uri)) { final URL url = new URL(uri.toString());
Utils.debugLog(TAG, "Found F-Droid repo at " + addressWithoutIndex);
return addressWithoutIndex;
}
} catch (IOException e) {
Log.e(TAG, "Error while searching for repo at " + addressWithoutIndex, e);
return originalAddress;
}
if (isCancelled()) {
Utils.debugLog(TAG, "Not checking more repo addresses, because process was skipped.");
break;
}
}
return originalAddress;
}
private boolean checkForRepository(Uri indexUri) throws IOException {
final URL url = new URL(indexUri.toString());
final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD"); connection.setRequestMethod("HEAD");
statusCode = connection.getResponseCode(); statusCode = connection.getResponseCode();
return statusCode == HttpURLConnection.HTTP_UNAUTHORIZED if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED || statusCode == HttpURLConnection.HTTP_OK) {
|| statusCode == HttpURLConnection.HTTP_OK; Utils.debugLog(TAG, "Found F-Droid repo at " + addressWithoutIndex);
return Pair.create(statusCode, addressWithoutIndex);
} }
} catch (IOException e) {
@Override Log.e(TAG, "Error while searching for repo at " + addressWithoutIndex, e);
protected void onProgressUpdate(String... values) { return Pair.create(statusCode, originalAddress);
String address = values[0];
textSearching.setText(getString(R.string.repo_searching_address, address));
} }
}
@Override return Pair.create(statusCode, originalAddress);
protected void onPostExecute(final String newAddress) { })
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnDispose(() -> Utils.debugLog(TAG, "Not checking more repo addresses, because process was skipped."))
.subscribe(codeAddressPair -> {
final int statusCode = codeAddressPair.first;
final String newAddress = codeAddressPair.second;
if (addRepoDialog.isShowing()) { if (addRepoDialog.isShowing()) {
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED) { if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
final View view = getLayoutInflater().inflate(R.layout.login, null); final View view = getLayoutInflater().inflate(R.layout.login, null);
final AlertDialog credentialsDialog = new AlertDialog.Builder(context) final AlertDialog credentialsDialog = new AlertDialog.Builder(context)
.setView(view).create(); .setView(view).create();
@ -679,29 +668,19 @@ public class ManageReposActivity extends AppCompatActivity
credentialsDialog.setTitle(R.string.login_title); credentialsDialog.setTitle(R.string.login_title);
credentialsDialog.setButton(DialogInterface.BUTTON_NEGATIVE, credentialsDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
getString(R.string.cancel), getString(R.string.cancel), (dialog, which) -> {
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss(); dialog.dismiss();
// cancel parent dialog, don't add repo // cancel parent dialog, don't add repo
addRepoDialog.cancel(); addRepoDialog.cancel();
}
}); });
credentialsDialog.setButton(DialogInterface.BUTTON_POSITIVE, credentialsDialog.setButton(DialogInterface.BUTTON_POSITIVE,
getString(R.string.ok), getString(R.string.ok),
new DialogInterface.OnClickListener() { (dialog, which) -> createNewRepo(newAddress, fingerprint,
@Override
public void onClick(DialogInterface dialog, int which) {
createNewRepo(newAddress, fingerprint,
nameInput.getText().toString(), nameInput.getText().toString(),
passwordInput.getText().toString()); passwordInput.getText().toString()));
}
});
credentialsDialog.show(); credentialsDialog.show();
} else if (statusCode == REFRESH_DIALOG) { } else if (statusCode == REFRESH_DIALOG) {
addRepoForm.setVisibility(View.VISIBLE); addRepoForm.setVisibility(View.VISIBLE);
positiveButton.setVisibility(View.VISIBLE); positiveButton.setVisibility(View.VISIBLE);
@ -710,29 +689,22 @@ public class ManageReposActivity extends AppCompatActivity
skip.setOnClickListener(null); skip.setOnClickListener(null);
validateRepoDetails(newAddress, fingerprint); validateRepoDetails(newAddress, fingerprint);
} else { } else {
// create repo without username/password // create repo without username/password
createNewRepo(newAddress, fingerprint); createNewRepo(newAddress, fingerprint);
} }
} }
} });
}; compositeDisposable.add(disposable);
skip.setOnClickListener(new View.OnClickListener() { skip.setOnClickListener(v -> {
@Override
public void onClick(View v) {
// Still proceed with adding the repo, just don't bother searching for // Still proceed with adding the repo, just don't bother searching for
// a better alternative than the one provided. // a better alternative than the one provided.
// The reason for this is that if they are not connected to the internet, // The reason for this is that if they are not connected to the internet,
// or their internet is playing up, then you'd have to wait for several // or their internet is playing up, then you'd have to wait for several
// connection timeouts before being able to proceed. // connection timeouts before being able to proceed.
createNewRepo(originalAddress, fingerprint); createNewRepo(originalAddress, fingerprint);
checker.cancel(false); disposable.dispose();
}
}); });
checker.execute(originalAddress);
} }
/** /**