Use the screenShot method from the rule
This commit is contained in:
parent
3b83081419
commit
67727e9159
8 changed files with 99 additions and 119 deletions
|
@ -3,7 +3,6 @@ package org.ligi.passandroid;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import com.squareup.spoon.Spoon;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -21,6 +20,11 @@ import static android.support.test.espresso.assertion.ViewAssertions.matches;
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.ligi.passandroid.model.pass.PassBarCodeFormat.AZTEC;
|
||||||
|
import static org.ligi.passandroid.model.pass.PassBarCodeFormat.CODE_128;
|
||||||
|
import static org.ligi.passandroid.model.pass.PassBarCodeFormat.CODE_39;
|
||||||
|
import static org.ligi.passandroid.model.pass.PassBarCodeFormat.PDF_417;
|
||||||
|
import static org.ligi.passandroid.model.pass.PassBarCodeFormat.QR_CODE;
|
||||||
|
|
||||||
public class TheFullscreenBarcodeActivity {
|
public class TheFullscreenBarcodeActivity {
|
||||||
|
|
||||||
|
@ -39,39 +43,39 @@ public class TheFullscreenBarcodeActivity {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPDF417BarcodeIsShown() {
|
public void testPDF417BarcodeIsShown() {
|
||||||
testWithBarcodeFormat(PassBarCodeFormat.PDF_417);
|
testWithBarcodeFormat(PDF_417);
|
||||||
|
|
||||||
Spoon.screenshot(rule.getActivity(), "pdf417_barcode");
|
rule.screenShot("pdf417_barcode");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAztecBarcodeIsShown() {
|
public void testAztecBarcodeIsShown() {
|
||||||
testWithBarcodeFormat(PassBarCodeFormat.AZTEC);
|
testWithBarcodeFormat(AZTEC);
|
||||||
|
|
||||||
Spoon.screenshot(rule.getActivity(), "aztec_barcode");
|
rule.screenShot("aztec_barcode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQRCodeIsShown() {
|
public void testQRCodeIsShown() {
|
||||||
testWithBarcodeFormat(PassBarCodeFormat.QR_CODE);
|
testWithBarcodeFormat(QR_CODE);
|
||||||
|
|
||||||
Spoon.screenshot(rule.getActivity(), "qr_barcode");
|
rule.screenShot("qr_barcode");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCode128CodeIsShown() {
|
public void testCode128CodeIsShown() {
|
||||||
testWithBarcodeFormat(PassBarCodeFormat.CODE_128);
|
testWithBarcodeFormat(CODE_128);
|
||||||
|
|
||||||
Spoon.screenshot(rule.getActivity(), "code128_barcode");
|
rule.screenShot("code128_barcode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCode39CodeIsShown() {
|
public void testCode39CodeIsShown() {
|
||||||
testWithBarcodeFormat(PassBarCodeFormat.CODE_39);
|
testWithBarcodeFormat(CODE_39);
|
||||||
|
|
||||||
Spoon.screenshot(rule.getActivity(), "code39_barcode");
|
rule.screenShot("code39_barcode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,11 @@ public class ThePastLocationsStore {
|
||||||
public void testPastLocationsStoreShouldNeverContainMoreThanMaxElements() {
|
public void testPastLocationsStoreShouldNeverContainMoreThanMaxElements() {
|
||||||
PastLocationsStore tested = new PastLocationsStore(sharedPreferences, tracker);
|
PastLocationsStore tested = new PastLocationsStore(sharedPreferences, tracker);
|
||||||
|
|
||||||
for (int i = 0; i < PastLocationsStore.MAX_ELEMENTS * 2; i++) {
|
for (int i = 0; i < PastLocationsStore.Companion.getMAX_ELEMENTS() * 2; i++) {
|
||||||
tested.putLocation("" + i);
|
tested.putLocation("" + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(tested.getLocations().size()).isEqualTo(PastLocationsStore.MAX_ELEMENTS);
|
assertThat(tested.getLocations().size()).isEqualTo(PastLocationsStore.Companion.getMAX_ELEMENTS());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
package org.ligi.passandroid.model;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import org.ligi.passandroid.Tracker;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
public class PastLocationsStore {
|
|
||||||
public static final String KEY_PAST_LOCATIONS = "past_locations";
|
|
||||||
public static final int MAX_ELEMENTS = 5;
|
|
||||||
|
|
||||||
private final SharedPreferences sharedPreferences;
|
|
||||||
private final Tracker tracker;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public PastLocationsStore(SharedPreferences sharedPreferences, Tracker tracker) {
|
|
||||||
this.sharedPreferences = sharedPreferences;
|
|
||||||
this.tracker = tracker;
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(11)
|
|
||||||
public void putLocation(final String path) {
|
|
||||||
if (Build.VERSION.SDK_INT < 11) {
|
|
||||||
// feature not available for these versions
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final Set<String> pastLocations = sharedPreferences.getStringSet(KEY_PAST_LOCATIONS, new HashSet<String>());
|
|
||||||
|
|
||||||
if (pastLocations.size() >= MAX_ELEMENTS) {
|
|
||||||
deleteOneElementFromSet(pastLocations);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pastLocations.contains(path)) {
|
|
||||||
pastLocations.add(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
tracker.trackEvent("scan", "put location", "count", (long) pastLocations.size());
|
|
||||||
sharedPreferences.edit().putStringSet(KEY_PAST_LOCATIONS, pastLocations).apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteOneElementFromSet(Set<String> pastLocations) {
|
|
||||||
final int deleteAtPosition = (int) (Math.random() * MAX_ELEMENTS);
|
|
||||||
int pos = 0;
|
|
||||||
for (String location : pastLocations) {
|
|
||||||
if (pos == deleteAtPosition) {
|
|
||||||
pastLocations.remove(location);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@TargetApi(11)
|
|
||||||
public Set<String> getLocations() {
|
|
||||||
if (Build.VERSION.SDK_INT < 11) {
|
|
||||||
// feature not available for these versions
|
|
||||||
return new HashSet<>();
|
|
||||||
}
|
|
||||||
return sharedPreferences.getStringSet(KEY_PAST_LOCATIONS, new HashSet<String>());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
package org.ligi.passandroid.model
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Build
|
||||||
|
import org.ligi.passandroid.Tracker
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class PastLocationsStore
|
||||||
|
@Inject
|
||||||
|
constructor(private val sharedPreferences: SharedPreferences, private val tracker: Tracker) {
|
||||||
|
|
||||||
|
@TargetApi(11)
|
||||||
|
fun putLocation(path: String) {
|
||||||
|
if (Build.VERSION.SDK_INT < 11) {
|
||||||
|
// feature not available for these versions
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val pastLocations = sharedPreferences.getStringSet(KEY_PAST_LOCATIONS, HashSet<String>())
|
||||||
|
|
||||||
|
if (pastLocations!!.size >= MAX_ELEMENTS) {
|
||||||
|
deleteOneElementFromSet(pastLocations)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pastLocations.contains(path)) {
|
||||||
|
pastLocations.add(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
tracker.trackEvent("scan", "put location", "count", pastLocations.size.toLong())
|
||||||
|
sharedPreferences.edit().putStringSet(KEY_PAST_LOCATIONS, pastLocations).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteOneElementFromSet(pastLocations: MutableSet<String>) {
|
||||||
|
val deleteAtPosition = (Math.random() * MAX_ELEMENTS).toInt()
|
||||||
|
for ((pos, location) in pastLocations.withIndex()) {
|
||||||
|
if (pos == deleteAtPosition) {
|
||||||
|
pastLocations.remove(location)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// feature not available for these versions
|
||||||
|
val locations: Set<String>
|
||||||
|
@TargetApi(11)
|
||||||
|
get() {
|
||||||
|
if (Build.VERSION.SDK_INT < 11) {
|
||||||
|
return HashSet()
|
||||||
|
}
|
||||||
|
return sharedPreferences.getStringSet(KEY_PAST_LOCATIONS, HashSet<String>())
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
val KEY_PAST_LOCATIONS = "past_locations"
|
||||||
|
val MAX_ELEMENTS = 5
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
package org.ligi.passandroid.printing;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.print.PrintManager;
|
|
||||||
import org.ligi.passandroid.R;
|
|
||||||
import org.ligi.passandroid.model.pass.Pass;
|
|
||||||
|
|
||||||
public class PrintHelper {
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
|
||||||
public static void doPrint(Context context, Pass pass) {
|
|
||||||
final PrintManager printManager = (PrintManager) context.getSystemService(Context.PRINT_SERVICE);
|
|
||||||
final String jobName = context.getString(R.string.app_name) + " print of " + pass.getDescription();
|
|
||||||
printManager.print(jobName, new PassPrintDocumentAdapter(context, pass, jobName), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.ligi.passandroid.printing
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import android.print.PrintManager
|
||||||
|
import org.ligi.passandroid.R
|
||||||
|
import org.ligi.passandroid.model.pass.Pass
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.KITKAT)
|
||||||
|
fun doPrint(context: Context, pass: Pass) {
|
||||||
|
val printManager = context.getSystemService(Context.PRINT_SERVICE) as PrintManager
|
||||||
|
val jobName = context.getString(R.string.app_name) + " print of " + pass.description
|
||||||
|
printManager.print(jobName, PassPrintDocumentAdapter(context, pass, jobName), null)
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ import org.ligi.passandroid.maps.PassbookMapsFacade
|
||||||
import org.ligi.passandroid.model.PassStore
|
import org.ligi.passandroid.model.PassStore
|
||||||
import org.ligi.passandroid.model.Settings
|
import org.ligi.passandroid.model.Settings
|
||||||
import org.ligi.passandroid.model.pass.Pass
|
import org.ligi.passandroid.model.pass.Pass
|
||||||
import org.ligi.passandroid.printing.PrintHelper
|
import org.ligi.passandroid.printing.doPrint
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ class PassMenuOptions(val activity: Activity, val pass: Pass) {
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.menu_print -> {
|
R.id.menu_print -> {
|
||||||
PrintHelper.doPrint(activity, pass)
|
doPrint(activity, pass)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,15 @@
|
||||||
PassAndroid - Passbook для Android
|
<b>Что это?</b>
|
||||||
|
|
||||||
|
|
||||||
Что это?
|
|
||||||
========
|
|
||||||
|
|
||||||
Это приложение для просмотра файлов passbook. Это может быть посадочный талон на ваш следующий рейс, купон на бесплатный кофе в месте назначения, билет в кино, дисконтная карта - возможна масса вариантов.
|
Это приложение для просмотра файлов passbook. Это может быть посадочный талон на ваш следующий рейс, купон на бесплатный кофе в месте назначения, билет в кино, дисконтная карта - возможна масса вариантов.
|
||||||
Это замена кускам бумаги или пластика, которые приходится носить с собой а потом выбрасывать. Давайте спасем несколько деревьев и уменьшим количество мусора!
|
Это замена кускам бумаги или пластика, которые приходится носить с собой а потом выбрасывать. Давайте спасем несколько деревьев и уменьшим количество мусора!
|
||||||
Кстати, это приложение бесплатно, свободно в духе концепции Ричарда Столлмана о бесплатном и открытом программном обеспечении на благо мира.
|
Кстати, это приложение бесплатно, свободно в духе концепции Ричарда Столлмана о бесплатном и открытом программном обеспечении на благо мира.
|
||||||
|
|
||||||
Как это работает?
|
<b>Как это работает?</b>
|
||||||
==============
|
|
||||||
|
|
||||||
Есть так называемые pkpass фалы, которые можно открыть в этом приложением, например когда вы получаете их по почте или загружаете с сайтов. Самое важное содержимое - это штрих-код (QR , AZTEC & PDF417), который обычно считывают на кассе или на стойке регистрации. Но в карточке может содержаться еще и детальное описание, а часто и время события (которое можно добавить в календарь), а также место (до которого проложить маршрут). Попробуйте, это удобно!
|
Есть так называемые pkpass фалы, которые можно открыть в этом приложением, например когда вы получаете их по почте или загружаете с сайтов. Самое важное содержимое - это штрих-код (QR , AZTEC & PDF417), который обычно считывают на кассе или на стойке регистрации. Но в карточке может содержаться еще и детальное описание, а часто и время события (которое можно добавить в календарь), а также место (до которого проложить маршрут). Попробуйте, это удобно!
|
||||||
Карточки, сохраненные в приложении, можно использовать офлайн!
|
Карточки, сохраненные в приложении, можно использовать офлайн!
|
||||||
|
|
||||||
История создания
|
<b>История создания</b>
|
||||||
=====
|
|
||||||
|
|
||||||
Я наткнулся на файлы Passbook когда получил билет на конференцию "29C3" (ежегодные компьютерные конференции, эта проводилась в 2013г.), мне понравилась идея но не было приложения под Android которое меня бы устроило. Я увидел что технически реализация довольно проста: обычный zip архив со скриптом json и картинками. Первая версия приложения была создана очень быстро и сработала, меня пустили на конференцию. В течении следующего года я почти не занимался этим приложением, поскольку лично у меня оно не находило постоянного применения. Однако много людей скачали приложение и используют его, люди писали отзывы, присылали файлы passbook которые не открывались в приложении, пришлось поработать и добиться нормальной работы с файлами passbook, в которых json был просто "сломан", написан не по стандарту.
|
Я наткнулся на файлы Passbook когда получил билет на конференцию "29C3" (ежегодные компьютерные конференции, эта проводилась в 2013г.), мне понравилась идея но не было приложения под Android которое меня бы устроило. Я увидел что технически реализация довольно проста: обычный zip архив со скриптом json и картинками. Первая версия приложения была создана очень быстро и сработала, меня пустили на конференцию. В течении следующего года я почти не занимался этим приложением, поскольку лично у меня оно не находило постоянного применения. Однако много людей скачали приложение и используют его, люди писали отзывы, присылали файлы passbook которые не открывались в приложении, пришлось поработать и добиться нормальной работы с файлами passbook, в которых json был просто "сломан", написан не по стандарту.
|
||||||
Годом позже - как раз перед конференцией "30C3" (2014г.) - я опять начал активно работать над этим приложением по двум причинам:
|
Годом позже - как раз перед конференцией "30C3" (2014г.) - я опять начал активно работать над этим приложением по двум причинам:
|
||||||
|
@ -23,8 +17,7 @@ PassAndroid - Passbook для Android
|
||||||
- я получил письмо от Luis Torrecilla - прекрасного дизайнера, который нарисовал новый дизайн приложения.
|
- я получил письмо от Luis Torrecilla - прекрасного дизайнера, который нарисовал новый дизайн приложения.
|
||||||
Все это привело к появлению следующей версии PassAndroid, полностью новой версии с новым функциональным интерфейсом.
|
Все это привело к появлению следующей версии PassAndroid, полностью новой версии с новым функциональным интерфейсом.
|
||||||
|
|
||||||
Карточки которые работают с данным приложением
|
<b>Карточки которые работают с данным приложением</b>
|
||||||
=============
|
|
||||||
|
|
||||||
Air Berlin
|
Air Berlin
|
||||||
Air Canada
|
Air Canada
|
||||||
|
@ -64,18 +57,14 @@ TAP (Portugal)
|
||||||
|
|
||||||
это только те карточки про которые я знаю, напишите мне или напишите в сообществе, какие еще карточки Passbook работают в данном приложении.
|
это только те карточки про которые я знаю, напишите мне или напишите в сообществе, какие еще карточки Passbook работают в данном приложении.
|
||||||
|
|
||||||
Исходный код / сообщения о проблемах в приложении
|
<b>Исходный код / сообщения о проблемах в приложении</b>
|
||||||
==================
|
|
||||||
|
|
||||||
все на github:
|
все на github:
|
||||||
|
|
||||||
https://github.com/ligi/PassAndroid/
|
https://github.com/ligi/PassAndroid/
|
||||||
|
|
||||||
|
|
||||||
Лицензия
|
<b>Лицензия </b>
|
||||||
======
|
|
||||||
|
|
||||||
GPLv3
|
GPLv3
|
||||||
|
|
||||||
|
|
||||||
Ключевые слова: карточки подарочные карты лояльности билеты passbook qr-code qr-код qr-коды билет билеты лояльность passsource членство идентификация член конференция посадочный талон путешествия
|
|
Loading…
Reference in a new issue