Generate a QR bitmap using RxJava instead of AsyncTask.
This commit is contained in:
parent
93a160b40d
commit
e1ca1552f7
@ -34,7 +34,18 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.LayoutRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.SearchView;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
|
|
||||||
import com.google.android.material.appbar.MaterialToolbar;
|
import com.google.android.material.appbar.MaterialToolbar;
|
||||||
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
import com.google.zxing.integration.android.IntentIntegrator;
|
import com.google.zxing.integration.android.IntentIntegrator;
|
||||||
import com.google.zxing.integration.android.IntentResult;
|
import com.google.zxing.integration.android.IntentResult;
|
||||||
|
|
||||||
@ -54,7 +65,6 @@ import org.fdroid.fdroid.net.BluetoothDownloader;
|
|||||||
import org.fdroid.fdroid.net.Downloader;
|
import org.fdroid.fdroid.net.Downloader;
|
||||||
import org.fdroid.fdroid.net.HttpDownloader;
|
import org.fdroid.fdroid.net.HttpDownloader;
|
||||||
import org.fdroid.fdroid.qr.CameraCharacteristicsChecker;
|
import org.fdroid.fdroid.qr.CameraCharacteristicsChecker;
|
||||||
import org.fdroid.fdroid.qr.QrGenAsyncTask;
|
|
||||||
import org.fdroid.fdroid.views.main.MainActivity;
|
import org.fdroid.fdroid.views.main.MainActivity;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -65,17 +75,8 @@ import java.util.Set;
|
|||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
import androidx.annotation.LayoutRes;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.appcompat.widget.SearchView;
|
|
||||||
import com.google.android.material.switchmaterial.SwitchMaterial;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|
||||||
import cc.mvdan.accesspoint.WifiApControl;
|
import cc.mvdan.accesspoint.WifiApControl;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
|
|
||||||
import static org.fdroid.fdroid.views.main.MainActivity.ACTION_REQUEST_SWAP;
|
import static org.fdroid.fdroid.views.main.MainActivity.ACTION_REQUEST_SWAP;
|
||||||
|
|
||||||
@ -118,6 +119,8 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
|||||||
@LayoutRes
|
@LayoutRes
|
||||||
private int currentSwapViewLayoutRes = STEP_INTRO;
|
private int currentSwapViewLayoutRes = STEP_INTRO;
|
||||||
|
|
||||||
|
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||||
|
|
||||||
public static void requestSwap(Context context, String repo) {
|
public static void requestSwap(Context context, String repo) {
|
||||||
requestSwap(context, Uri.parse(repo));
|
requestSwap(context, Uri.parse(repo));
|
||||||
}
|
}
|
||||||
@ -235,6 +238,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
|
compositeDisposable.dispose();
|
||||||
localBroadcastManager.unregisterReceiver(downloaderInterruptedReceiver);
|
localBroadcastManager.unregisterReceiver(downloaderInterruptedReceiver);
|
||||||
unbindService(serviceConnection);
|
unbindService(serviceConnection);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
@ -929,11 +933,14 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
|||||||
ImageView qrImage = container.findViewById(R.id.wifi_qr_code);
|
ImageView qrImage = container.findViewById(R.id.wifi_qr_code);
|
||||||
if (qrUriString != null && qrImage != null) {
|
if (qrUriString != null && qrImage != null) {
|
||||||
Utils.debugLog(TAG, "Encoded swap URI in QR Code: " + qrUriString);
|
Utils.debugLog(TAG, "Encoded swap URI in QR Code: " + qrUriString);
|
||||||
new QrGenAsyncTask(SwapWorkflowActivity.this, R.id.wifi_qr_code).execute(qrUriString);
|
|
||||||
|
compositeDisposable.add(Utils.generateQrBitmap(this, qrUriString)
|
||||||
|
.subscribe(qrBitmap -> {
|
||||||
|
qrImage.setImageBitmap(qrBitmap);
|
||||||
|
|
||||||
// Replace all blacks with the background blue.
|
// Replace all blacks with the background blue.
|
||||||
qrImage.setColorFilter(new LightingColorFilter(0xffffffff, ContextCompat.getColor(this,
|
qrImage.setColorFilter(new LightingColorFilter(0xffffffff,
|
||||||
R.color.swap_blue)));
|
ContextCompat.getColor(this, R.color.swap_blue)));
|
||||||
|
|
||||||
final View qrWarningMessage = container.findViewById(R.id.warning_qr_scanner);
|
final View qrWarningMessage = container.findViewById(R.id.warning_qr_scanner);
|
||||||
if (CameraCharacteristicsChecker.getInstance(this).hasAutofocus()) {
|
if (CameraCharacteristicsChecker.getInstance(this).hasAutofocus()) {
|
||||||
@ -941,6 +948,8 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
|||||||
} else {
|
} else {
|
||||||
qrWarningMessage.setVisibility(View.VISIBLE);
|
qrWarningMessage.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import android.content.pm.Signature;
|
|||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Point;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
@ -44,11 +45,21 @@ import android.text.style.TypefaceSpan;
|
|||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
|
import android.view.Display;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||||
|
|
||||||
|
import com.google.zxing.BarcodeFormat;
|
||||||
|
import com.google.zxing.encode.Contents;
|
||||||
|
import com.google.zxing.encode.QRCodeEncoder;
|
||||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||||
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
|
||||||
@ -92,10 +103,9 @@ import java.util.TimeZone;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
import androidx.annotation.Nullable;
|
import io.reactivex.rxjava3.core.Single;
|
||||||
import androidx.annotation.RequiresApi;
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
|
||||||
|
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
|
|
||||||
@ -986,6 +996,27 @@ public final class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static Single<Bitmap> generateQrBitmap(@NonNull final AppCompatActivity activity,
|
||||||
|
@NonNull final String qrData) {
|
||||||
|
return Single.fromCallable(() -> {
|
||||||
|
Display display = activity.getWindowManager().getDefaultDisplay();
|
||||||
|
Point outSize = new Point();
|
||||||
|
display.getSize(outSize);
|
||||||
|
final int x = outSize.x;
|
||||||
|
final int y = outSize.y;
|
||||||
|
final int qrCodeDimension = Math.min(x, y);
|
||||||
|
debugLog(TAG, "generating QRCode Bitmap of " + qrCodeDimension + "x" + qrCodeDimension);
|
||||||
|
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(qrData, null,
|
||||||
|
Contents.Type.TEXT, BarcodeFormat.QR_CODE.toString(), qrCodeDimension);
|
||||||
|
|
||||||
|
return qrCodeEncoder.encodeAsBitmap();
|
||||||
|
})
|
||||||
|
.subscribeOn(Schedulers.computation())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doOnError(throwable -> Log.e(TAG, "Could not encode QR as bitmap", throwable));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep an instance of this class as an field in an AppCompatActivity for figuring out whether the on
|
* Keep an instance of this class as an field in an AppCompatActivity for figuring out whether the on
|
||||||
* screen keyboard is currently visible or not.
|
* screen keyboard is currently visible or not.
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
package org.fdroid.fdroid.qr;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.Point;
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.Display;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
|
|
||||||
import com.google.zxing.BarcodeFormat;
|
|
||||||
import com.google.zxing.WriterException;
|
|
||||||
import com.google.zxing.encode.Contents;
|
|
||||||
import com.google.zxing.encode.QRCodeEncoder;
|
|
||||||
|
|
||||||
import org.fdroid.fdroid.Utils;
|
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
|
|
||||||
public class QrGenAsyncTask extends AsyncTask<String, Void, Void> {
|
|
||||||
private static final String TAG = "QrGenAsyncTask";
|
|
||||||
|
|
||||||
private final AppCompatActivity activity;
|
|
||||||
private final int viewId;
|
|
||||||
private Bitmap qrBitmap;
|
|
||||||
|
|
||||||
public QrGenAsyncTask(AppCompatActivity activity, int viewId) {
|
|
||||||
this.activity = activity;
|
|
||||||
this.viewId = viewId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The method for getting screen dimens changed, so this uses both the
|
|
||||||
* deprecated one and the 13+ one, and supports all Android versions.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@TargetApi(13)
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(String... s) {
|
|
||||||
String qrData = s[0];
|
|
||||||
Display display = activity.getWindowManager().getDefaultDisplay();
|
|
||||||
Point outSize = new Point();
|
|
||||||
int x, y, qrCodeDimension;
|
|
||||||
display.getSize(outSize);
|
|
||||||
x = outSize.x;
|
|
||||||
y = outSize.y;
|
|
||||||
if (x < y) {
|
|
||||||
qrCodeDimension = x;
|
|
||||||
} else {
|
|
||||||
qrCodeDimension = y;
|
|
||||||
}
|
|
||||||
Utils.debugLog(TAG, "generating QRCode Bitmap of " + qrCodeDimension + "x" + qrCodeDimension);
|
|
||||||
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(qrData, null,
|
|
||||||
Contents.Type.TEXT, BarcodeFormat.QR_CODE.toString(), qrCodeDimension);
|
|
||||||
|
|
||||||
try {
|
|
||||||
qrBitmap = qrCodeEncoder.encodeAsBitmap();
|
|
||||||
} catch (WriterException e) {
|
|
||||||
Log.e(TAG, "Could not encode QR as bitmap", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(Void v) {
|
|
||||||
ImageView qrCodeImageView = (ImageView) activity.findViewById(viewId);
|
|
||||||
|
|
||||||
// If the generation takes too long for whatever reason, then this view, and indeed the entire
|
|
||||||
// activity may not be around any more.
|
|
||||||
if (qrCodeImageView != null) {
|
|
||||||
qrCodeImageView.setImageBitmap(qrBitmap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,9 +23,19 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.CompoundButton;
|
import android.widget.CompoundButton;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.core.app.NavUtils;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.appbar.MaterialToolbar;
|
import com.google.android.material.appbar.MaterialToolbar;
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
|
|
||||||
@ -38,20 +48,12 @@ import org.fdroid.fdroid.Utils;
|
|||||||
import org.fdroid.fdroid.data.Repo;
|
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 org.fdroid.fdroid.qr.QrGenAsyncTask;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.core.app.NavUtils;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
public class RepoDetailsActivity extends AppCompatActivity {
|
public class RepoDetailsActivity extends AppCompatActivity {
|
||||||
private static final String TAG = "RepoDetailsActivity";
|
private static final String TAG = "RepoDetailsActivity";
|
||||||
@ -91,6 +93,8 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private MirrorAdapter adapterToNotify;
|
private MirrorAdapter adapterToNotify;
|
||||||
|
|
||||||
|
private Disposable disposable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@ -141,7 +145,19 @@ public class RepoDetailsActivity extends AppCompatActivity {
|
|||||||
Uri uri = Uri.parse(repo.address);
|
Uri uri = Uri.parse(repo.address);
|
||||||
uri = uri.buildUpon().appendQueryParameter("fingerprint", repo.fingerprint).build();
|
uri = uri.buildUpon().appendQueryParameter("fingerprint", repo.fingerprint).build();
|
||||||
String qrUriString = uri.toString();
|
String qrUriString = uri.toString();
|
||||||
new QrGenAsyncTask(this, R.id.qr_code).execute(qrUriString);
|
disposable = Utils.generateQrBitmap(this, qrUriString)
|
||||||
|
.subscribe(bitmap -> {
|
||||||
|
final ImageView qrCode = findViewById(R.id.qr_code);
|
||||||
|
if (qrCode != null) {
|
||||||
|
qrCode.setImageBitmap(bitmap);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
disposable.dispose();
|
||||||
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(14)
|
@TargetApi(14)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user