Skip to content
This repository has been archived by the owner on Jan 12, 2019. It is now read-only.

Commit

Permalink
Release 5.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lkorth committed Jan 27, 2017
1 parent ca36426 commit ed89cf2
Show file tree
Hide file tree
Showing 23 changed files with 858 additions and 162 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
card.io Android SDK change log and release notes
================================================

5.5.0
-----
* Update Gradle build plugin to 2.2.3.
* Update compile and target SDK versions to 25.
* Update NDK to r13b.
* Increase `minSdkVersion` to 16.
* Upgrade OpenCV to 2.4.13.

5.4.2
-----
* Add Mastercard 2-series support.
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ All releases follow [semantic versioning](http://semver.org/).

The latest version is available via `mavenCentral()`. Just add the following dependency:

```gradle
compile 'io.card:android-sdk:5.4.2'
```
compile 'io.card:android-sdk:5.5.0'
```

You can receive updates about new versions via a few different channels:
Expand Down Expand Up @@ -45,8 +45,8 @@ A manual entry fallback mode is provided for devices that do not meet these requ

##### If you use gradle, then add the following dependency from `mavenCentral()`:

```gradle
compile 'io.card:android-sdk:5.4.2'
```
compile 'io.card:android-sdk:5.5.0'
```

##### If you use something other than gradle, then:
Expand Down
29 changes: 21 additions & 8 deletions SampleApp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,31 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.android.tools.build:gradle:2.2.3'
}
}

repositories {
jcenter()
maven {
url "https://jitpack.io"
}
}

apply plugin: 'com.android.application'

android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
compileSdkVersion 25
buildToolsVersion "25.0.0"

defaultConfig {
applicationId "io.card.development"
minSdkVersion 18
targetSdkVersion 25
versionCode 1
versionName "1.0.0"
testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
}

signingConfigs {
myConfig {
Expand All @@ -27,10 +39,6 @@ android {
}

buildTypes {
debug {
applicationIdSuffix ".debug"
}

release {
minifyEnabled true
proguardFile getDefaultProguardFile('proguard-android.txt')
Expand All @@ -52,8 +60,13 @@ dependencies {
if (parent != null) {
compile project(':card.io')
} else {
compile 'io.card:android-sdk:5.4.2'
compile 'io.card:android-sdk:5.5.0'
}

debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4'

androidTestCompile "com.android.support.test.espresso:espresso-core:2.2.2"
androidTestCompile "com.github.lkorth:device-automator:01d85912ec"
}

task wrapper(type: Wrapper) {
Expand Down
4 changes: 4 additions & 0 deletions SampleApp/src/androidTest/assets/test_card_images/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Test Card Images

Card images in this folder are included for automated testing. Images should be 640px x 480px for
tests.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
113 changes: 113 additions & 0 deletions SampleApp/src/androidTest/java/io/card/payment/CardScannerTester.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package io.card.payment;

/* CardScannerTester.java
* See the file "LICENSE.md" for the full license governing this code.
*/

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.view.SurfaceHolder;

import java.io.IOException;

import static android.support.test.InstrumentationRegistry.getInstrumentation;

public class CardScannerTester extends CardScanner {

private static final long FRAME_INTERVAL = (long) (1000.0 / 30);

private static String sCardAssetName;

private boolean mScanAllowed;
private Handler mHandler;
private byte[] mFrame;

public static void setCardAsset(String cardAssetName) {
sCardAssetName = cardAssetName;
}

public CardScannerTester(CardIOActivity scanActivity, int currentFrameOrientation) {
super(scanActivity, currentFrameOrientation);
useCamera = false;
mScanAllowed = false;
mHandler = new Handler();

try {
Bitmap bitmap = BitmapFactory.decodeStream(getInstrumentation().getContext().getAssets()
.open("test_card_images/" + sCardAssetName));
mFrame = getNV21FormattedImage(bitmap.getWidth(), bitmap.getHeight(), bitmap);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private Runnable mFrameRunnable = new Runnable() {
@Override
public void run() {
if (!mScanAllowed) {
return;
}

onPreviewFrame(mFrame, null);
mHandler.postDelayed(this, FRAME_INTERVAL);
}
};

@Override
boolean resumeScanning(SurfaceHolder holder) {
boolean result = super.resumeScanning(holder);
mScanAllowed = true;
mHandler.postDelayed(mFrameRunnable, FRAME_INTERVAL);
return result;
}

@Override
public void pauseScanning() {
mScanAllowed = false;
super.pauseScanning();
}

private byte[] getNV21FormattedImage(int width, int height, Bitmap bitmap) {
int [] argb = new int[width * height];
byte [] yuv = new byte[width * height * 3 / 2];

bitmap.getPixels(argb, 0, width, 0, 0, width, height);
encodeYUV420SP(yuv, argb, width, height);
bitmap.recycle();

return yuv;
}

private void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) {
int frameSize = width * height;
int yIndex = 0;
int uvIndex = frameSize;

int R, G, B, Y, U, V;
int index = 0;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
R = (argb[index] & 0xff0000) >> 16;
G = (argb[index] & 0xff00) >> 8;
B = (argb[index] & 0xff);

// well known RGB to YUV algorithm
Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128;

// NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2
// meaning for every 4 Y pixels there are 1 V and 1 U. Note the sampling is every
// other pixel AND every other scanline.
yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
if (j % 2 == 0 && index % 2 == 0) {
yuv420sp[uvIndex++] = (byte)((V<0) ? 0 : ((V > 255) ? 255 : V));
yuv420sp[uvIndex++] = (byte)((U<0) ? 0 : ((U > 255) ? 255 : U));
}

index ++;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package io.card.test;

import android.Manifest;
import android.app.Activity;
import android.content.Intent;

import org.junit.Rule;
import org.junit.Test;

import java.lang.reflect.Field;

import io.card.payment.CardIOActivity;
import io.card.payment.CardScannerTester;
import io.card.payment.CreditCard;

import static com.lukekorth.deviceautomator.DeviceAutomator.onDevice;
import static junit.framework.Assert.assertEquals;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

public class CardIOActivityTest {

private CardIOTestActivity mActivity;

@Rule
public final CustomActivityTestRule<CardIOTestActivity> mActivityTestRule =
new CustomActivityTestRule<>(CardIOTestActivity.class, false, false);

@Test(timeout = 30000)
public void scansAmexCards() {
CardScannerTester.setCardAsset("amex.png");

startScan();

waitForActivityToFinish();
CreditCard result = getActivityResultIntent().getParcelableExtra(CardIOActivity.EXTRA_SCAN_RESULT);
assertEquals("3743 260055 74998", result.getFormattedCardNumber());
}

private void startScan() {
mActivityTestRule.launchActivity(null);
mActivity = mActivityTestRule.getActivity();

onDevice().acceptRuntimePermission(Manifest.permission.CAMERA);
}

private void waitForActivityToFinish() {
long endTime = System.currentTimeMillis() + 10000;

do {
try {
if (mActivity.isFinishing()) {
return;
}
} catch (Exception ignored) {}
} while (System.currentTimeMillis() < endTime);

throw new RuntimeException("Maximum wait elapsed (10s) while waiting for activity to finish");
}

private Intent getActivityResultIntent() {
assertThat("Activity did not finish", mActivity.isFinishing(), is(true));

try {
Field resultDataField = Activity.class.getDeclaredField("mResultData");
resultDataField.setAccessible(true);
return (Intent) resultDataField.get(mActivity);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.card.test;


import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Context;

import static android.support.test.InstrumentationRegistry.getTargetContext;

public class CustomActivityTestRule<T extends Activity> extends android.support.test.rule.ActivityTestRule<T> {

private KeyguardManager.KeyguardLock mKeyguardLock;

public CustomActivityTestRule(Class<T> activityClass) {
super(activityClass);
init();
}

public CustomActivityTestRule(Class<T> activityClass, boolean initialTouchMode) {
super(activityClass, initialTouchMode);
init();
}

public CustomActivityTestRule(Class<T> activityClass, boolean initialTouchMode, boolean launchActivity) {
super(activityClass, initialTouchMode, launchActivity);
init();
}

private void init() {
mKeyguardLock = ((KeyguardManager) getTargetContext().getSystemService(Context.KEYGUARD_SERVICE))
.newKeyguardLock("CardIOTest");
mKeyguardLock.disableKeyguard();
}

@Override
protected void afterActivityFinished() {
super.afterActivityFinished();

mKeyguardLock.reenableKeyguard();
}
}
Loading

0 comments on commit ed89cf2

Please sign in to comment.