generate QR Codes internally based on ZXing's core.jar
This app needs to be able to generate QR Codes regardless of what other app might be installed, so zxing's core.jar needs to be embedded in this app. This also includes two classes which are modified versions of ZXing classes that allow the generation of QR Codes without the Barcode Scanner app being installed: https://stackoverflow.com/questions/4782543/integration-zxing-library-directly-into-my-android-application The classes are src/com/google/zxing/encode/Contents.java which is a copy of zxing/android/src/com/google/zxing/client/android/Contents.java; and src/com/google/zxing/encode/QRCodeEncoder.java which is a heavily stripped and modified version of zxing/android/src/com/google/zxing/client/android/encode/QRCodeEncoder.java refs #3204 https://dev.guardianproject.info/issues/3204 refs #2470 https://dev.guardianproject.info/issues/2470
This commit is contained in:
parent
049cd56215
commit
3caec653e5
BIN
libs/core-3.0.1.jar
Normal file
BIN
libs/core-3.0.1.jar
Normal file
Binary file not shown.
17
libs/core-3.0.1.jar.README
Normal file
17
libs/core-3.0.1.jar.README
Normal file
@ -0,0 +1,17 @@
|
||||
zxing
|
||||
-----
|
||||
|
||||
ZXing ("zebra crossing") is an open-source, multi-format 1D/2D barcode image
|
||||
processing library implemented in Java, with ports to other languages.
|
||||
|
||||
https://github.com/zxing/zxing
|
||||
|
||||
Building zxing from scratch is a massive pain, so we use the official jar.
|
||||
The main source repo is SVN, so we couldn't do a git submodule anyway.
|
||||
|
||||
The releases should be signed by this key:
|
||||
Sean Owen (ZXing) <srowen@gmail.com>
|
||||
CE32 85F3 2068 5193 D11F EA01 F6CE 9695 C931 8406
|
||||
|
||||
http://central.maven.org/maven2/com/google/zxing/core/3.0.1/core-3.0.1.jar
|
||||
http://central.maven.org/maven2/com/google/zxing/core/3.0.1/core-3.0.1.jar.asc
|
114
src/com/google/zxing/encode/Contents.java
Executable file
114
src/com/google/zxing/encode/Contents.java
Executable file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.zxing.encode;
|
||||
|
||||
import android.provider.ContactsContract;
|
||||
|
||||
/**
|
||||
* The set of constants to use when sending Barcode Scanner an Intent which requests a barcode
|
||||
* to be encoded.
|
||||
*
|
||||
* @author dswitkin@google.com (Daniel Switkin)
|
||||
*/
|
||||
public final class Contents {
|
||||
private Contents() {
|
||||
}
|
||||
|
||||
public static final class Type {
|
||||
/**
|
||||
* Plain text. Use Intent.putExtra(DATA, string). This can be used for URLs too, but string
|
||||
* must include "http://" or "https://".
|
||||
*/
|
||||
public static final String TEXT = "TEXT_TYPE";
|
||||
|
||||
/**
|
||||
* An email type. Use Intent.putExtra(DATA, string) where string is the email address.
|
||||
*/
|
||||
public static final String EMAIL = "EMAIL_TYPE";
|
||||
|
||||
/**
|
||||
* Use Intent.putExtra(DATA, string) where string is the phone number to call.
|
||||
*/
|
||||
public static final String PHONE = "PHONE_TYPE";
|
||||
|
||||
/**
|
||||
* An SMS type. Use Intent.putExtra(DATA, string) where string is the number to SMS.
|
||||
*/
|
||||
public static final String SMS = "SMS_TYPE";
|
||||
|
||||
/**
|
||||
* A contact. Send a request to encode it as follows:
|
||||
* <p/>
|
||||
* import android.provider.Contacts;
|
||||
* <p/>
|
||||
* Intent intent = new Intent(Intents.Encode.ACTION);
|
||||
* intent.putExtra(Intents.Encode.TYPE, CONTACT);
|
||||
* Bundle bundle = new Bundle();
|
||||
* bundle.putString(Contacts.Intents.Insert.NAME, "Jenny");
|
||||
* bundle.putString(Contacts.Intents.Insert.PHONE, "8675309");
|
||||
* bundle.putString(Contacts.Intents.Insert.EMAIL, "jenny@the80s.com");
|
||||
* bundle.putString(Contacts.Intents.Insert.POSTAL, "123 Fake St. San Francisco, CA 94102");
|
||||
* intent.putExtra(Intents.Encode.DATA, bundle);
|
||||
*/
|
||||
public static final String CONTACT = "CONTACT_TYPE";
|
||||
|
||||
/**
|
||||
* A geographic location. Use as follows:
|
||||
* Bundle bundle = new Bundle();
|
||||
* bundle.putFloat("LAT", latitude);
|
||||
* bundle.putFloat("LONG", longitude);
|
||||
* intent.putExtra(Intents.Encode.DATA, bundle);
|
||||
*/
|
||||
public static final String LOCATION = "LOCATION_TYPE";
|
||||
|
||||
private Type() {
|
||||
}
|
||||
}
|
||||
|
||||
public static final String URL_KEY = "URL_KEY";
|
||||
|
||||
public static final String NOTE_KEY = "NOTE_KEY";
|
||||
|
||||
/**
|
||||
* When using Type.CONTACT, these arrays provide the keys for adding or retrieving multiple
|
||||
* phone numbers and addresses.
|
||||
*/
|
||||
public static final String[] PHONE_KEYS = {
|
||||
ContactsContract.Intents.Insert.PHONE,
|
||||
ContactsContract.Intents.Insert.SECONDARY_PHONE,
|
||||
ContactsContract.Intents.Insert.TERTIARY_PHONE
|
||||
};
|
||||
|
||||
public static final String[] PHONE_TYPE_KEYS = {
|
||||
ContactsContract.Intents.Insert.PHONE_TYPE,
|
||||
ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE,
|
||||
ContactsContract.Intents.Insert.TERTIARY_PHONE_TYPE
|
||||
};
|
||||
|
||||
public static final String[] EMAIL_KEYS = {
|
||||
ContactsContract.Intents.Insert.EMAIL,
|
||||
ContactsContract.Intents.Insert.SECONDARY_EMAIL,
|
||||
ContactsContract.Intents.Insert.TERTIARY_EMAIL
|
||||
};
|
||||
|
||||
public static final String[] EMAIL_TYPE_KEYS = {
|
||||
ContactsContract.Intents.Insert.EMAIL_TYPE,
|
||||
ContactsContract.Intents.Insert.SECONDARY_EMAIL_TYPE,
|
||||
ContactsContract.Intents.Insert.TERTIARY_EMAIL_TYPE
|
||||
};
|
||||
|
||||
}
|
248
src/com/google/zxing/encode/QRCodeEncoder.java
Executable file
248
src/com/google/zxing/encode/QRCodeEncoder.java
Executable file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright (C) 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// from https://stackoverflow.com/questions/4782543/integration-zxing-library-directly-into-my-android-application
|
||||
package com.google.zxing.encode;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.provider.ContactsContract;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.EncodeHintType;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.WriterException;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
public final class QRCodeEncoder {
|
||||
private static final int WHITE = 0xFFFFFFFF;
|
||||
private static final int BLACK = 0xFF000000;
|
||||
|
||||
private int dimension = Integer.MIN_VALUE;
|
||||
private String contents = null;
|
||||
private String displayContents = null;
|
||||
private String title = null;
|
||||
private BarcodeFormat format = null;
|
||||
private boolean encoded = false;
|
||||
|
||||
public QRCodeEncoder(String data, Bundle bundle, String type, String format, int dimension) {
|
||||
this.dimension = dimension;
|
||||
encoded = encodeContents(data, bundle, type, format);
|
||||
}
|
||||
|
||||
public String getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
public String getDisplayContents() {
|
||||
return displayContents;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
private boolean encodeContents(String data, Bundle bundle, String type, String formatString) {
|
||||
// Default to QR_CODE if no format given.
|
||||
format = null;
|
||||
if (formatString != null) {
|
||||
try {
|
||||
format = BarcodeFormat.valueOf(formatString);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
// Ignore it then
|
||||
}
|
||||
}
|
||||
if (format == null || format == BarcodeFormat.QR_CODE) {
|
||||
this.format = BarcodeFormat.QR_CODE;
|
||||
encodeQRCodeContents(data, bundle, type);
|
||||
} else if (data != null && data.length() > 0) {
|
||||
contents = data;
|
||||
displayContents = data;
|
||||
title = "Text";
|
||||
}
|
||||
return contents != null && contents.length() > 0;
|
||||
}
|
||||
|
||||
private void encodeQRCodeContents(String data, Bundle bundle, String type) {
|
||||
if (type.equals(Contents.Type.TEXT)) {
|
||||
if (data != null && data.length() > 0) {
|
||||
contents = data;
|
||||
displayContents = data;
|
||||
title = "Text";
|
||||
}
|
||||
} else if (type.equals(Contents.Type.EMAIL)) {
|
||||
data = trim(data);
|
||||
if (data != null) {
|
||||
contents = "mailto:" + data;
|
||||
displayContents = data;
|
||||
title = "E-Mail";
|
||||
}
|
||||
} else if (type.equals(Contents.Type.PHONE)) {
|
||||
data = trim(data);
|
||||
if (data != null) {
|
||||
contents = "tel:" + data;
|
||||
displayContents = PhoneNumberUtils.formatNumber(data);
|
||||
title = "Phone";
|
||||
}
|
||||
} else if (type.equals(Contents.Type.SMS)) {
|
||||
data = trim(data);
|
||||
if (data != null) {
|
||||
contents = "sms:" + data;
|
||||
displayContents = PhoneNumberUtils.formatNumber(data);
|
||||
title = "SMS";
|
||||
}
|
||||
} else if (type.equals(Contents.Type.CONTACT)) {
|
||||
if (bundle != null) {
|
||||
StringBuilder newContents = new StringBuilder(100);
|
||||
StringBuilder newDisplayContents = new StringBuilder(100);
|
||||
|
||||
newContents.append("MECARD:");
|
||||
|
||||
String name = trim(bundle.getString(ContactsContract.Intents.Insert.NAME));
|
||||
if (name != null) {
|
||||
newContents.append("N:").append(escapeMECARD(name)).append(';');
|
||||
newDisplayContents.append(name);
|
||||
}
|
||||
|
||||
String address = trim(bundle.getString(ContactsContract.Intents.Insert.POSTAL));
|
||||
if (address != null) {
|
||||
newContents.append("ADR:").append(escapeMECARD(address)).append(';');
|
||||
newDisplayContents.append('\n').append(address);
|
||||
}
|
||||
|
||||
Collection<String> uniquePhones = new HashSet<String>(Contents.PHONE_KEYS.length);
|
||||
for (int x = 0; x < Contents.PHONE_KEYS.length; x++) {
|
||||
String phone = trim(bundle.getString(Contents.PHONE_KEYS[x]));
|
||||
if (phone != null) {
|
||||
uniquePhones.add(phone);
|
||||
}
|
||||
}
|
||||
for (String phone : uniquePhones) {
|
||||
newContents.append("TEL:").append(escapeMECARD(phone)).append(';');
|
||||
newDisplayContents.append('\n').append(PhoneNumberUtils.formatNumber(phone));
|
||||
}
|
||||
|
||||
Collection<String> uniqueEmails = new HashSet<String>(Contents.EMAIL_KEYS.length);
|
||||
for (int x = 0; x < Contents.EMAIL_KEYS.length; x++) {
|
||||
String email = trim(bundle.getString(Contents.EMAIL_KEYS[x]));
|
||||
if (email != null) {
|
||||
uniqueEmails.add(email);
|
||||
}
|
||||
}
|
||||
for (String email : uniqueEmails) {
|
||||
newContents.append("EMAIL:").append(escapeMECARD(email)).append(';');
|
||||
newDisplayContents.append('\n').append(email);
|
||||
}
|
||||
|
||||
String url = trim(bundle.getString(Contents.URL_KEY));
|
||||
if (url != null) {
|
||||
// escapeMECARD(url) -> wrong escape e.g. http\://zxing.google.com
|
||||
newContents.append("URL:").append(url).append(';');
|
||||
newDisplayContents.append('\n').append(url);
|
||||
}
|
||||
|
||||
String note = trim(bundle.getString(Contents.NOTE_KEY));
|
||||
if (note != null) {
|
||||
newContents.append("NOTE:").append(escapeMECARD(note)).append(';');
|
||||
newDisplayContents.append('\n').append(note);
|
||||
}
|
||||
|
||||
// Make sure we've encoded at least one field.
|
||||
if (newDisplayContents.length() > 0) {
|
||||
newContents.append(';');
|
||||
contents = newContents.toString();
|
||||
displayContents = newDisplayContents.toString();
|
||||
title = "Contact";
|
||||
} else {
|
||||
contents = null;
|
||||
displayContents = null;
|
||||
}
|
||||
|
||||
}
|
||||
} else if (type.equals(Contents.Type.LOCATION)) {
|
||||
if (bundle != null) {
|
||||
// These must use Bundle.getFloat(), not getDouble(), it's part of the API.
|
||||
float latitude = bundle.getFloat("LAT", Float.MAX_VALUE);
|
||||
float longitude = bundle.getFloat("LONG", Float.MAX_VALUE);
|
||||
if (latitude != Float.MAX_VALUE && longitude != Float.MAX_VALUE) {
|
||||
contents = "geo:" + latitude + ',' + longitude;
|
||||
displayContents = latitude + "," + longitude;
|
||||
title = "Location";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap encodeAsBitmap() throws WriterException {
|
||||
if (!encoded) return null;
|
||||
|
||||
Map<EncodeHintType, Object> hints = null;
|
||||
String encoding = guessAppropriateEncoding(contents);
|
||||
if (encoding != null) {
|
||||
hints = new EnumMap<EncodeHintType, Object>(EncodeHintType.class);
|
||||
hints.put(EncodeHintType.CHARACTER_SET, encoding);
|
||||
}
|
||||
MultiFormatWriter writer = new MultiFormatWriter();
|
||||
BitMatrix result = writer.encode(contents, format, dimension, dimension, hints);
|
||||
int width = result.getWidth();
|
||||
int height = result.getHeight();
|
||||
int[] pixels = new int[width * height];
|
||||
// All are 0, or black, by default
|
||||
for (int y = 0; y < height; y++) {
|
||||
int offset = y * width;
|
||||
for (int x = 0; x < width; x++) {
|
||||
pixels[offset + x] = result.get(x, y) ? BLACK : WHITE;
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private static String guessAppropriateEncoding(CharSequence contents) {
|
||||
// Very crude at the moment
|
||||
for (int i = 0; i < contents.length(); i++) {
|
||||
if (contents.charAt(i) > 0xFF) { return "UTF-8"; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String trim(String s) {
|
||||
if (s == null) { return null; }
|
||||
String result = s.trim();
|
||||
return result.length() == 0 ? null : result;
|
||||
}
|
||||
|
||||
private static String escapeMECARD(String input) {
|
||||
if (input == null || (input.indexOf(':') < 0 && input.indexOf(';') < 0)) { return input; }
|
||||
int length = input.length();
|
||||
StringBuilder result = new StringBuilder(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = input.charAt(i);
|
||||
if (c == ':' || c == ';') {
|
||||
result.append('\\');
|
||||
}
|
||||
result.append(c);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user