Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to version 4.6.1 #239

Merged
merged 13 commits into from
Jul 26, 2024
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ android {
compileSdk 34
targetSdkVersion 34
multiDexEnabled true
versionCode 42
versionName "4.6.0"
versionCode 43
versionName "4.6.1"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
buildFeatures.dataBinding = true
vectorDrawables.useSupportLibrary = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void useAppContext() throws Exception {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();

assertEquals("com.secuso.privacyfriendlycodescanner.qrscanner", appContext.getPackageName());
assertEquals("com.secuso.privacyFriendlyCodeScanner", appContext.getPackageName());
}

@Before
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="auto"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.CAMERA" />
Expand Down Expand Up @@ -193,4 +194,4 @@
<data android:mimeType="*/*" />
</intent>
</queries>
</manifest>
</manifest>
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package com.secuso.privacyfriendlycodescanner.qrscanner.generator;

import static android.content.Context.WINDOW_SERVICE;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.media.MediaScannerConnection;
import android.net.Uri;
Expand All @@ -15,14 +20,19 @@
import android.view.Display;
import android.view.WindowManager;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.encoder.ByteMatrix;
import com.google.zxing.qrcode.encoder.Encoder;
import com.google.zxing.qrcode.encoder.QRCode;

import java.io.File;
import java.io.FileOutputStream;
Expand All @@ -31,9 +41,9 @@
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;

import static android.content.Context.WINDOW_SERVICE;
import java.util.Map;

public class QRGeneratorUtils {

Expand Down Expand Up @@ -85,36 +95,115 @@ public static Uri getCachedUri() {
return cache;
}

public static Uri createImage(Context context, String qrInputText, Contents.Type qrType, BarcodeFormat barcodeFormat, String errorCorrectionLevel) {

private static int getDimension(Context context) {
//Find screen size
WindowManager manager = (WindowManager) context.getSystemService(WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
Point point = new Point();
display.getSize(point);
int width = point.x;
int height = point.y;
int smallerDimension = width < height ? width : height;
smallerDimension = smallerDimension * 3 / 4;

//Encode with a QR Code image
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(qrInputText,
null,
qrType,
barcodeFormat.toString(),
smallerDimension);
Bitmap bitmap_ = null;
try {
bitmap_ = qrCodeEncoder.encodeAsBitmap(errorCorrectionLevel);
// return bitmap_;
int smallerDimension = Math.min(width, height);
return smallerDimension * 3 / 4;
}

} catch (WriterException e) {
e.printStackTrace();
public static Uri createImage(Context context, String qrInputText, Contents.Type qrType, BarcodeFormat barcodeFormat, String errorCorrectionLevel, boolean dots) {
int smallerDimension = getDimension(context);

Bitmap bitmap_ = null;
if (!dots) {
//Encode with a QR Code image
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(qrInputText,
null,
qrType,
barcodeFormat.toString(),
smallerDimension);
try {
bitmap_ = qrCodeEncoder.encodeAsBitmap(errorCorrectionLevel);
} catch (WriterException e) {
e.printStackTrace();
}
} else {
final Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.MARGIN, 1);
QRCode code;
try {
code = Encoder.encode(qrInputText, ErrorCorrectionLevel.valueOf(errorCorrectionLevel), hints);
} catch (WriterException e) {
throw new RuntimeException(e);
}
bitmap_ = createDotQRCode(code, smallerDimension, smallerDimension, Color.BLACK, Color.WHITE, 1);
}

return cacheImage(context, bitmap_);
}

private static Bitmap createDotQRCode(QRCode code, int width, int height, @ColorInt int color, @ColorInt int backgroundColor, int quietZone) {
Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(image);
canvas.drawColor(backgroundColor);
Paint paint = new Paint();
paint.setColor(color);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);


ByteMatrix input = code.getMatrix();
if (input == null) {
throw new IllegalArgumentException();
}

final int QR_WIDTH = input.getWidth() + (quietZone * 2);
final int QR_HEIGHT = input.getHeight() + (quietZone * 2);
final int OUTPUT_WIDTH = Math.max(width, QR_WIDTH);
final int OUTPUT_HEIGHT = Math.max(height, QR_HEIGHT);

final float SCALE = Math.min((float) OUTPUT_WIDTH / (float) QR_WIDTH, (float) OUTPUT_HEIGHT / (float) QR_HEIGHT); //scale from ByteMatrix to Canvas
final int POSITION_PATTERN_SIZE = 7; //size of the position pattern inside the ByteMatrix
final float POSITION_PATTERN_RADIUS = (SCALE * POSITION_PATTERN_SIZE) / 2f;
final float CIRCLE_RADIUS = (SCALE * 0.35f);
final float PADDING_LEFT = (OUTPUT_WIDTH - (input.getWidth() * SCALE)) / 2.0f + CIRCLE_RADIUS / 2.0f;
final float PADDING_TOP = (OUTPUT_HEIGHT - (input.getHeight() * SCALE)) / 2.0f + CIRCLE_RADIUS / 2.0f;

for (int y = 0; y < input.getHeight(); y++) {
for (int x = 0; x < input.getWidth(); x++) {
if (input.get(x, y) == 1) {
boolean isInPositionPatternArea = //do not draw anything inside the position pattern regions
x <= POSITION_PATTERN_SIZE && y <= POSITION_PATTERN_SIZE || //top left position pattern
x >= input.getWidth() - POSITION_PATTERN_SIZE && y <= POSITION_PATTERN_SIZE || //top right position pattern
x <= POSITION_PATTERN_SIZE && y >= input.getHeight() - POSITION_PATTERN_SIZE; //bottom left position pattern
if (!isInPositionPatternArea) {
float outputX = PADDING_LEFT + x * SCALE;
float outputY = PADDING_TOP + y * SCALE;
canvas.drawCircle(outputX + CIRCLE_RADIUS, outputY + CIRCLE_RADIUS, CIRCLE_RADIUS, paint);
}
}
}
}

//draw position patterns
drawPositionPattern(canvas, color, backgroundColor, PADDING_LEFT, PADDING_TOP, POSITION_PATTERN_RADIUS);
drawPositionPattern(canvas, color, backgroundColor, PADDING_LEFT + (input.getWidth() - POSITION_PATTERN_SIZE) * SCALE, PADDING_TOP, POSITION_PATTERN_RADIUS);
drawPositionPattern(canvas, color, backgroundColor, PADDING_LEFT, PADDING_TOP + (input.getHeight() - POSITION_PATTERN_SIZE) * SCALE, POSITION_PATTERN_RADIUS);

return image;
}

private static void drawPositionPattern(Canvas canvas, @ColorInt int color, @ColorInt int backgroundColor, float x, float y, float patternRadius) {
final float BACKGROUND_CIRCLE_RADIUS = patternRadius * 5f / 7f;
final float MIDDLE_DOT_RADIUS = patternRadius * 3f / 7f;

Paint paint = new Paint();
paint.setColor(color);
Paint bgPaint = new Paint();
bgPaint.setColor(backgroundColor);

canvas.drawCircle(x + patternRadius, y + patternRadius, patternRadius, paint);
canvas.drawCircle(x + patternRadius, y + patternRadius, BACKGROUND_CIRCLE_RADIUS, bgPaint);
canvas.drawCircle(x + patternRadius, y + patternRadius, MIDDLE_DOT_RADIUS, paint);
}

public static void saveCachedImageToExternalStorage(Context context) {
Bitmap bitmap = null;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ public static Bitmap generateCode(String data, BarcodeFormat original_format, in
if (!hints.containsKey(ERROR_CORRECTION) && metadata != null && metadata.containsKey(ERROR_CORRECTION_LEVEL) && format.equals(original_format)) {
Object ec = metadata.get(ERROR_CORRECTION_LEVEL);
if (ec != null) {
hints.put(ERROR_CORRECTION, ec);
String errorCorrection = ec.toString();
errorCorrection = errorCorrection.replace("%", ""); // Sometimes the error correction value contains a percent sign
hints.put(ERROR_CORRECTION, errorCorrection);
}
}
if (!hints.containsKey(ERROR_CORRECTION) && format != BarcodeFormat.AZTEC && format != BarcodeFormat.PDF_417) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,17 @@ public class QrGeneratorDisplayActivity extends AppCompatActivity {
String qrInputText = "";
Contents.Type qrInputType = Contents.Type.UNDEFINED;

private static final String BARCODE_FORMAT_QR_CODE_DOTS = BarcodeFormat.QR_CODE.name() + "_DOTS";
private String[] barcodeFormats = new String[]{
BarcodeFormat.QR_CODE.name(),
BARCODE_FORMAT_QR_CODE_DOTS,
BarcodeFormat.AZTEC.name(),
BarcodeFormat.DATA_MATRIX.name(),
BarcodeFormat.PDF_417.name(),
BarcodeFormat.CODE_128.name()};
private Integer[] barcodeFormatIcons = new Integer[]{
R.drawable.ic_baseline_qr_code_24dp,
R.drawable.ic_baseline_qr_code_dots_24dp,
R.drawable.ic_aztec_code_24dp,
R.drawable.ic_data_matrix_code_24dp,
R.drawable.ic_pdf_417_code_24dp,
Expand Down Expand Up @@ -137,7 +140,7 @@ private void initDropDownMenus() {
}

private void updateDropDownMenus() {
barcodeFormat = BarcodeFormat.valueOf(barcodeFormatMenu.getText().toString());
UpdateBarcodeFormatFromMenuValue();

if (barcodeFormat.equals(BarcodeFormat.QR_CODE)) {
currentErrorCorrections = errorCorrectionsQR;
Expand All @@ -151,7 +154,7 @@ private void updateDropDownMenus() {
updateErrorCorrectionMenu();
//Update icon
ImageView barcodeFormatIcon = findViewById(R.id.iconImageView);
Glide.with(this).load(AppCompatResources.getDrawable(this, barcodeFormatIcons[Arrays.asList(barcodeFormats).indexOf(barcodeFormat.name())])).into(barcodeFormatIcon);
Glide.with(this).load(AppCompatResources.getDrawable(this, barcodeFormatIcons[Arrays.asList(barcodeFormats).indexOf(barcodeFormatMenu.getText().toString())])).into(barcodeFormatIcon);

}

Expand All @@ -176,11 +179,15 @@ private void updateErrorCorrectionMenu() {
private void generateAndUpdateImage() {
ImageView myImage = findViewById(R.id.resultQRCodeImage);

barcodeFormat = BarcodeFormat.valueOf(barcodeFormatMenu.getText().toString());
UpdateBarcodeFormatFromMenuValue();
String errorCorrectionLevel = errorCorrectionMenu.getText().toString();
try {
Log.d(getClass().getSimpleName(), "Creating image...");
Glide.with(this).asBitmap().load(QRGeneratorUtils.createImage(this, qrInputText, qrInputType, barcodeFormat, errorCorrectionLevel)).into(new BitmapImageViewTarget(myImage));
if (barcodeFormatMenu.getText().toString().equals(BARCODE_FORMAT_QR_CODE_DOTS)) {
Glide.with(this).asBitmap().load(QRGeneratorUtils.createImage(this, qrInputText, qrInputType, barcodeFormat, errorCorrectionLevel, true)).into(new BitmapImageViewTarget(myImage));
} else {
Glide.with(this).asBitmap().load(QRGeneratorUtils.createImage(this, qrInputText, qrInputType, barcodeFormat, errorCorrectionLevel, false)).into(new BitmapImageViewTarget(myImage));
}
} catch (IllegalArgumentException e) {
Toast.makeText(this, R.string.code_generation_error, Toast.LENGTH_SHORT).show();
Log.d(getClass().getSimpleName(), "Error during code generation.", e);
Expand Down Expand Up @@ -263,6 +270,14 @@ protected void onDestroy() {
QRGeneratorUtils.purgeCacheFolder(this);
}

private void UpdateBarcodeFormatFromMenuValue() {
if (barcodeFormatMenu.getText().toString().equals(BARCODE_FORMAT_QR_CODE_DOTS)) {
barcodeFormat = BarcodeFormat.QR_CODE;
} else {
barcodeFormat = BarcodeFormat.valueOf(barcodeFormatMenu.getText().toString());
}
}

@Override
protected void onResume() {
super.onResume();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public void onProceedPressed(Context context) {
Intent contact = new Intent(ContactsContract.Intents.Insert.ACTION);
contact.setType(ContactsContract.RawContacts.CONTENT_TYPE);

contact.putExtra(ContactsContract.Intents.Insert.NAME, result.getNames() != null ? result.getNames()[0] : null);
contact.putExtra(ContactsContract.Intents.Insert.NAME, result.getNames() != null && result.getNames().length > 0 ? result.getNames()[0] : null);
contact.putExtra(ContactsContract.Intents.Insert.COMPANY, result.getOrg());
contact.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, result.getTitle());
contact.putExtra(ContactsContract.Intents.Insert.NOTES, result.getNote());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.regex.Pattern;

public class URLResultFragment extends ResultFragment {
private static final String VALID_RFC3986_PROTOCOL_SCHEME = "^[a-zA-Z][a-zA-Z0-9+.-]*:.*$";

URIParsedResult result;

Expand Down Expand Up @@ -95,23 +96,14 @@ public void onProceedPressed(Context context) {
if (!checked) {
Toast.makeText(context, R.string.conform_url, Toast.LENGTH_LONG).show();
} else {
String caption;
String qrurl3;
final String lowercase_qrurl = qrurl.toLowerCase();
if (!lowercase_qrurl.startsWith("http://") && !lowercase_qrurl.startsWith("https://")) {
qrurl3 = "http://" + qrurl;

Intent url = new Intent(Intent.ACTION_VIEW);/// !!!!
url.setData(Uri.parse(qrurl3));
caption = getResources().getStringArray(R.array.url_array)[0];
startActivity(Intent.createChooser(url, caption));
} else {
Intent url = new Intent(Intent.ACTION_VIEW);/// !!!!
url.setData(Uri.parse(qrurl).normalizeScheme());
caption = getResources().getStringArray(R.array.url_array)[0];
startActivity(Intent.createChooser(url, caption));

String urlForIntentData = qrurl;
if (!qrurl.matches(VALID_RFC3986_PROTOCOL_SCHEME)) {
urlForIntentData = "http://" + qrurl;
}
Intent url = new Intent(Intent.ACTION_VIEW);/// !!!!
url.setData(Uri.parse(urlForIntentData).normalizeScheme());
String caption = getResources().getStringArray(R.array.url_array)[0];
startActivity(Intent.createChooser(url, caption));
}
}

Expand Down
55 changes: 55 additions & 0 deletions app/src/main/res/drawable/ic_baseline_qr_code_dots_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorIcons"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/white"
android:pathData="M5,7 a2,2 0 1,1 4,0
a2,2 0 1,1 -4,0
h-2
a4,4 0 1,0 8,0
a4,4 0 1,0 -8,0 Z" />

<path
android:fillColor="@color/white"
android:pathData="M5,17 a2,2 0 1,1 4,0
a2,2 0 1,1 -4,0
h-2
a4,4 0 1,0 8,0
a4,4 0 1,0 -8,0 Z" />

<path
android:fillColor="@color/white"
android:pathData="M15,7 a2,2 0 1,1 4,0
a2,2 0 1,1 -4,0
h-2
a4,4 0 1,0 8,0
a4,4 0 1,0 -8,0 Z" />

<path
android:fillColor="@android:color/white"
android:pathData="M19,20a1,1 0 1,1 2,0a1,1 0 1,1 -2,0z" />
<path
android:fillColor="@android:color/white"
android:pathData="M13,14a1,1 0 1,1 2,0a1,1 0 1,1 -2,0z" />
<path
android:fillColor="@android:color/white"
android:pathData="M15,16a1,1 0 1,1 2,0a1,1 0 1,1 -2,0z" />
<path
android:fillColor="@android:color/white"
android:pathData="M13,18a1,1 0 1,1 2,0a1,1 0 1,1 -2,0z" />
<path
android:fillColor="@android:color/white"
android:pathData="M15,20a1,1 0 1,1 2,0a1,1 0 1,1 -2,0z" />
<path
android:fillColor="@android:color/white"
android:pathData="M17,18a1,1 0 1,1 2,0a1,1 0 1,1 -2,0z" />
<path
android:fillColor="@android:color/white"
android:pathData="M17,14a1,1 0 1,1 2,0a1,1 0 1,1 -2,0z" />
<path
android:fillColor="@android:color/white"
android:pathData="M19,16a1,1 0 1,1 2,0a1,1 0 1,1 -2,0z" />
</vector>
Loading