This repository has been archived by the owner on Jan 12, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 375
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
231 additions
and
560 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
113
SampleApp/src/androidTest/java/io/card/payment/CardScannerTester.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 ++; | ||
} | ||
} | ||
} | ||
} |
81 changes: 81 additions & 0 deletions
81
SampleApp/src/androidTest/java/io/card/test/CardIOActivityTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package io.card.test; | ||
|
||
import android.Manifest; | ||
import android.app.Activity; | ||
import android.content.Intent; | ||
import android.support.test.rule.ActivityTestRule; | ||
import android.view.WindowManager; | ||
|
||
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 ActivityTestRule<CardIOTestActivity> mActivityTestRule = | ||
new ActivityTestRule<>(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(); | ||
mActivity.runOnUiThread(new Runnable() { | ||
public void run() { | ||
mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | | ||
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | | ||
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); | ||
} | ||
}); | ||
|
||
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); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Binary file removed
BIN
-3.07 MB
SampleApp/src/main/assets/recordings/recording_320455133.550273.zip
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.