mirror of
https://github.com/CatimaLoyalty/Android.git
synced 2025-12-24 15:47:53 -05:00
Compare commits
32 Commits
v2.23.3
...
feature/pk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
435ad2cfb3 | ||
|
|
ef675fe6e5 | ||
|
|
fe4dc868aa | ||
|
|
52e32caca3 | ||
|
|
d7ef204d0a | ||
|
|
915e364454 | ||
|
|
da1d1d62e4 | ||
|
|
fd1b86b1cc | ||
|
|
3f4d0ab5df | ||
|
|
1a6cad893d | ||
|
|
2ef4d3f6e0 | ||
|
|
43148cb12c | ||
|
|
80b45973ac | ||
|
|
ca8243de01 | ||
|
|
b4a532d183 | ||
|
|
a05f9f6ec9 | ||
|
|
79bba52d93 | ||
|
|
04dcee6097 | ||
|
|
6cd7a3f5bf | ||
|
|
09727038ce | ||
|
|
896da82b13 | ||
|
|
ca93f89e1b | ||
|
|
9291563cef | ||
|
|
703db472fc | ||
|
|
b043320af5 | ||
|
|
e1f25ed092 | ||
|
|
05d38a0184 | ||
|
|
5a046b037e | ||
|
|
2f73d510e2 | ||
|
|
2c7cb4769a | ||
|
|
3d543dd23c | ||
|
|
8637f8d2a1 |
@@ -32,6 +32,11 @@ android {
|
||||
disable "MissingTranslation"
|
||||
disable "MissingPrefix"
|
||||
}
|
||||
sourceSets {
|
||||
test {
|
||||
resources.srcDirs += ['src/test/resources']
|
||||
}
|
||||
}
|
||||
|
||||
// Starting with Android Studio 3 Robolectric is unable to find resources.
|
||||
// The following allows it to find the resources.
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- Accepts URIs that begin with "https://github.com/brarcher/loyalty-card-locker/” -->
|
||||
<!-- Accepts URIs that begin with "https://thelastproject.github.io/Catima/share" or "https://brarcher.github.io/loyalty-card-locker/share” -->
|
||||
<data android:scheme="https"
|
||||
android:host="@string/intent_import_card_from_url_host"
|
||||
android:pathPrefix="@string/intent_import_card_from_url_path_prefix" />
|
||||
@@ -57,6 +57,19 @@
|
||||
android:host="@string/intent_import_card_from_url_host_old"
|
||||
android:pathPrefix="@string/intent_import_card_from_url_path_prefix_old" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<!-- Accept pkpass files -->
|
||||
<data android:scheme="content" android:mimeType="application/octet-stream"/>
|
||||
<data android:scheme="content" android:mimeType="application/x-compressed"/>
|
||||
<data android:scheme="content" android:mimeType="application/x-zip-compressed"/>
|
||||
<data android:scheme="content" android:mimeType="application/zip"/>
|
||||
<data android:scheme="content" android:mimeType="application/vnd.apple.pkpass"/>
|
||||
<data android:scheme="content" android:mimeType="application/pkpass"/>
|
||||
<data android:scheme="content" android:mimeType="application/vndapplepkpass"/>
|
||||
<data android:scheme="content" android:mimeType="application/vnd-com.apple.pkpass"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".BarcodeSelectorActivity"
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.database.Cursor;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVPrinter;
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
@@ -25,7 +26,8 @@ public class CsvDatabaseExporter implements DatabaseExporter
|
||||
DBHelper.LoyaltyCardDbIds.CARD_ID,
|
||||
DBHelper.LoyaltyCardDbIds.HEADER_COLOR,
|
||||
DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR,
|
||||
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE);
|
||||
DBHelper.LoyaltyCardDbIds.BARCODE_TYPE,
|
||||
DBHelper.LoyaltyCardDbIds.EXTRAS);
|
||||
|
||||
Cursor cursor = db.getLoyaltyCardCursor();
|
||||
|
||||
@@ -33,13 +35,23 @@ public class CsvDatabaseExporter implements DatabaseExporter
|
||||
{
|
||||
LoyaltyCard card = LoyaltyCard.toLoyaltyCard(cursor);
|
||||
|
||||
String extras;
|
||||
try {
|
||||
extras = card.extras.toJSON().toString();
|
||||
}
|
||||
catch (JSONException ex)
|
||||
{
|
||||
throw new IOException(ex);
|
||||
}
|
||||
|
||||
printer.printRecord(card.id,
|
||||
card.store,
|
||||
card.note,
|
||||
card.cardId,
|
||||
card.headerColor,
|
||||
card.headerTextColor,
|
||||
card.barcodeType);
|
||||
card.barcodeType,
|
||||
extras);
|
||||
|
||||
if(Thread.currentThread().isInterrupted())
|
||||
{
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import org.apache.commons.csv.CSVFormat;
|
||||
import org.apache.commons.csv.CSVParser;
|
||||
import org.apache.commons.csv.CSVRecord;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.Normalizer;
|
||||
|
||||
/**
|
||||
* Class for importing a database from CSV (Comma Separate Values)
|
||||
@@ -142,6 +146,23 @@ public class CsvDatabaseImporter implements DatabaseImporter
|
||||
headerTextColor = extractInt(DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR, record, true);
|
||||
}
|
||||
|
||||
helper.insertLoyaltyCard(database, id, store, note, cardId, barcodeType, headerColor, headerTextColor);
|
||||
Bitmap icon = null;
|
||||
String iconData = extractString(DBHelper.LoyaltyCardDbIds.ICON, record, "");
|
||||
if(!iconData.isEmpty())
|
||||
{
|
||||
icon = DBHelper.convertBitmapBlobToBitmap(iconData.getBytes("UTF-8"));
|
||||
}
|
||||
|
||||
ExtrasHelper extras = new ExtrasHelper();
|
||||
|
||||
try
|
||||
{
|
||||
extras.fromJSON(new JSONObject(extractString(DBHelper.LoyaltyCardDbIds.EXTRAS, record, "{}")));
|
||||
helper.insertLoyaltyCard(database, id, store, note, cardId, barcodeType, headerColor, headerTextColor, icon, extras);
|
||||
}
|
||||
catch (JSONException ex)
|
||||
{
|
||||
throw new FormatException("Invalid JSON in extras field: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,20 @@ import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class DBHelper extends SQLiteOpenHelper
|
||||
{
|
||||
public static final String DATABASE_NAME = "Catima.db";
|
||||
public static final int ORIGINAL_DATABASE_VERSION = 1;
|
||||
public static final int DATABASE_VERSION = 3;
|
||||
public static final int DATABASE_VERSION = 4;
|
||||
|
||||
static class LoyaltyCardDbIds
|
||||
{
|
||||
@@ -23,6 +31,8 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
public static final String HEADER_TEXT_COLOR = "headertextcolor";
|
||||
public static final String CARD_ID = "cardid";
|
||||
public static final String BARCODE_TYPE = "barcodetype";
|
||||
public static final String ICON = "icon";
|
||||
public static final String EXTRAS = "extras";
|
||||
}
|
||||
|
||||
public DBHelper(Context context)
|
||||
@@ -30,6 +40,19 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||
}
|
||||
|
||||
public static byte[] convertBitmapToBlob(Bitmap bitmap)
|
||||
{
|
||||
// https://stackoverflow.com/a/7620610
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 0, byteArrayOutputStream);
|
||||
return byteArrayOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
public static Bitmap convertBitmapBlobToBitmap(byte[] bytes)
|
||||
{
|
||||
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db)
|
||||
{
|
||||
@@ -41,7 +64,9 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
LoyaltyCardDbIds.HEADER_COLOR + " INTEGER," +
|
||||
LoyaltyCardDbIds.HEADER_TEXT_COLOR + " INTEGER," +
|
||||
LoyaltyCardDbIds.CARD_ID + " TEXT not null," +
|
||||
LoyaltyCardDbIds.BARCODE_TYPE + " TEXT not null)");
|
||||
LoyaltyCardDbIds.BARCODE_TYPE + " TEXT not null," +
|
||||
LoyaltyCardDbIds.ICON + " BLOB," +
|
||||
LoyaltyCardDbIds.EXTRAS + " TEXT)");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,11 +87,21 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.HEADER_TEXT_COLOR + " INTEGER");
|
||||
}
|
||||
|
||||
// Upgrade from version 3 to version 4
|
||||
if(oldVersion < 4 && newVersion >= 4)
|
||||
{
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.ICON + " BLOB");
|
||||
db.execSQL("ALTER TABLE " + LoyaltyCardDbIds.TABLE
|
||||
+ " ADD COLUMN " + LoyaltyCardDbIds.EXTRAS + " TEXT");
|
||||
}
|
||||
}
|
||||
|
||||
public long insertLoyaltyCard(final String store, final String note, final String cardId,
|
||||
final String barcodeType, final Integer headerColor,
|
||||
final Integer headerTextColor)
|
||||
final Integer headerTextColor, final Bitmap icon,
|
||||
final ExtrasHelper extras) throws JSONException
|
||||
{
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
@@ -76,6 +111,8 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_TEXT_COLOR, headerTextColor);
|
||||
contentValues.put(LoyaltyCardDbIds.ICON, icon != null ? convertBitmapToBlob(icon) : null);
|
||||
contentValues.put(LoyaltyCardDbIds.EXTRAS, extras.toJSON().toString());
|
||||
final long newId = db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
|
||||
return newId;
|
||||
}
|
||||
@@ -83,7 +120,8 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
public boolean insertLoyaltyCard(final SQLiteDatabase db, final int id,
|
||||
final String store, final String note, final String cardId,
|
||||
final String barcodeType, final Integer headerColor,
|
||||
final Integer headerTextColor)
|
||||
final Integer headerTextColor, final Bitmap icon,
|
||||
final ExtrasHelper extras) throws JSONException
|
||||
{
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(LoyaltyCardDbIds.ID, id);
|
||||
@@ -93,6 +131,8 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_TEXT_COLOR, headerTextColor);
|
||||
contentValues.put(LoyaltyCardDbIds.ICON, icon != null ? convertBitmapToBlob(icon) : null);
|
||||
contentValues.put(LoyaltyCardDbIds.EXTRAS, extras.toJSON().toString());
|
||||
final long newId = db.insert(LoyaltyCardDbIds.TABLE, null, contentValues);
|
||||
return (newId != -1);
|
||||
}
|
||||
@@ -100,7 +140,8 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
|
||||
public boolean updateLoyaltyCard(final int id, final String store, final String note,
|
||||
final String cardId, final String barcodeType,
|
||||
final Integer headerColor, final Integer headerTextColor)
|
||||
final Integer headerColor, final Integer headerTextColor,
|
||||
final Bitmap icon, final ExtrasHelper extras) throws JSONException
|
||||
{
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
@@ -110,6 +151,8 @@ public class DBHelper extends SQLiteOpenHelper
|
||||
contentValues.put(LoyaltyCardDbIds.BARCODE_TYPE, barcodeType);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_COLOR, headerColor);
|
||||
contentValues.put(LoyaltyCardDbIds.HEADER_TEXT_COLOR, headerTextColor);
|
||||
contentValues.put(LoyaltyCardDbIds.ICON, icon != null ? convertBitmapToBlob(icon) : null);
|
||||
contentValues.put(LoyaltyCardDbIds.EXTRAS, extras.toJSON().toString());
|
||||
int rowsUpdated = db.update(LoyaltyCardDbIds.TABLE, contentValues,
|
||||
LoyaltyCardDbIds.ID + "=?",
|
||||
new String[]{Integer.toString(id)});
|
||||
|
||||
77
app/src/main/java/protect/card_locker/ExtrasHelper.java
Normal file
77
app/src/main/java/protect/card_locker/ExtrasHelper.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class ExtrasHelper {
|
||||
private HashMap<String, LinkedHashMap<String, String>> extras = new HashMap<>();
|
||||
|
||||
public ExtrasHelper fromJSON(JSONObject json) throws JSONException
|
||||
{
|
||||
Iterator<String> languages = json.keys();
|
||||
|
||||
while(languages.hasNext())
|
||||
{
|
||||
String language = languages.next();
|
||||
Iterator<String> keys = json.getJSONObject(language).keys();
|
||||
|
||||
while(keys.hasNext())
|
||||
{
|
||||
String key = keys.next();
|
||||
addLanguageValue(language, key, json.getJSONObject(language).getString(key));
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSONObject toJSON() throws JSONException
|
||||
{
|
||||
return new JSONObject(extras);
|
||||
}
|
||||
|
||||
public void addLanguageValue(String language, String key, String value)
|
||||
{
|
||||
if(!extras.containsKey(language))
|
||||
{
|
||||
extras.put(language, new LinkedHashMap<String, String>());
|
||||
}
|
||||
|
||||
LinkedHashMap<String, String> values = extras.get(language);
|
||||
values.put(key, value);
|
||||
|
||||
extras.put(language, values);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public LinkedHashMap<String, String> getAllValues(String language)
|
||||
{
|
||||
return getAllValues(new String[]{language});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public LinkedHashMap<String, String> getAllValues(String[] languages)
|
||||
{
|
||||
LinkedHashMap<String, String> values = new LinkedHashMap<>();
|
||||
|
||||
// Get least preferred language (last in list) first
|
||||
// Then go further and further to the start of the list (preferred language)
|
||||
for(int i = (languages.length - 1); i >= 0; i--)
|
||||
{
|
||||
LinkedHashMap<String, String> languageValues = extras.get(languages[i]);
|
||||
|
||||
if(languageValues != null)
|
||||
{
|
||||
values.putAll(languageValues);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,13 @@ package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.util.Base64;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
|
||||
public class ImportURIHelper {
|
||||
@@ -12,6 +18,8 @@ public class ImportURIHelper {
|
||||
private static final String BARCODE_TYPE = DBHelper.LoyaltyCardDbIds.BARCODE_TYPE;
|
||||
private static final String HEADER_COLOR = DBHelper.LoyaltyCardDbIds.HEADER_COLOR;
|
||||
private static final String HEADER_TEXT_COLOR = DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR;
|
||||
private static final String ICON = DBHelper.LoyaltyCardDbIds.ICON;
|
||||
private static final String EXTRAS = DBHelper.LoyaltyCardDbIds.EXTRAS;
|
||||
|
||||
private final Context context;
|
||||
private final String host;
|
||||
@@ -24,12 +32,12 @@ public class ImportURIHelper {
|
||||
this.context = context;
|
||||
host = context.getResources().getString(R.string.intent_import_card_from_url_host);
|
||||
path = context.getResources().getString(R.string.intent_import_card_from_url_path_prefix);
|
||||
oldHost = "brarcher.github.io";
|
||||
oldPath = "/loyalty-card-locker/share";
|
||||
oldHost = context.getResources().getString(R.string.intent_import_card_from_url_host_old);
|
||||
oldPath = context.getResources().getString(R.string.intent_import_card_from_url_path_prefix_old);
|
||||
shareText = context.getResources().getString(R.string.intent_import_card_from_url_share_text);
|
||||
}
|
||||
|
||||
private boolean isImportUri(Uri uri) {
|
||||
public boolean isImportUri(Uri uri) {
|
||||
return (uri.getHost().equals(host) && uri.getPath().equals(path)) || (uri.getHost().equals(oldHost) && uri.getPath().equals(oldPath));
|
||||
}
|
||||
|
||||
@@ -57,14 +65,36 @@ public class ImportURIHelper {
|
||||
{
|
||||
headerTextColor = Integer.parseInt(unparsedHeaderTextColor);
|
||||
}
|
||||
return new LoyaltyCard(-1, store, note, cardId, barcodeType, headerColor, headerTextColor);
|
||||
} catch (NullPointerException | NumberFormatException ex) {
|
||||
String iconData = uri.getQueryParameter(ICON);
|
||||
Bitmap icon = null;
|
||||
|
||||
if(iconData != null && !iconData.isEmpty())
|
||||
{
|
||||
byte[] iconBytes = Base64.decode(iconData, Base64.URL_SAFE);
|
||||
icon = DBHelper.convertBitmapBlobToBitmap(iconBytes);
|
||||
}
|
||||
|
||||
String extrasData = uri.getQueryParameter(EXTRAS);
|
||||
ExtrasHelper extras = new ExtrasHelper();
|
||||
if(extrasData != null && !extrasData.isEmpty())
|
||||
{
|
||||
extras.fromJSON(new JSONObject(uri.getQueryParameter(EXTRAS)));
|
||||
}
|
||||
|
||||
return new LoyaltyCard(-1, store, note, cardId, barcodeType, headerColor, headerTextColor, icon, extras);
|
||||
} catch (NullPointerException | NumberFormatException | JSONException ex) {
|
||||
throw new InvalidObjectException("Not a valid import URI");
|
||||
}
|
||||
}
|
||||
|
||||
// Protected for usage in tests
|
||||
protected Uri toUri(LoyaltyCard loyaltyCard) {
|
||||
protected Uri toUri(LoyaltyCard loyaltyCard) throws JSONException {
|
||||
String icon = "";
|
||||
if(loyaltyCard.icon != null)
|
||||
{
|
||||
icon = Base64.encodeToString(DBHelper.convertBitmapToBlob(loyaltyCard.icon), Base64.URL_SAFE);
|
||||
}
|
||||
|
||||
Uri.Builder uriBuilder = new Uri.Builder();
|
||||
uriBuilder.scheme("https");
|
||||
uriBuilder.authority(host);
|
||||
@@ -81,6 +111,8 @@ public class ImportURIHelper {
|
||||
{
|
||||
uriBuilder.appendQueryParameter(HEADER_TEXT_COLOR, loyaltyCard.headerTextColor.toString());
|
||||
}
|
||||
uriBuilder.appendQueryParameter(ICON, icon);
|
||||
uriBuilder.appendQueryParameter(EXTRAS, loyaltyCard.extras.toJSON().toString());
|
||||
|
||||
return uriBuilder.build();
|
||||
}
|
||||
@@ -95,7 +127,14 @@ public class ImportURIHelper {
|
||||
context.startActivity(shareIntent);
|
||||
}
|
||||
|
||||
public void startShareIntent(LoyaltyCard loyaltyCard) {
|
||||
startShareIntent(toUri(loyaltyCard));
|
||||
public boolean startShareIntent(LoyaltyCard loyaltyCard) {
|
||||
try
|
||||
{
|
||||
startShareIntent(toUri(loyaltyCard));
|
||||
return true;
|
||||
}
|
||||
catch (JSONException ex) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class LoyaltyCard
|
||||
{
|
||||
public final int id;
|
||||
@@ -17,8 +22,15 @@ public class LoyaltyCard
|
||||
@Nullable
|
||||
public final Integer headerTextColor;
|
||||
|
||||
@Nullable
|
||||
public final Bitmap icon;
|
||||
|
||||
@Nullable
|
||||
public final ExtrasHelper extras;
|
||||
|
||||
public LoyaltyCard(final int id, final String store, final String note, final String cardId,
|
||||
final String barcodeType, final Integer headerColor, final Integer headerTextColor)
|
||||
final String barcodeType, final Integer headerColor, final Integer headerTextColor,
|
||||
final Bitmap icon, final ExtrasHelper extras)
|
||||
{
|
||||
this.id = id;
|
||||
this.store = store;
|
||||
@@ -27,6 +39,8 @@ public class LoyaltyCard
|
||||
this.barcodeType = barcodeType;
|
||||
this.headerColor = headerColor;
|
||||
this.headerTextColor = headerTextColor;
|
||||
this.icon = icon;
|
||||
this.extras = extras;
|
||||
}
|
||||
|
||||
public static LoyaltyCard toLoyaltyCard(Cursor cursor)
|
||||
@@ -53,6 +67,32 @@ public class LoyaltyCard
|
||||
headerTextColor = cursor.getInt(headerTextColorColumn);
|
||||
}
|
||||
|
||||
return new LoyaltyCard(id, store, note, cardId, barcodeType, headerColor, headerTextColor);
|
||||
int iconColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.ICON);
|
||||
Bitmap icon = null;
|
||||
|
||||
if(cursor.isNull(iconColumn) == false)
|
||||
{
|
||||
byte[] iconData = cursor.getBlob(iconColumn);
|
||||
icon = BitmapFactory.decodeByteArray(iconData, 0, iconData.length);
|
||||
}
|
||||
|
||||
int extrasColumn = cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.EXTRAS);
|
||||
ExtrasHelper extras = new ExtrasHelper();
|
||||
|
||||
if(cursor.isNull(extrasColumn) == false)
|
||||
{
|
||||
try
|
||||
{
|
||||
extras = extras.fromJSON(new JSONObject(cursor.getString(extrasColumn)));
|
||||
}
|
||||
catch (JSONException ex)
|
||||
{
|
||||
// That this is actually JSON is an implementation detail
|
||||
// The important part is that the DB is in a bad state
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
return new LoyaltyCard(id, store, note, cardId, barcodeType, headerColor, headerTextColor, icon, extras);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -61,10 +62,18 @@ class LoyaltyCardCursorAdapter extends CursorAdapter
|
||||
int tileLetterFontSize = context.getResources().getDimensionPixelSize(R.dimen.tileLetterFontSize);
|
||||
int pixelSize = context.getResources().getDimensionPixelSize(R.dimen.cardThumbnailSize);
|
||||
|
||||
Integer letterBackgroundColor = loyaltyCard.headerColor;
|
||||
Integer letterTextColor = loyaltyCard.headerTextColor;
|
||||
LetterBitmap letterBitmap = new LetterBitmap(context, loyaltyCard.store, loyaltyCard.store,
|
||||
tileLetterFontSize, pixelSize, pixelSize, letterBackgroundColor, letterTextColor);
|
||||
thumbnail.setImageBitmap(letterBitmap.getLetterTile());
|
||||
|
||||
if(loyaltyCard.icon == null)
|
||||
{
|
||||
Integer letterBackgroundColor = loyaltyCard.headerColor;
|
||||
Integer letterTextColor = loyaltyCard.headerTextColor;
|
||||
LetterBitmap letterBitmap = new LetterBitmap(context, loyaltyCard.store, loyaltyCard.store,
|
||||
tileLetterFontSize, pixelSize, pixelSize, letterBackgroundColor, letterTextColor);
|
||||
thumbnail.setImageBitmap(letterBitmap.getLetterTile());
|
||||
}
|
||||
else
|
||||
{
|
||||
thumbnail.setImageBitmap(loyaltyCard.icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
@@ -32,6 +33,10 @@ import com.google.zxing.integration.android.IntentResult;
|
||||
import com.jaredrummler.android.colorpicker.ColorPickerDialog;
|
||||
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
|
||||
public class LoyaltyCardEditActivity extends AppCompatActivity
|
||||
@@ -61,23 +66,53 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
|
||||
int loyaltyCardId;
|
||||
boolean updateLoyaltyCard;
|
||||
Uri importLoyaltyCardUri = null;
|
||||
String importLoyaltyCardType = null;
|
||||
Integer headingColorValue = null;
|
||||
Integer headingStoreTextColorValue = null;
|
||||
Bitmap icon = null;
|
||||
ExtrasHelper extras = new ExtrasHelper();
|
||||
|
||||
DBHelper db;
|
||||
ImportURIHelper importUriHelper;
|
||||
PkpassImporter pkpassImporter;
|
||||
|
||||
private void extractIntentFields(Intent intent)
|
||||
{
|
||||
final Bundle b = intent.getExtras();
|
||||
loyaltyCardId = b != null ? b.getInt("id") : 0;
|
||||
updateLoyaltyCard = b != null && b.getBoolean("update", false);
|
||||
importLoyaltyCardType = intent.getType();
|
||||
importLoyaltyCardUri = intent.getData();
|
||||
|
||||
Log.d(TAG, "View activity: id=" + loyaltyCardId
|
||||
+ ", updateLoyaltyCard=" + Boolean.toString(updateLoyaltyCard));
|
||||
}
|
||||
|
||||
private LoyaltyCard importCard(String type, Uri uri)
|
||||
{
|
||||
// Import URI
|
||||
if(importUriHelper.isImportUri(uri))
|
||||
{
|
||||
try
|
||||
{
|
||||
return importUriHelper.parse(importLoyaltyCardUri);
|
||||
}
|
||||
catch (InvalidObjectException ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Pkpass
|
||||
try
|
||||
{
|
||||
return pkpassImporter.fromURI(uri);
|
||||
}
|
||||
catch (IOException | JSONException ex) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
@@ -96,6 +131,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
|
||||
|
||||
db = new DBHelper(this);
|
||||
importUriHelper = new ImportURIHelper(this);
|
||||
pkpassImporter = new PkpassImporter(this);
|
||||
|
||||
storeFieldEdit = findViewById(R.id.storeNameEdit);
|
||||
noteFieldEdit = findViewById(R.id.noteEdit);
|
||||
@@ -186,15 +222,17 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
|
||||
}
|
||||
}
|
||||
|
||||
extras = loyaltyCard.extras;
|
||||
|
||||
setTitle(R.string.editCardTitle);
|
||||
}
|
||||
else if(importLoyaltyCardUri != null)
|
||||
{
|
||||
// Try to parse
|
||||
LoyaltyCard importCard;
|
||||
try {
|
||||
importCard = importUriHelper.parse(importLoyaltyCardUri);
|
||||
} catch (InvalidObjectException ex) {
|
||||
LoyaltyCard importCard = importCard(importLoyaltyCardType, importLoyaltyCardUri);
|
||||
|
||||
if(importCard == null)
|
||||
{
|
||||
Toast.makeText(this, R.string.failedParsingImportUriError, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
return;
|
||||
@@ -206,6 +244,8 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
|
||||
barcodeTypeField.setText(importCard.barcodeType);
|
||||
headingColorValue = importCard.headerColor;
|
||||
headingStoreTextColorValue = importCard.headerTextColor;
|
||||
icon = importCard.icon;
|
||||
extras = importCard.extras;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -331,7 +371,11 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
|
||||
saveButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
doSave();
|
||||
try {
|
||||
doSave();
|
||||
} catch (JSONException ex) {
|
||||
Toast.makeText(getApplicationContext(), R.string.failedSavingCard, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -378,7 +422,7 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void doSave()
|
||||
private void doSave() throws JSONException
|
||||
{
|
||||
String store = storeFieldEdit.getText().toString();
|
||||
String note = noteFieldEdit.getText().toString();
|
||||
@@ -406,12 +450,12 @@ public class LoyaltyCardEditActivity extends AppCompatActivity
|
||||
|
||||
if(updateLoyaltyCard)
|
||||
{
|
||||
db.updateLoyaltyCard(loyaltyCardId, store, note, cardId, barcodeType, headingColorValue, headingStoreTextColorValue);
|
||||
db.updateLoyaltyCard(loyaltyCardId, store, note, cardId, barcodeType, headingColorValue, headingStoreTextColorValue, icon, extras);
|
||||
Log.i(TAG, "Updated " + loyaltyCardId + " to " + cardId);
|
||||
}
|
||||
else
|
||||
{
|
||||
loyaltyCardId = (int)db.insertLoyaltyCard(store, note, cardId, barcodeType, headingColorValue, headingStoreTextColorValue);
|
||||
loyaltyCardId = (int)db.insertLoyaltyCard(store, note, cardId, barcodeType, headingColorValue, headingStoreTextColorValue, icon, extras);
|
||||
}
|
||||
|
||||
finish();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package protect.card_locker;
|
||||
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Color;
|
||||
@@ -8,6 +9,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
@@ -32,6 +34,12 @@ import android.widget.Toast;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import protect.card_locker.preferences.Settings;
|
||||
|
||||
|
||||
@@ -317,6 +325,13 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
item.setVisible(false);
|
||||
}
|
||||
|
||||
if(loyaltyCard != null && !loyaltyCard.extras.getAllValues(new String[]{Locale.getDefault().getLanguage(), "en", ""}).isEmpty())
|
||||
{
|
||||
MenuItem extraItem = menu.findItem(R.id.action_view_extras);
|
||||
extraItem.setIcon(getIcon(R.drawable.ic_info_outline_white, backgroundNeedsDarkIcons));
|
||||
extraItem.setVisible(true);
|
||||
}
|
||||
|
||||
menu.findItem(R.id.action_share).setIcon(getIcon(R.drawable.ic_share_white, backgroundNeedsDarkIcons));
|
||||
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
@@ -348,6 +363,18 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
}
|
||||
rotationEnabled = !rotationEnabled;
|
||||
return true;
|
||||
|
||||
case R.id.action_view_extras:
|
||||
try
|
||||
{
|
||||
displayExtrasDialog();
|
||||
}
|
||||
catch (JSONException ex)
|
||||
{
|
||||
Toast.makeText(this, R.string.failedShowingExtras, Toast.LENGTH_LONG).show();
|
||||
finish();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
@@ -370,6 +397,29 @@ public class LoyaltyCardViewActivity extends AppCompatActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void displayExtrasDialog() throws JSONException
|
||||
{
|
||||
StringBuilder items = new StringBuilder();
|
||||
|
||||
HashMap<String, String> extraValues = loyaltyCard.extras.getAllValues(new String[]{Locale.getDefault().getLanguage(), "en", ""});
|
||||
for(Map.Entry<String, String> entry : extraValues.entrySet())
|
||||
{
|
||||
items.append(entry.getValue() + "\n");
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(items.toString())
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener()
|
||||
{
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
dialog.dismiss();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* When enabled, hides the status bar and moves the barcode to the top of the screen.
|
||||
*
|
||||
|
||||
@@ -14,7 +14,6 @@ import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
@@ -210,7 +209,10 @@ public class MainActivity extends AppCompatActivity
|
||||
else if(item.getItemId() == R.id.action_share)
|
||||
{
|
||||
final ImportURIHelper importURIHelper = new ImportURIHelper(this);
|
||||
importURIHelper.startShareIntent(card);
|
||||
if(importURIHelper.startShareIntent(card))
|
||||
{
|
||||
Toast.makeText(this, R.string.failedSharingCard, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
319
app/src/main/java/protect/card_locker/PkpassImporter.java
Normal file
319
app/src/main/java/protect/card_locker/PkpassImporter.java
Normal file
@@ -0,0 +1,319 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
public class PkpassImporter {
|
||||
private Context context;
|
||||
|
||||
private Bitmap icon = null;
|
||||
|
||||
private HashMap<String, HashMap<String, String>> translations = new HashMap<>();
|
||||
|
||||
public PkpassImporter(Context context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private ByteArrayOutputStream readZipInputStream(ZipInputStream zipInputStream) throws IOException
|
||||
{
|
||||
byte[] buffer = new byte[2048];
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
int size;
|
||||
|
||||
while((size = zipInputStream.read(buffer, 0, buffer.length)) != -1)
|
||||
{
|
||||
byteArrayOutputStream.write(buffer, 0, size);
|
||||
}
|
||||
|
||||
return byteArrayOutputStream;
|
||||
}
|
||||
|
||||
private void loadBitmap(ByteArrayOutputStream byteArrayOutputStream)
|
||||
{
|
||||
byte[] bytes = byteArrayOutputStream.toByteArray();
|
||||
// Only keep the largest icon
|
||||
if(icon != null && bytes.length < icon.getByteCount())
|
||||
{
|
||||
return;
|
||||
}
|
||||
icon = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
// FIXME: Probably very fragile
|
||||
private void parseTranslations(String language, String iOSTranslationFileContent)
|
||||
{
|
||||
if(!translations.containsKey(language))
|
||||
{
|
||||
translations.put(language, new HashMap<String, String>());
|
||||
}
|
||||
|
||||
HashMap<String, String> values = translations.get(language);
|
||||
|
||||
for (String entry : iOSTranslationFileContent.trim().split(";"))
|
||||
{
|
||||
String[] parts = entry.split(" = ", 2);
|
||||
|
||||
// Remove all spaces around the key and value
|
||||
String key = parts[0].trim();
|
||||
String value = parts[1].trim();
|
||||
|
||||
// iOS .string files quote everything in double quotes, we don't need to keep those
|
||||
values.put(key.substring(1, key.length()-1), value.substring(1, value.length()-1));
|
||||
}
|
||||
|
||||
translations.put(language, values);
|
||||
}
|
||||
|
||||
private ExtrasHelper appendData(ExtrasHelper extrasHelper, JSONObject pkpassJSON, String styleKey, String arrayName) throws JSONException
|
||||
{
|
||||
// https://developer.apple.com/library/archive/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/FieldDictionary.html#//apple_ref/doc/uid/TP40012026-CH4-SW1
|
||||
|
||||
JSONArray fields;
|
||||
// These are all optional, so don't throw an exception if they don't exist
|
||||
try
|
||||
{
|
||||
fields = pkpassJSON.getJSONObject(styleKey).getJSONArray(arrayName);
|
||||
}
|
||||
catch (JSONException ex)
|
||||
{
|
||||
return extrasHelper;
|
||||
}
|
||||
|
||||
for(int i = 0; i < fields.length(); i++)
|
||||
{
|
||||
JSONObject fieldObject = fields.getJSONObject(i);
|
||||
String key = fieldObject.getString("key");
|
||||
String label = fieldObject.getString("label");
|
||||
String value = fieldObject.getString("value");
|
||||
|
||||
// Label is optional
|
||||
if(label == null)
|
||||
{
|
||||
label = key;
|
||||
}
|
||||
|
||||
// Add the completely untranslated stuff as fallback
|
||||
String formattedUntranslatedValue = value;
|
||||
if(!label.isEmpty())
|
||||
{
|
||||
formattedUntranslatedValue = label + ": " + value;
|
||||
}
|
||||
extrasHelper.addLanguageValue("", key, formattedUntranslatedValue);
|
||||
|
||||
// Try to find translations
|
||||
for(Map.Entry<String, HashMap<String, String>> language : translations.entrySet())
|
||||
{
|
||||
String translatedLabel = label;
|
||||
if(language.getValue().containsKey(label))
|
||||
{
|
||||
translatedLabel = language.getValue().get(label);
|
||||
}
|
||||
|
||||
String translatedValue = value;
|
||||
if(language.getValue().containsKey(value))
|
||||
{
|
||||
translatedValue = language.getValue().get(value);
|
||||
}
|
||||
|
||||
String formattedValue = translatedValue;
|
||||
|
||||
if(!translatedLabel.isEmpty())
|
||||
{
|
||||
formattedValue = translatedLabel + ": " + translatedValue;
|
||||
}
|
||||
|
||||
extrasHelper.addLanguageValue(language.getKey(), key, formattedValue);
|
||||
}
|
||||
}
|
||||
|
||||
return extrasHelper;
|
||||
}
|
||||
|
||||
public LoyaltyCard fromURI(Uri uri) throws IOException, JSONException {
|
||||
return fromInputStream(context.getContentResolver().openInputStream(uri));
|
||||
}
|
||||
|
||||
public LoyaltyCard fromInputStream(InputStream inputStream) throws IOException, JSONException
|
||||
{
|
||||
String passJSONString = null;
|
||||
|
||||
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
|
||||
|
||||
ZipEntry entry;
|
||||
|
||||
// We first want to parse the translations
|
||||
while((entry = zipInputStream.getNextEntry()) != null) {
|
||||
if(entry.getName().endsWith("pass.strings"))
|
||||
{
|
||||
// Example: en.lproj/pass.strings
|
||||
String language = entry.getName().substring(0, entry.getName().indexOf("."));
|
||||
|
||||
parseTranslations(language, readZipInputStream(zipInputStream).toString("UTF-8"));
|
||||
}
|
||||
else if(entry.getName().equals("pass.json"))
|
||||
{
|
||||
passJSONString = readZipInputStream(zipInputStream).toString("UTF-8");
|
||||
}
|
||||
else if(entry.getName().equals("icon.png") || entry.getName().equals("icon@2x.png"))
|
||||
{
|
||||
loadBitmap(readZipInputStream(zipInputStream));
|
||||
}
|
||||
}
|
||||
|
||||
if(passJSONString == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return fromPassJSON(new JSONObject(passJSONString));
|
||||
}
|
||||
|
||||
public LoyaltyCard fromPassJSON(JSONObject json) throws JSONException
|
||||
{
|
||||
String store = json.getString("organizationName");
|
||||
String note = json.getString("description");
|
||||
|
||||
// https://developer.apple.com/library/archive/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/TopLevel.html#//apple_ref/doc/uid/TP40012026-CH2-SW1
|
||||
// barcodes is the new field
|
||||
// barcode is deprecated, but used on old iOS versions, so we do fall back to it
|
||||
JSONObject barcode = null;
|
||||
JSONArray barcodes = null;
|
||||
|
||||
try {
|
||||
barcodes = json.getJSONArray("barcodes");
|
||||
} catch (JSONException ex) {
|
||||
}
|
||||
|
||||
if (barcodes != null) {
|
||||
barcode = barcodes.getJSONObject(0);
|
||||
} else {
|
||||
barcode = json.getJSONObject("barcode");
|
||||
}
|
||||
|
||||
if (barcode == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String cardId = barcode.getString("message");
|
||||
|
||||
// https://developer.apple.com/library/archive/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/LowerLevel.html#//apple_ref/doc/uid/TP40012026-CH3-SW3
|
||||
// Required. Barcode format. For the barcode dictionary, you can use only the following values: PKBarcodeFormatQR, PKBarcodeFormatPDF417, or PKBarcodeFormatAztec. For dictionaries in the barcodes array, you may also use PKBarcodeFormatCode128.
|
||||
ImmutableMap<String, String> supportedBarcodeTypes = ImmutableMap.<String, String>builder()
|
||||
.put("PKBarcodeFormatQR", BarcodeFormat.QR_CODE.name())
|
||||
.put("PKBarcodeFormatPDF417", BarcodeFormat.PDF_417.name())
|
||||
.put("PKBarcodeFormatAztec", BarcodeFormat.AZTEC.name())
|
||||
.put("PKBarcodeFormatCode128", BarcodeFormat.CODE_128.name())
|
||||
.build();
|
||||
|
||||
String barcodeType = supportedBarcodeTypes.get(barcode.getString("format"));
|
||||
|
||||
if(barcodeType == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Prepare to parse colors
|
||||
Pattern rgbPattern = Pattern.compile("^rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)$");
|
||||
|
||||
// Optional. Background color of the pass, specified as an CSS-style RGB triple. For example, rgb(23, 187, 82).
|
||||
Integer headerColor = null;
|
||||
Matcher headerColorMatcher = rgbPattern.matcher(json.getString("backgroundColor"));
|
||||
if(headerColorMatcher.find())
|
||||
{
|
||||
headerColor = Color.rgb(
|
||||
Integer.parseInt(headerColorMatcher.group(1)),
|
||||
Integer.parseInt(headerColorMatcher.group(2)),
|
||||
Integer.parseInt(headerColorMatcher.group(3)));
|
||||
}
|
||||
if(headerColor == null)
|
||||
{
|
||||
// Maybe they violate the spec, let's parse it in a format Android understands
|
||||
// Necessary for at least Eurowings
|
||||
try
|
||||
{
|
||||
headerColor = Color.parseColor(json.getString("backgroundColor"));
|
||||
}
|
||||
catch (IllegalArgumentException ex) {}
|
||||
}
|
||||
|
||||
|
||||
// Optional. Color of the label text, specified as a CSS-style RGB triple. For example, rgb(255, 255, 255).
|
||||
Integer headerTextColor = null;
|
||||
Matcher headerTextColorMatcher = rgbPattern.matcher(json.getString("labelColor"));
|
||||
if(headerTextColorMatcher.find())
|
||||
{
|
||||
headerTextColor = Color.rgb(
|
||||
Integer.parseInt(headerTextColorMatcher.group(1)),
|
||||
Integer.parseInt(headerTextColorMatcher.group(2)),
|
||||
Integer.parseInt(headerTextColorMatcher.group(3)));
|
||||
}
|
||||
if(headerTextColor == null)
|
||||
{
|
||||
// Maybe they violate the spec, let's parse it in a format Android understands
|
||||
// Necessary for at least Eurowings
|
||||
try
|
||||
{
|
||||
headerTextColor = Color.parseColor(json.getString("labelColor"));
|
||||
}
|
||||
catch (IllegalArgumentException ex) {}
|
||||
}
|
||||
|
||||
// https://developer.apple.com/library/archive/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/TopLevel.html#//apple_ref/doc/uid/TP40012026-CH2-SW6
|
||||
// There needs to be exactly one style key
|
||||
|
||||
String styleKey = null;
|
||||
ImmutableList<String> possibleStyleKeys = ImmutableList.<String>builder()
|
||||
.add("boardingPass")
|
||||
.add("coupon")
|
||||
.add("eventTicket")
|
||||
.add("generic")
|
||||
.add("storeCard")
|
||||
.build();
|
||||
for(int i = 0; i < possibleStyleKeys.size(); i++)
|
||||
{
|
||||
String possibleStyleKey = possibleStyleKeys.get(i);
|
||||
if(json.has(possibleStyleKey))
|
||||
{
|
||||
styleKey = possibleStyleKey;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(styleKey == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// https://developer.apple.com/library/archive/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/LowerLevel.html#//apple_ref/doc/uid/TP40012026-CH3-SW14
|
||||
ExtrasHelper extras = new ExtrasHelper();
|
||||
extras = appendData(extras, json, styleKey, "headerFields");
|
||||
extras = appendData(extras, json, styleKey, "primaryFields");
|
||||
extras = appendData(extras, json, styleKey, "secondaryFields");
|
||||
extras = appendData(extras, json, styleKey, "auxiliaryFields");
|
||||
extras = appendData(extras, json, styleKey, "backFields");
|
||||
|
||||
return new LoyaltyCard(-1, store, note, cardId, barcodeType, headerColor, headerTextColor, icon, extras);
|
||||
}
|
||||
}
|
||||
BIN
app/src/main/res/drawable-hdpi/ic_info_outline_white.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_info_outline_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 582 B |
BIN
app/src/main/res/drawable-mdpi/ic_info_outline_white.png
Normal file
BIN
app/src/main/res/drawable-mdpi/ic_info_outline_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 371 B |
BIN
app/src/main/res/drawable-xhdpi/ic_info_outline_white.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_info_outline_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 742 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_info_outline_white.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_info_outline_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@@ -12,4 +12,10 @@
|
||||
android:icon="@drawable/ic_share_white"
|
||||
android:title="@string/share"
|
||||
app:showAsAction="always"/>
|
||||
<item
|
||||
android:id="@+id/action_view_extras"
|
||||
android:icon="@drawable/ic_info_outline_white"
|
||||
android:title="@string/moreInfo"
|
||||
app:showAsAction="always"
|
||||
android:visible="false"/>
|
||||
</menu>
|
||||
@@ -20,6 +20,7 @@
|
||||
<string name="enterCard">Enter Card</string>
|
||||
<string name="editCard">Edit Card</string>
|
||||
<string name="edit">Edit</string>
|
||||
<string name="moreInfo">More Info</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="lockScreen">Block Rotation</string>
|
||||
@@ -42,6 +43,9 @@
|
||||
<string name="noStoreError">No Store entered</string>
|
||||
<string name="noCardIdError">No Card ID entered</string>
|
||||
<string name="noCardExistsError">Could not lookup loyalty card</string>
|
||||
<string name="failedSharingCard">Could not share card</string>
|
||||
<string name="failedShowingExtras">Could not show extra information: data not correctly formatted</string>
|
||||
<string name="failedSavingCard">Could not save card</string>
|
||||
<string name="failedParsingImportUriError">Could not parse the import URI</string>
|
||||
<string name="cardIdFormat">%1$s: %2$s</string>
|
||||
<string name="importExport">Import/Export</string>
|
||||
|
||||
@@ -2,12 +2,17 @@ package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -28,19 +33,24 @@ public class DatabaseTest
|
||||
|
||||
private static final Integer DEFAULT_HEADER_COLOR = Color.BLACK;
|
||||
private static final Integer DEFAULT_HEADER_TEXT_COLOR = Color.WHITE;
|
||||
private static Bitmap DEFAULT_ICON = BitmapFactory.decodeResource(Resources.getSystem(), R.mipmap.ic_launcher);
|
||||
private static ExtrasHelper DEFAULT_EXTRAS;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
public void setUp() throws JSONException
|
||||
{
|
||||
DEFAULT_EXTRAS = new ExtrasHelper();
|
||||
DEFAULT_EXTRAS.addLanguageValue("en", "key", "value");
|
||||
|
||||
Activity activity = Robolectric.setupActivity(MainActivity.class);
|
||||
db = new DBHelper(activity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRemoveOneGiftCard()
|
||||
public void addRemoveOneGiftCard() throws JSONException
|
||||
{
|
||||
assertEquals(0, db.getLoyaltyCardCount());
|
||||
long id = db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), DEFAULT_HEADER_COLOR, DEFAULT_HEADER_TEXT_COLOR);
|
||||
long id = db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), DEFAULT_HEADER_COLOR, DEFAULT_HEADER_TEXT_COLOR, DEFAULT_ICON, DEFAULT_EXTRAS);
|
||||
boolean result = (id != -1);
|
||||
assertTrue(result);
|
||||
assertEquals(1, db.getLoyaltyCardCount());
|
||||
@@ -59,14 +69,14 @@ public class DatabaseTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateGiftCard()
|
||||
public void updateGiftCard() throws JSONException
|
||||
{
|
||||
long id = db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), DEFAULT_HEADER_COLOR, DEFAULT_HEADER_TEXT_COLOR);
|
||||
long id = db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), DEFAULT_HEADER_COLOR, DEFAULT_HEADER_TEXT_COLOR, DEFAULT_ICON, DEFAULT_EXTRAS);
|
||||
boolean result = (id != -1);
|
||||
assertTrue(result);
|
||||
assertEquals(1, db.getLoyaltyCardCount());
|
||||
|
||||
result = db.updateLoyaltyCard(1, "store1", "note1", "cardId1", BarcodeFormat.AZTEC.toString(), DEFAULT_HEADER_COLOR, DEFAULT_HEADER_TEXT_COLOR);
|
||||
result = db.updateLoyaltyCard(1, "store1", "note1", "cardId1", BarcodeFormat.AZTEC.toString(), DEFAULT_HEADER_COLOR, DEFAULT_HEADER_TEXT_COLOR, DEFAULT_ICON, DEFAULT_EXTRAS);
|
||||
assertTrue(result);
|
||||
assertEquals(1, db.getLoyaltyCardCount());
|
||||
|
||||
@@ -76,23 +86,24 @@ public class DatabaseTest
|
||||
assertEquals("note1", loyaltyCard.note);
|
||||
assertEquals("cardId1", loyaltyCard.cardId);
|
||||
assertEquals(BarcodeFormat.AZTEC.toString(), loyaltyCard.barcodeType);
|
||||
assertEquals(DEFAULT_EXTRAS.toJSON().toString(), loyaltyCard.extras.toJSON().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateMissingGiftCard()
|
||||
public void updateMissingGiftCard() throws JSONException
|
||||
{
|
||||
assertEquals(0, db.getLoyaltyCardCount());
|
||||
|
||||
boolean result = db.updateLoyaltyCard(1, "store1", "note1", "cardId1",
|
||||
BarcodeFormat.UPC_A.toString(), DEFAULT_HEADER_COLOR, DEFAULT_HEADER_TEXT_COLOR);
|
||||
BarcodeFormat.UPC_A.toString(), DEFAULT_HEADER_COLOR, DEFAULT_HEADER_TEXT_COLOR, DEFAULT_ICON, DEFAULT_EXTRAS);
|
||||
assertEquals(false, result);
|
||||
assertEquals(0, db.getLoyaltyCardCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyGiftCardValues()
|
||||
public void emptyGiftCardValues() throws JSONException
|
||||
{
|
||||
long id = db.insertLoyaltyCard("", "", "", "", null, null);
|
||||
long id = db.insertLoyaltyCard("", "", "", "", null, null, null, new ExtrasHelper());
|
||||
boolean result = (id != -1);
|
||||
assertTrue(result);
|
||||
assertEquals(1, db.getLoyaltyCardCount());
|
||||
@@ -103,10 +114,11 @@ public class DatabaseTest
|
||||
assertEquals("", loyaltyCard.note);
|
||||
assertEquals("", loyaltyCard.cardId);
|
||||
assertEquals("", loyaltyCard.barcodeType);
|
||||
assertEquals("{}", loyaltyCard.extras.toJSON().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void giftCardsViaCursor()
|
||||
public void giftCardsViaCursor() throws JSONException
|
||||
{
|
||||
final int CARDS_TO_ADD = 10;
|
||||
|
||||
@@ -115,7 +127,7 @@ public class DatabaseTest
|
||||
for(int index = CARDS_TO_ADD-1; index >= 0; index--)
|
||||
{
|
||||
long id = db.insertLoyaltyCard("store" + index, "note" + index, "cardId" + index,
|
||||
BarcodeFormat.UPC_A.toString(), index, index*2);
|
||||
BarcodeFormat.UPC_A.toString(), index, index*2, DEFAULT_ICON, DEFAULT_EXTRAS);
|
||||
boolean result = (id != -1);
|
||||
assertTrue(result);
|
||||
}
|
||||
@@ -138,6 +150,7 @@ public class DatabaseTest
|
||||
assertEquals(BarcodeFormat.UPC_A.toString(), cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.BARCODE_TYPE)));
|
||||
assertEquals(index, cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.HEADER_COLOR)));
|
||||
assertEquals(index*2, cursor.getInt(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.HEADER_TEXT_COLOR)));
|
||||
assertEquals("{\"en\":{\"key\":\"value\"}}", cursor.getString(cursor.getColumnIndexOrThrow(DBHelper.LoyaltyCardDbIds.EXTRAS)));
|
||||
|
||||
cursor.moveToNext();
|
||||
}
|
||||
@@ -172,7 +185,7 @@ public class DatabaseTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void databaseUpgradeFromVersion1()
|
||||
public void databaseUpgradeFromVersion1() throws JSONException
|
||||
{
|
||||
SQLiteDatabase database = db.getWritableDatabase();
|
||||
|
||||
@@ -193,6 +206,7 @@ public class DatabaseTest
|
||||
assertEquals("", card.note);
|
||||
assertEquals(null, card.headerColor);
|
||||
assertEquals(null, card.headerTextColor);
|
||||
assertEquals("{}", card.extras.toJSON().toString());
|
||||
|
||||
database.close();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import android.os.Environment;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import org.apache.tools.ant.filters.StringInputStream;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -46,10 +48,14 @@ public class ImportExportTest
|
||||
|
||||
private final String BARCODE_DATA = "428311627547";
|
||||
private final String BARCODE_TYPE = BarcodeFormat.UPC_A.name();
|
||||
private ExtrasHelper EXTRAS;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
public void setUp() throws JSONException
|
||||
{
|
||||
EXTRAS = new ExtrasHelper();
|
||||
EXTRAS.addLanguageValue("en", "key", "value");
|
||||
|
||||
activity = Robolectric.setupActivity(MainActivity.class);
|
||||
db = new DBHelper(activity);
|
||||
nowMs = System.currentTimeMillis();
|
||||
@@ -64,14 +70,14 @@ public class ImportExportTest
|
||||
* an index in the store name.
|
||||
* @param cardsToAdd
|
||||
*/
|
||||
private void addLoyaltyCards(int cardsToAdd)
|
||||
private void addLoyaltyCards(int cardsToAdd) throws JSONException
|
||||
{
|
||||
// Add in reverse order to test sorting
|
||||
for(int index = cardsToAdd; index > 0; index--)
|
||||
{
|
||||
String storeName = String.format("store, \"%4d", index);
|
||||
String note = String.format("note, \"%4d", index);
|
||||
long id = db.insertLoyaltyCard(storeName, note, BARCODE_DATA, BARCODE_TYPE, index, index*2);
|
||||
long id = db.insertLoyaltyCard(storeName, note, BARCODE_DATA, BARCODE_TYPE, index, index*2, null, EXTRAS);
|
||||
boolean result = (id != -1);
|
||||
assertTrue(result);
|
||||
}
|
||||
@@ -84,7 +90,7 @@ public class ImportExportTest
|
||||
* specified in addLoyaltyCards(), and are in sequential order
|
||||
* where the smallest card's index is 1
|
||||
*/
|
||||
private void checkLoyaltyCards()
|
||||
private void checkLoyaltyCards() throws JSONException
|
||||
{
|
||||
Cursor cursor = db.getLoyaltyCardCursor();
|
||||
int index = 1;
|
||||
@@ -102,6 +108,7 @@ public class ImportExportTest
|
||||
assertEquals(BARCODE_TYPE, card.barcodeType);
|
||||
assertEquals(Integer.valueOf(index), card.headerColor);
|
||||
assertEquals(Integer.valueOf(index*2), card.headerTextColor);
|
||||
assertEquals("{\"en\":{\"key\":\"value\"}}", card.extras.toJSON().toString());
|
||||
|
||||
index++;
|
||||
}
|
||||
@@ -121,7 +128,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleCardsExportImport() throws IOException
|
||||
public void multipleCardsExportImport() throws IOException, JSONException
|
||||
{
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
@@ -156,7 +163,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void importExistingCardsNotReplace() throws IOException
|
||||
public void importExistingCardsNotReplace() throws IOException, JSONException
|
||||
{
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
@@ -189,7 +196,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void corruptedImportNothingSaved() throws IOException
|
||||
public void corruptedImportNothingSaved() throws IOException, JSONException
|
||||
{
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
@@ -234,7 +241,7 @@ public class ImportExportTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useImportExportTask() throws FileNotFoundException
|
||||
public void useImportExportTask() throws FileNotFoundException, JSONException
|
||||
{
|
||||
final int NUM_CARDS = 10;
|
||||
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.io.InvalidObjectException;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static protect.card_locker.DBHelper.LoyaltyCardDbIds;
|
||||
@@ -31,13 +39,18 @@ public class ImportURITest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureNoDataLoss() throws InvalidObjectException
|
||||
public void ensureNoDataLoss() throws InvalidObjectException, JSONException
|
||||
{
|
||||
// Generate card
|
||||
db.insertLoyaltyCard("store", "note", BarcodeFormat.UPC_A.toString(), LoyaltyCardDbIds.BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
Bitmap icon = BitmapFactory.decodeResource(Resources.getSystem(), R.mipmap.ic_launcher);
|
||||
assertNotNull(icon);
|
||||
ExtrasHelper extrasHelper = new ExtrasHelper();
|
||||
extrasHelper.addLanguageValue("en", "key", "value");
|
||||
db.insertLoyaltyCard("store", "note", BarcodeFormat.UPC_A.toString(), LoyaltyCardDbIds.BARCODE_TYPE, Color.BLACK, Color.WHITE, icon, extrasHelper);
|
||||
|
||||
// Get card
|
||||
LoyaltyCard card = db.getLoyaltyCard(1);
|
||||
assertNotNull(card.icon);
|
||||
|
||||
// Card to URI
|
||||
Uri cardUri = importURIHelper.toUri(card);
|
||||
@@ -52,13 +65,23 @@ public class ImportURITest {
|
||||
assertEquals(card.headerTextColor, parsedCard.headerTextColor);
|
||||
assertEquals(card.note, parsedCard.note);
|
||||
assertEquals(card.store, parsedCard.store);
|
||||
assertEquals(card.icon.getWidth(), parsedCard.icon.getWidth());
|
||||
assertEquals(card.icon.getHeight(), parsedCard.icon.getHeight());
|
||||
for(int i = 0; i < card.icon.getWidth(); i++)
|
||||
{
|
||||
for(int j = 0; j < card.icon.getHeight(); j++)
|
||||
{
|
||||
assertEquals(card.icon.getPixel(i, j), parsedCard.icon.getPixel(i, j));
|
||||
}
|
||||
}
|
||||
assertEquals(card.extras.toJSON().toString(), parsedCard.extras.toJSON().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ensureNoCrashOnMissingHeaderFields() throws InvalidObjectException
|
||||
public void ensureNoCrashOnMissingHeaderFields() throws InvalidObjectException, JSONException
|
||||
{
|
||||
// Generate card
|
||||
db.insertLoyaltyCard("store", "note", BarcodeFormat.UPC_A.toString(), LoyaltyCardDbIds.BARCODE_TYPE, null, null);
|
||||
db.insertLoyaltyCard("store", "note", BarcodeFormat.UPC_A.toString(), LoyaltyCardDbIds.BARCODE_TYPE, null, null, null, new ExtrasHelper());
|
||||
|
||||
// Get card
|
||||
LoyaltyCard card = db.getLoyaltyCard(1);
|
||||
|
||||
@@ -10,6 +10,8 @@ import android.widget.TextView;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -81,9 +83,9 @@ public class LoyaltyCardCursorAdapterTest
|
||||
|
||||
|
||||
@Test
|
||||
public void TestCursorAdapterEmptyNote()
|
||||
public void TestCursorAdapterEmptyNote() throws JSONException
|
||||
{
|
||||
db.insertLoyaltyCard("store", "", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
LoyaltyCard card = db.getLoyaltyCard(1);
|
||||
|
||||
Cursor cursor = db.getLoyaltyCardCursor();
|
||||
@@ -95,9 +97,9 @@ public class LoyaltyCardCursorAdapterTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestCursorAdapterWithNote()
|
||||
public void TestCursorAdapterWithNote() throws JSONException
|
||||
{
|
||||
db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
LoyaltyCard card = db.getLoyaltyCard(1);
|
||||
|
||||
Cursor cursor = db.getLoyaltyCardCursor();
|
||||
@@ -109,9 +111,9 @@ public class LoyaltyCardCursorAdapterTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestCursorAdapterFontSizes()
|
||||
public void TestCursorAdapterFontSizes() throws JSONException
|
||||
{
|
||||
db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
LoyaltyCard card = db.getLoyaltyCard(1);
|
||||
|
||||
Cursor cursor = db.getLoyaltyCardCursor();
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.widget.TextView;
|
||||
import androidx.core.widget.TextViewCompat;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.client.android.Intents;
|
||||
import org.json.JSONException;
|
||||
import java.io.IOException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -394,13 +395,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWithLoyaltyCardEditModeCheckDisplay() throws IOException
|
||||
public void startWithLoyaltyCardEditModeCheckDisplay() throws IOException, JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(true);
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -410,13 +411,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWithLoyaltyCardViewModeCheckDisplay() throws IOException
|
||||
public void startWithLoyaltyCardViewModeCheckDisplay() throws IOException, JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(false);
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -426,13 +427,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWithLoyaltyCardWithBarcodeUpdateBarcode() throws IOException
|
||||
public void startWithLoyaltyCardWithBarcodeUpdateBarcode() throws IOException, JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(true);
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
|
||||
db.insertLoyaltyCard("store", "note", EAN_BARCODE_DATA, EAN_BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", EAN_BARCODE_DATA, EAN_BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -447,13 +448,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWithLoyaltyCardWithReceiptUpdateReceiptCancel() throws IOException
|
||||
public void startWithLoyaltyCardWithReceiptUpdateReceiptCancel() throws IOException, JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(true);
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
|
||||
db.insertLoyaltyCard("store", "note", EAN_BARCODE_DATA, EAN_BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", EAN_BARCODE_DATA, EAN_BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -473,13 +474,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkMenu() throws IOException
|
||||
public void checkMenu() throws IOException, JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(false);
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -488,11 +489,12 @@ public class LoyaltyCardViewActivityTest
|
||||
final Menu menu = shadowOf(activity).getOptionsMenu();
|
||||
assertTrue(menu != null);
|
||||
|
||||
// The share and settings button should be present
|
||||
assertEquals(menu.size(), 2);
|
||||
// The rotation,share and info button should be present
|
||||
assertEquals(menu.size(), 3);
|
||||
|
||||
assertEquals("Block Rotation", menu.findItem(R.id.action_lock_unlock).getTitle().toString());
|
||||
assertEquals("Share", menu.findItem(R.id.action_share).getTitle().toString());
|
||||
assertEquals("More Info", menu.findItem(R.id.action_view_extras).getTitle().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -516,13 +518,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWithoutParametersViewBack()
|
||||
public void startWithoutParametersViewBack() throws JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(false);
|
||||
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -534,13 +536,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startWithoutColors()
|
||||
public void startWithoutColors() throws JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(false);
|
||||
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, null, null);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, null, null, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -552,13 +554,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startLoyaltyCardWithoutColorsSave() throws IOException
|
||||
public void startLoyaltyCardWithoutColorsSave() throws IOException, JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(true);
|
||||
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, null, null);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, null, null, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -569,13 +571,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startLoyaltyCardWithExplicitNoBarcodeSave() throws IOException
|
||||
public void startLoyaltyCardWithExplicitNoBarcodeSave() throws IOException, JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(true);
|
||||
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, "", Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, "", Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -586,13 +588,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeBarcodeFromLoyaltyCard() throws IOException
|
||||
public void removeBarcodeFromLoyaltyCard() throws IOException, JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(true);
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -613,13 +615,13 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startCheckFontSizes()
|
||||
public void startCheckFontSizes() throws JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(false);
|
||||
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
final int STORE_FONT_SIZE = 50;
|
||||
final int CARD_FONT_SIZE = 40;
|
||||
@@ -653,7 +655,7 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkScreenOrientationLockSetting()
|
||||
public void checkScreenOrientationLockSetting() throws JSONException
|
||||
{
|
||||
for(boolean locked : new boolean[] {false, true})
|
||||
{
|
||||
@@ -661,7 +663,7 @@ public class LoyaltyCardViewActivityTest
|
||||
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
settings.edit()
|
||||
@@ -690,13 +692,54 @@ public class LoyaltyCardViewActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkBarcodeFullscreenWorkflow()
|
||||
public void checkMoreInfoNoExtras() throws JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(false);
|
||||
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.resume();
|
||||
activityController.visible();
|
||||
|
||||
assertEquals(false, activity.isFinishing());
|
||||
|
||||
MenuItem item = shadowOf(activity).getOptionsMenu().findItem(R.id.action_view_extras);
|
||||
assertEquals(false, item.isVisible());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkMoreInfoExtras() throws JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(false);
|
||||
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
ExtrasHelper extrasHelper = new ExtrasHelper();
|
||||
extrasHelper.addLanguageValue("en", "key", "value");
|
||||
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, extrasHelper);
|
||||
|
||||
activityController.start();
|
||||
activityController.resume();
|
||||
activityController.visible();
|
||||
|
||||
assertEquals(false, activity.isFinishing());
|
||||
|
||||
MenuItem item = shadowOf(activity).getOptionsMenu().findItem(R.id.action_view_extras);
|
||||
assertEquals(true, item.isVisible());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkBarcodeFullscreenWorkflow() throws JSONException
|
||||
{
|
||||
ActivityController activityController = createActivityWithLoyaltyCard(false);
|
||||
|
||||
Activity activity = (Activity)activityController.get();
|
||||
DBHelper db = new DBHelper(activity);
|
||||
db.insertLoyaltyCard("store", "note", BARCODE_DATA, BARCODE_TYPE, Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.start();
|
||||
activityController.visible();
|
||||
@@ -755,7 +798,7 @@ public class LoyaltyCardViewActivityTest
|
||||
@Test
|
||||
public void importCard()
|
||||
{
|
||||
Uri importUri = Uri.parse("https://thelastproject.github.io/Catima/share?store=Example%20Store¬e=&cardid=123456&barcodetype=AZTEC&headercolor=-416706&headertextcolor=-1");
|
||||
Uri importUri = Uri.parse("https://thelastproject.github.io/Catima/share?store=Example%20Store¬e=&cardid=123456&barcodetype=AZTEC&headercolor=-416706&headertextcolor=-1&icon=&extras={}");
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(importUri);
|
||||
@@ -776,7 +819,7 @@ public class LoyaltyCardViewActivityTest
|
||||
@Test
|
||||
public void importCardOldURL()
|
||||
{
|
||||
Uri importUri = Uri.parse("https://brarcher.github.io/loyalty-card-locker/share?store=Example%20Store¬e=&cardid=123456&barcodetype=AZTEC&headercolor=-416706&headertextcolor=-1");
|
||||
Uri importUri = Uri.parse("https://thelastproject.github.io/Catima/share?store=Example%20Store¬e=&cardid=123456&barcodetype=AZTEC&headercolor=-416706&headertextcolor=-1");
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.setData(importUri);
|
||||
|
||||
@@ -8,7 +8,6 @@ import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
@@ -16,6 +15,7 @@ import android.widget.TextView;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -83,7 +83,7 @@ public class MainActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addOneLoyaltyCard()
|
||||
public void addOneLoyaltyCard() throws JSONException
|
||||
{
|
||||
ActivityController activityController = Robolectric.buildActivity(MainActivity.class).create();
|
||||
|
||||
@@ -98,7 +98,7 @@ public class MainActivityTest
|
||||
assertEquals(0, list.getCount());
|
||||
|
||||
DBHelper db = new DBHelper(mainActivity);
|
||||
db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("store", "note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
assertEquals(View.VISIBLE, helpText.getVisibility());
|
||||
assertEquals(View.GONE, noMatchingCardsText.getVisibility());
|
||||
@@ -117,7 +117,7 @@ public class MainActivityTest
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFiltering()
|
||||
public void testFiltering() throws JSONException
|
||||
{
|
||||
ActivityController activityController = Robolectric.buildActivity(MainActivity.class).create();
|
||||
|
||||
@@ -130,8 +130,8 @@ public class MainActivityTest
|
||||
ListView list = mainActivity.findViewById(R.id.list);
|
||||
|
||||
DBHelper db = new DBHelper(mainActivity);
|
||||
db.insertLoyaltyCard("The First Store", "Initial note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("The Second Store", "Secondary note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE);
|
||||
db.insertLoyaltyCard("The First Store", "Initial note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
db.insertLoyaltyCard("The Second Store", "Secondary note", "cardId", BarcodeFormat.UPC_A.toString(), Color.BLACK, Color.WHITE, null, new ExtrasHelper());
|
||||
|
||||
activityController.pause();
|
||||
activityController.resume();
|
||||
|
||||
384
app/src/test/java/protect/card_locker/PkpassTest.java
Normal file
384
app/src/test/java/protect/card_locker/PkpassTest.java
Normal file
@@ -0,0 +1,384 @@
|
||||
package protect.card_locker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowContentResolver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(sdk = 23)
|
||||
public class PkpassTest {
|
||||
private PkpassImporter pkpassImporter;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
Activity activity = Robolectric.setupActivity(MainActivity.class);
|
||||
pkpassImporter = new PkpassImporter(activity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseGenericExample() throws IOException, JSONException
|
||||
{
|
||||
// https://github.com/keefmoon/Passbook-Example-Code/blob/master/Pass-Example-Generic/Pass-Example-Generic.pkpass
|
||||
InputStream inputStream = getClass().getResourceAsStream("Pass-Example-Generic.pkpass");
|
||||
|
||||
LoyaltyCard card = pkpassImporter.fromInputStream(inputStream);
|
||||
|
||||
// Compare everything
|
||||
assertEquals(BarcodeFormat.QR_CODE.name(), card.barcodeType);
|
||||
assertEquals("0000001", card.cardId);
|
||||
assertEquals("Staff Pass for Employee Number 001", card.note);
|
||||
assertEquals("Passbook Example Company", card.store);
|
||||
assertEquals(String.valueOf(Color.rgb(90, 90, 90)), card.headerColor.toString());
|
||||
assertEquals(String.valueOf(Color.rgb(255, 255, 255)), card.headerTextColor.toString());
|
||||
|
||||
// Check if all the extras got parsed correctly
|
||||
ExtrasHelper extras = card.extras;
|
||||
// Expecting no English entries
|
||||
assertEquals(0, extras.getAllValues("en").keySet().size());
|
||||
// Expecting 7 untranslated entries
|
||||
assertEquals(7, extras.getAllValues("").keySet().size());
|
||||
// Untranslated and English + untranslated fallback should return the same
|
||||
assertEquals(extras.getAllValues(""), extras.getAllValues(new String[]{"en", ""}));
|
||||
|
||||
// Check all 7 values
|
||||
Iterator<Map.Entry<String, String>> extrasKeys = extras.getAllValues("").entrySet().iterator();
|
||||
|
||||
// 1
|
||||
Map.Entry<String, String> entry = extrasKeys.next();
|
||||
assertEquals("staffNumber", entry.getKey());
|
||||
assertEquals("Staff Number: 001", entry.getValue());
|
||||
|
||||
// 2
|
||||
entry = extrasKeys.next();
|
||||
assertEquals("staffName", entry.getKey());
|
||||
assertEquals("Name: Peter Brooke", entry.getValue());
|
||||
|
||||
// 3
|
||||
entry = extrasKeys.next();
|
||||
assertEquals("telephoneExt", entry.getKey());
|
||||
assertEquals("Extension: 9779", entry.getValue());
|
||||
|
||||
// 4
|
||||
entry = extrasKeys.next();
|
||||
assertEquals("jobTitle", entry.getKey());
|
||||
assertEquals("Job Title: Chief Pass Creator", entry.getValue());
|
||||
|
||||
// 5
|
||||
entry = extrasKeys.next();
|
||||
assertEquals("expiryDate", entry.getKey());
|
||||
assertEquals("Expiry Date: 2013-12-31T00:00-23:59", entry.getValue());
|
||||
|
||||
// 6
|
||||
entry = extrasKeys.next();
|
||||
assertEquals("managersName", entry.getKey());
|
||||
assertEquals("Manager's Name: Paul Bailey", entry.getValue());
|
||||
|
||||
// 7
|
||||
entry = extrasKeys.next();
|
||||
assertEquals("managersExt", entry.getKey());
|
||||
assertEquals("Manager's Extension: 9673", entry.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseEurowingsTicket() throws IOException, JSONException
|
||||
{
|
||||
// https://github.com/brarcher/loyalty-card-locker/issues/309#issuecomment-563465333
|
||||
InputStream inputStream = getClass().getResourceAsStream("Eurowings.pkpass");
|
||||
|
||||
LoyaltyCard card = pkpassImporter.fromInputStream(inputStream);
|
||||
|
||||
// Compare everything
|
||||
assertEquals(BarcodeFormat.AZTEC.name(), card.barcodeType);
|
||||
assertEquals("M1DOE/JOHN JBZPPP CGNDBVEW 0954 251A016E0073 148>5181W 9250BEW 00000000000002A0000000000000 0 N", card.cardId);
|
||||
assertEquals("Eurowings Boarding Pass", card.note);
|
||||
assertEquals("EUROWINGS", card.store);
|
||||
|
||||
// Violates the spec, but we want to support it anyway...
|
||||
assertEquals(String.valueOf(Color.parseColor("#FFFFFF")), card.headerColor.toString());
|
||||
assertEquals(String.valueOf(Color.parseColor("#AA0061")), card.headerTextColor.toString());
|
||||
|
||||
// Check if all the extras got parsed correctly
|
||||
ExtrasHelper extras = card.extras;
|
||||
|
||||
// Expect 18 English values
|
||||
assertEquals(18, extras.getAllValues("en").size());
|
||||
|
||||
// Expect 18 German values
|
||||
assertEquals(18, extras.getAllValues("de").size());
|
||||
|
||||
// Expect 18 untranslated values
|
||||
assertEquals(18, extras.getAllValues("").size());
|
||||
|
||||
// Expect no French values
|
||||
assertEquals(0, extras.getAllValues("fr").size());
|
||||
|
||||
// Check all 18 English, German and untranslated values
|
||||
Iterator<Map.Entry<String, String>> englishKeys = extras.getAllValues("en").entrySet().iterator();
|
||||
Iterator<Map.Entry<String, String>> germanKeys = extras.getAllValues("de").entrySet().iterator();
|
||||
Iterator<Map.Entry<String, String>> untranslatedKeys = extras.getAllValues("").entrySet().iterator();
|
||||
|
||||
// 1
|
||||
Map.Entry<String, String> englishEntry = englishKeys.next();
|
||||
Map.Entry<String, String> germanEntry = germanKeys.next();
|
||||
Map.Entry<String, String> untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("gate", englishEntry.getKey());
|
||||
assertEquals("gate", germanEntry.getKey());
|
||||
assertEquals("gate", untranslatedEntry.getKey());
|
||||
assertEquals("Gate: B61", englishEntry.getValue());
|
||||
assertEquals("Gate: B61", germanEntry.getValue());
|
||||
assertEquals("gate_str: B61", untranslatedEntry.getValue());
|
||||
|
||||
// 2
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("seat", englishEntry.getKey());
|
||||
assertEquals("seat", germanEntry.getKey());
|
||||
assertEquals("seat", untranslatedEntry.getKey());
|
||||
assertEquals("Seat: 16E", englishEntry.getValue());
|
||||
assertEquals("Sitz: 16E", germanEntry.getValue());
|
||||
assertEquals("seat_str: 16E", untranslatedEntry.getValue());
|
||||
|
||||
// 3
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("origin", englishEntry.getKey());
|
||||
assertEquals("origin", germanEntry.getKey());
|
||||
assertEquals("origin", untranslatedEntry.getKey());
|
||||
assertEquals("Cologne-Bonn: CGN", englishEntry.getValue());
|
||||
assertEquals("Cologne-Bonn: CGN", germanEntry.getValue());
|
||||
assertEquals("Cologne-Bonn: CGN", untranslatedEntry.getValue());
|
||||
|
||||
// 4
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("destination", englishEntry.getKey());
|
||||
assertEquals("destination", germanEntry.getKey());
|
||||
assertEquals("destination", untranslatedEntry.getKey());
|
||||
assertEquals("Dubrovnik: DBV", englishEntry.getValue());
|
||||
assertEquals("Dubrovnik: DBV", germanEntry.getValue());
|
||||
assertEquals("Dubrovnik: DBV", untranslatedEntry.getValue());
|
||||
|
||||
// 5
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("name", englishEntry.getKey());
|
||||
assertEquals("name", germanEntry.getKey());
|
||||
assertEquals("name", untranslatedEntry.getKey());
|
||||
assertEquals("Name: John Doe", englishEntry.getValue());
|
||||
assertEquals("Name: John Doe", germanEntry.getValue());
|
||||
assertEquals("name_str: John Doe", untranslatedEntry.getValue());
|
||||
|
||||
// 6
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("status", englishEntry.getKey());
|
||||
assertEquals("status", germanEntry.getKey());
|
||||
assertEquals("status", untranslatedEntry.getKey());
|
||||
assertEquals("Status: -", englishEntry.getValue());
|
||||
assertEquals("Status: -", germanEntry.getValue());
|
||||
assertEquals("status_str: -", untranslatedEntry.getValue());
|
||||
|
||||
// 7
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("boardinggroup", englishEntry.getKey());
|
||||
assertEquals("boardinggroup", germanEntry.getKey());
|
||||
assertEquals("boardinggroup", untranslatedEntry.getKey());
|
||||
assertEquals("Group: GROUP 1", englishEntry.getValue());
|
||||
assertEquals("Gruppe: GROUP 1", germanEntry.getValue());
|
||||
assertEquals("boardinggroup_str: GROUP 1", untranslatedEntry.getValue());
|
||||
|
||||
// 8
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("tarif", englishEntry.getKey());
|
||||
assertEquals("tarif", germanEntry.getKey());
|
||||
assertEquals("tarif", untranslatedEntry.getKey());
|
||||
assertEquals("Fare: SMART", englishEntry.getValue());
|
||||
assertEquals("Tarif: SMART", germanEntry.getValue());
|
||||
assertEquals("fare_str: SMART", untranslatedEntry.getValue());
|
||||
|
||||
// 9
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("flightNumber", englishEntry.getKey());
|
||||
assertEquals("flightNumber", germanEntry.getKey());
|
||||
assertEquals("flightNumber", untranslatedEntry.getKey());
|
||||
assertEquals("Flight: EW 954", englishEntry.getValue());
|
||||
assertEquals("Flug: EW 954", germanEntry.getValue());
|
||||
assertEquals("flight_str: EW 954", untranslatedEntry.getValue());
|
||||
|
||||
// 10
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("departureDate", englishEntry.getKey());
|
||||
assertEquals("departureDate", germanEntry.getKey());
|
||||
assertEquals("departureDate", untranslatedEntry.getKey());
|
||||
assertEquals("Date: 08/09/2019", englishEntry.getValue());
|
||||
assertEquals("Datum: 08/09/2019", germanEntry.getValue());
|
||||
assertEquals("date_str: 08/09/2019", untranslatedEntry.getValue());
|
||||
|
||||
// 11
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("boarding", englishEntry.getKey());
|
||||
assertEquals("boarding", germanEntry.getKey());
|
||||
assertEquals("boarding", untranslatedEntry.getKey());
|
||||
assertEquals("Boarding: 05:00", englishEntry.getValue());
|
||||
assertEquals("Boarding: 05:00", germanEntry.getValue());
|
||||
assertEquals("boarding_str: 05:00", untranslatedEntry.getValue());
|
||||
|
||||
// 12
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("closure", englishEntry.getKey());
|
||||
assertEquals("closure", germanEntry.getKey());
|
||||
assertEquals("closure", untranslatedEntry.getKey());
|
||||
assertEquals("Gate closure: 05:15", englishEntry.getValue());
|
||||
assertEquals("Gate Schließt: 05:15", germanEntry.getValue());
|
||||
assertEquals("closure_str: 05:15", untranslatedEntry.getValue());
|
||||
|
||||
// 13
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("info", englishEntry.getKey());
|
||||
assertEquals("info", germanEntry.getKey());
|
||||
assertEquals("info", untranslatedEntry.getKey());
|
||||
assertEquals("Eurowings wishes you a pleasant flight .\r\n" +
|
||||
"\r\n" +
|
||||
"We kindly ask you to be present at your departure gate on time.", englishEntry.getValue());
|
||||
assertEquals("Eurowings wünscht Ihnen einen angenehmen Flug.\r\n" +
|
||||
"\r\n" +
|
||||
"Wir bitten Sie, sich zur angegeben Boarding Zeit am Gate einzufinden.", germanEntry.getValue());
|
||||
assertEquals("info_content_str", untranslatedEntry.getValue());
|
||||
|
||||
// 14
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("recordlocator", englishEntry.getKey());
|
||||
assertEquals("recordlocator", germanEntry.getKey());
|
||||
assertEquals("recordlocator", untranslatedEntry.getKey());
|
||||
assertEquals("Booking code: JBZPPP", englishEntry.getValue());
|
||||
assertEquals("Buchungscode: JBZPPP", germanEntry.getValue());
|
||||
assertEquals("recordlocator_str: JBZPPP", untranslatedEntry.getValue());
|
||||
|
||||
// 15
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("sequence", englishEntry.getKey());
|
||||
assertEquals("sequence", germanEntry.getKey());
|
||||
assertEquals("sequence", untranslatedEntry.getKey());
|
||||
assertEquals("Sequence: 73", englishEntry.getValue());
|
||||
assertEquals("Sequenz: 73", germanEntry.getValue());
|
||||
assertEquals("sequence_str: 73", untranslatedEntry.getValue());
|
||||
|
||||
// 16
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("notice", englishEntry.getKey());
|
||||
assertEquals("notice", germanEntry.getKey());
|
||||
assertEquals("notice", untranslatedEntry.getKey());
|
||||
assertEquals("Notice: Please note that although your flight may be delayed, you will still need to check in and go to your departure gate on time as scheduled.\r\n" +
|
||||
"\r\n" +
|
||||
"Carry on one item of hand luggage (8 kg, 55 x 40 x 23 cm) for free.", englishEntry.getValue());
|
||||
assertEquals("Hinweis: Bitte beachten Sie, dass obwohl Ihr Flug verspätet sein mag, Sie dennoch wie geplant pünktlich am Check-in und am Abfluggate erscheinen müssen.\r\n" +
|
||||
"\r\n" +
|
||||
"Kostenlose Mitnahme eines Handgepäckstücks (8 Kg, 55 x 40 x 23cm).", germanEntry.getValue());
|
||||
assertEquals("notice_str: notice_content_str", untranslatedEntry.getValue());
|
||||
|
||||
// 17
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("baggage", englishEntry.getKey());
|
||||
assertEquals("baggage", germanEntry.getKey());
|
||||
assertEquals("baggage", untranslatedEntry.getKey());
|
||||
assertEquals("Carrying liquids in hand luggage: In addition to other restrictions on hand luggage, there are still restrictions on liquids and gels brought by the passenger or purchased before the security control on all departures within the European Union, as well as to many other countries (including Switzerland, Russia, Iceland, Croatia, Israel, Egypt, Morocco, Tunisia and Norway):\r\n" +
|
||||
"\r\n" +
|
||||
"- All liquids (such as toiletries and cosmetics, gels, pastes, creams, lotions, mixtures of liquids and solids, perfumes, pressurised containers, cans, water bottles etc) as well as wax and gel-like substances may only be carried on board in amounts less than 100ml or 100g.\r\n" +
|
||||
"\r\n" +
|
||||
"- These liquids or substances must be packed in closed containers in a transparent, re-sealable plastic bag (max. contents 1 kg).\r\n" +
|
||||
"\r\n" +
|
||||
"- It is the passenger’s responsibility to purchase this bag before departure. They are available in many supermarkets, e.g. as freezer bags. It is currently not possible for passengers to obtain or purchase the required bags from Eurowings check-in.\r\n" +
|
||||
"\r\n" +
|
||||
"- Prescription medicines and baby food may still be carried in hand baggage. The passenger must prove that such medicines and/or baby food are needed during the flight.\r\n" +
|
||||
"\r\n" +
|
||||
"- Products and bags which do not meet the requirements or are only sealed with a rubber band or similar will unfortunately have to be surrendered by passengers\r\n" +
|
||||
"\r\n" +
|
||||
"In order to pass through the airport as quickly as possible, you are strongly advised to pack any liquids or gels which are not essential for your journey on board the aircraft in your checked baggage if possible.\r\n" +
|
||||
"\r\n" +
|
||||
"As a matter of course, liquids from the Travel Value / Duty Free shops which have been purchased after you have passed through security are still allowed on board.\r\n" +
|
||||
"\r\n" +
|
||||
"Eurowings shall not be liable for any items which passengers are prohibited from carrying in their hand baggage for security reasons and are required to surrender at the security checkpoint.", englishEntry.getValue());
|
||||
assertEquals("Mitnahme von Flüssigkeiten im Handgepäck: Neben den sonstigen Beschränkungen für das Handgepäck ist für alle Abflüge innerhalb der Europäischen Union sowie vielen weiteren Ländern (u.a. Schweiz, Russland, Island, Kroatien, Israel, Ägypten, Marokko, Tunesien, Norwegen) die Mitnahme von vor der Fluggastkontrolle erworbenen bzw. mitgebrachten Flüssigkeiten und Gels nur noch eingeschränkt erlaubt:\r\n" +
|
||||
"\r\n" +
|
||||
"- Sämtliche Flüssigkeiten (wie Kosmetik- und Toilettenartikel, Gels, Pasten, Cremes, Lotionen, Gemische aus flüssigen und festen Stoffen, Parfums, Behälter unter Druck, Dosen, Wasserflaschen etc.) sowie wachs- oder gelartige Stoffe dürfen nur noch in Behältnissen bis zu 100 ml bzw. 100 g mit an Bord genommen werden.\r\n" +
|
||||
"\r\n" +
|
||||
"- Diese Flüssigkeiten bzw. Stoffe müssen in einem transparenten, wiederverschließbaren Plastikbeutel (max. 1 kg Inhalt) vollständig geschlossen, verpackt sein.\r\n" +
|
||||
"\r\n" +
|
||||
"- Diese Beutel müssen Fluggäste selbst vor dem Abflug erwerben. Sie sind in vielen Supermärkten z. B. als Gefrierbeutel erhältlich. Es besteht zurzeit keine Möglichkeit, entsprechende Plastikbeutel am Eurowings Check-In zu erwerben bzw. auszugeben.\r\n" +
|
||||
"\r\n" +
|
||||
"- Verschreibungspflichtige Medikamente sowie Babynahrung dürfen weiterhin im Handgepäck transportiert werden. Der Fluggast muss nachweisen, dass die Medikamente und Babynahrung während des Fluges benötigt werden.\r\n" +
|
||||
"\r\n" +
|
||||
"- Produkte und Beutel, die nicht den Maßgaben entsprechen oder die nur mit Gummiband oder ähnlichem verschlossen sind, müssen leider abgegeben werden.\r\n" +
|
||||
"\r\n" +
|
||||
"Flüssigkeiten und Gels, die Sie nicht zwingend während Ihres Aufenthalts an Bord benötigen, sollten zur raschen Fluggastabfertigung nach Möglichkeit im aufzugebenden Gepäck untergebracht werden.\r\n" +
|
||||
"\r\n" +
|
||||
"Selbstverständlich ist die Mitnahme von allen Flüssigkeiten/Gels/Getränken aus Travel-Value oder Duty Free-Shops, die nach der Fluggastkontrolle erworben werden, weiterhin erlaubt.\r\n" +
|
||||
"\r\n" +
|
||||
"Eurowings übernimmt keine Haftung für Gegenstände, die der Fluggast nicht im Handgepäck mitführen darf und deshalb aus Sicherheitsgründen an der Fluggastkontrolle abgeben muss.", germanEntry.getValue());
|
||||
assertEquals("baggage_str: baggage_content_str", untranslatedEntry.getValue());
|
||||
|
||||
// 18
|
||||
englishEntry = englishKeys.next();
|
||||
germanEntry = germanKeys.next();
|
||||
untranslatedEntry = untranslatedKeys.next();
|
||||
assertEquals("contact", englishEntry.getKey());
|
||||
assertEquals("contact", germanEntry.getKey());
|
||||
assertEquals("contact", untranslatedEntry.getKey());
|
||||
assertEquals("Contact: https://mobile.eurowings.com/booking/StaticContactInfo.aspx?culture=en-GB&back=home", englishEntry.getValue());
|
||||
assertEquals("Kontakt: Sie erreichen das deutsche Call Center unter der Telefonnummer\r\n" +
|
||||
"\r\n" +
|
||||
"0180 6 320 320 ( 0:00 Uhr - 24:00 Uhr )\r\n" +
|
||||
"\r\n" +
|
||||
"(0,20 € pro Anruf aus dem Festnetz der Deutschen Telekom - Mobilfunk maximal 0,60 € pro Anruf).", germanEntry.getValue());
|
||||
assertEquals("contact_str: contact_content_str", untranslatedEntry.getValue());
|
||||
}
|
||||
}
|
||||
BIN
app/src/test/resources/protect/card_locker/Eurowings.pkpass
Normal file
BIN
app/src/test/resources/protect/card_locker/Eurowings.pkpass
Normal file
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user