Authored by Castiel

android 扫码提交 —review by 叶弯弯

Showing 35 changed files with 1098 additions and 10 deletions
... ... @@ -129,11 +129,19 @@ android {
}
}
}
packagingOptions {
exclude 'META-INF/maven/com.squareup.okhttp/okhttp/pom.xml'
exclude 'META-INF/maven/com.squareup.okhttp/okhttp/pom.properties'
exclude 'META-INF/maven/com.squareup.okio/okio/pom.xml'
exclude 'META-INF/maven/com.squareup.okio/okio/pom.properties'
}
}
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile 'com.google.zxing:core:3.2.1'
compile "com.facebook.react:react-native:+" // From node_modules
compile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') {
transitive = true;
... ...
... ... @@ -5,6 +5,33 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
Don't require camera, as this requires a rear camera. This allows it to work on the Nexus 7
<uses-feature android:name="android.hardware.Camera"></uses-feature>
<uses-feature android:name="android.hardware.camera.front"></uses-feature>
<!-- replace above two with next line after Android 4.2 -->
<uses-feature android:name="android.hardware.camera.any" />
<uses-feature android:name="android.hardware.camera.autofocus"></uses-feature>
<uses-feature android:name="android.hardware.camera.flash"></uses-feature>
<uses-feature android:name="android.hardware.screen.landscape" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<!-- This excludes Google TV, which is unfortunately included by virtue of not requiring a camera -->
<uses-feature android:name="android.hardware.touchscreen" />
<used-feature android:name="android.hardware.camera.setParameters" />
<uses-sdk
android:minSdkVersion="16"
... ... @@ -21,16 +48,22 @@
android:value="9ce9bfb831525a4128e175af5bca4a7ce276e162"
/>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".barcode.QRActivity"
android:label="@string/scan"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.NoActionBar">
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
... ...
... ... @@ -8,6 +8,7 @@ import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.learnium.RNDeviceInfo.RNDeviceInfo;
import com.smixx.fabric.FabricPackage;
import com.yh_vendor.barcode.QRNativeConfig;
import java.util.Arrays;
import java.util.List;
... ... @@ -50,6 +51,7 @@ public class MainActivity extends ReactActivity {
new FabricPackage(this),
new RNNativeConfig(),
new RNDeviceInfo(),
new QRNativeConfig(),
new MainReactPackage()
);
}
... ...
package com.yh_vendor.barcode;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.util.Log;
import android.view.SurfaceHolder;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.Result;
import com.yh_vendor.R;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public abstract class BaseCameraManager {
private Point qrBoxSize;
protected int rotate;
protected int count = 0;
protected boolean isRelease = true;
protected ExecutorService executor;
protected int displayOrientation;
protected MultiFormatReader reader;
protected OnResultListener onResultListener;
protected Context context;
public BaseCameraManager(Context context) {
this.context = context;
executor = Executors.newSingleThreadExecutor();
reader = new MultiFormatReader();
qrBoxSize = new Point();
qrBoxSize.x = (int) context.getResources().getDimension(R.dimen.width_qr_box_view);
qrBoxSize.y = (int) context.getResources().getDimension(R.dimen.height_qr_box_view);
}
protected QRResult getCodeValue(byte[] data, Point previewSize) {
Bitmap bitmap = null;
ByteArrayOutputStream stream = new ByteArrayOutputStream(data.length);
YuvImage image = new YuvImage(data, ImageFormat.NV21, previewSize.x, previewSize.y, null);
int left = previewSize.x - qrBoxSize.x >> 1;
int right = previewSize.x + qrBoxSize.x >> 1;
int top = previewSize.y - qrBoxSize.y >> 1;
int bottom = previewSize.y + qrBoxSize.y >> 1;
Rect rect = new Rect(left, top, right, bottom);
if (image.compressToJpeg(rect, 100, stream)) {
byte[] bytes = stream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
}
try {
stream.close();
} catch (IOException e) {
Log.e("onPreviewFrame", e.toString());
}
if (displayOrientation > 0) {
Matrix matrix = new Matrix();
matrix.postRotate(displayOrientation);
Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
bitmap.recycle();
bitmap = newBitmap;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
Result result = QRUtils.decode(new RGBLuminanceSource(width, height, pixels), reader);
if (result != null) {
return new QRResult(bitmap, result);
} else {
bitmap.recycle();
return null;
}
}
public void setOnResultListener(OnResultListener onResultListener) {
this.onResultListener = onResultListener;
}
public void shutdownExecutor() {
executor.shutdown();
}
public ExecutorService getExecutor() {
return executor;
}
public void setRotate(int rotate) {
this.rotate = rotate;
}
public abstract void connectCamera(SurfaceHolder surfaceHolder);
public abstract void setCameraParameter();
public abstract void startCapture();
public abstract void releaseCamera();
public interface OnResultListener {
void onResult(QRResult qrResult);
}
}
... ...
package com.yh_vendor.barcode;
import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import java.io.IOException;
import java.util.List;
/**
* This class is for android targets below android 5.0 and it uses old camera api
*/
public class CameraManager extends BaseCameraManager implements Camera.AutoFocusCallback, Camera.PreviewCallback {
private Camera camera;
public CameraManager(Context context) {
super(context);
}
@Override
public void onAutoFocus(boolean success, Camera camera) {
if (isRelease) return;
camera.setOneShotPreviewCallback(this);
}
@Override
public void connectCamera(SurfaceHolder surfaceHolder) {
if (!isRelease) return;
try {
camera = Camera.open();
isRelease = false;
camera.setPreviewDisplay(surfaceHolder);
setCameraParameter();
camera.startPreview();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void releaseCamera() {
if (isRelease) return;
isRelease = true;
camera.cancelAutoFocus();
camera.stopPreview();
try {
camera.setPreviewDisplay(null);
} catch (IOException e) {
throw new RuntimeException(e);
}
camera.release();
camera = null;
}
@Override
public void startCapture() {
if (isRelease || executor.isShutdown()) return;
executor.execute(new Runnable() {
@Override
public void run() {
camera.autoFocus(CameraManager.this);
}
});
}
@Override
public void setCameraParameter() {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(0, cameraInfo);
int degrees = 0;
switch (rotate) {
case Surface.ROTATION_0: {
degrees = 0;
break;
}
case Surface.ROTATION_90: {
degrees = 90;
break;
}
case Surface.ROTATION_180: {
degrees = 180;
break;
}
case Surface.ROTATION_270: {
degrees = 270;
break;
}
}
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
displayOrientation = (cameraInfo.orientation + degrees) % 360;
displayOrientation = (360 - displayOrientation) % 360;
} else {
displayOrientation = (cameraInfo.orientation - degrees + 360) % 360;
}
/** Warning : may throw exception with parameters not supported */
Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
Camera.Size bestSize = previewSizes.get(0);
for (int i = 1; i < previewSizes.size(); i++) {
if (previewSizes.get(i).width * previewSizes.get(i).height > bestSize.width * bestSize.height) {
bestSize = previewSizes.get(i);
}
}
parameters.setPreviewSize(bestSize.width, bestSize.height);
List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes();
bestSize = pictureSizes.get(0);
for (int i = 1; i < pictureSizes.size(); i++) {
if (pictureSizes.get(i).width * pictureSizes.get(i).height > bestSize.width * bestSize.height) {
bestSize = pictureSizes.get(i);
}
}
parameters.setPictureSize(bestSize.width, bestSize.height);
camera.setParameters(parameters);
camera.setDisplayOrientation(displayOrientation);
}
@Override
public void onPreviewFrame(final byte[] data, final Camera camera) {
if (executor.isShutdown()) return;
try {
Camera.Size size = camera.getParameters().getPreviewSize();
QRResult qrResult = getCodeValue(data, new Point(size.width, size.height));
if (qrResult == null) {
count++;
startCapture();
return;
}
QRUtils.vibrate(context);
if (onResultListener != null) {
onResultListener.onResult(qrResult);
}
count = 0;
}
catch (Exception e) {
Log.e("CameraManager", "getCodeValue() failed .");
}
}
}
... ...
package com.yh_vendor.barcode;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.yh_vendor.R;
public class QRActivity extends Activity
implements SurfaceHolder.Callback
{
private SurfaceHolder holder;
private QRCodeView qrCodeView;
private SurfaceView surfaceView;
private View emptyView;
public static ReactApplicationContext mRNContext;
public static final int CODE_PICK_IMAGE = 0x100;
private BaseCameraManager cameraManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qr);
surfaceView = (SurfaceView) findViewById(R.id.sv_preview);
qrCodeView = (QRCodeView) findViewById(R.id.qr_view);
emptyView = findViewById(R.id.v_empty);
if (Build.VERSION_CODES.LOLLIPOP >= Build.VERSION.SDK_INT) {
cameraManager = new CameraManager(getApplication());
} else {
cameraManager = new CameraManager(getApplication());
}
holder = surfaceView.getHolder();
holder.addCallback(this);
cameraManager.setOnResultListener(new BaseCameraManager.OnResultListener() {
@Override
public void onResult(QRResult qrResult) {
QRActivity.this.finish();
WritableMap params = Arguments.createMap();
params.putString("QRCode", qrResult.getResult().getText());
sendEvent(mRNContext, "scanQRComplete", params);
}
});
}
private void sendEvent(ReactContext reactContext,
String eventName,
@Nullable WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
@Override
protected void onResume() {
super.onResume();
setSurfaceViewVisible(true);
}
@Override
protected void onPause() {
super.onPause();
setSurfaceViewVisible(false);
}
@Override
protected void onDestroy() {
super.onDestroy();
cameraManager.releaseCamera();
cameraManager.shutdownExecutor();
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if (cameraManager.getExecutor().isShutdown()) return;
cameraManager.setRotate(getWindowManager().getDefaultDisplay().getRotation());
cameraManager.connectCamera(surfaceHolder);
setEmptyViewVisible(false);
cameraManager.startCapture();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
setEmptyViewVisible(true);
cameraManager.releaseCamera();
}
public void setEmptyViewVisible(boolean visible) {
if (visible) {
emptyView.setVisibility(View.VISIBLE);
} else {
emptyView.setVisibility(View.GONE);
}
}
public void setSurfaceViewVisible(boolean visible) {
if (visible) {
surfaceView.setVisibility(View.VISIBLE);
} else {
surfaceView.setVisibility(View.INVISIBLE);
}
}
}
... ...
package com.yh_vendor.barcode;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.yh_vendor.R;
public class QRCodeView extends RelativeLayout {
private int maskColor;
private int boxViewWidth;
private int boxViewHeight;
private int cornerColor;
private int borderColor;
private int cornerSize;
private int cornerLength;
private int cornerOffset;
private FrameLayout boxView;
private TextView textView;
private OnClickListener lightOnClickListener;
public QRCodeView(Context context) {
super(context);
initialize(context, null, 0, 0);
}
public QRCodeView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context, attrs, 0, 0);
}
public QRCodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize(context, attrs, defStyleAttr, 0);
}
@SuppressLint("NewApi")
public QRCodeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize(context, attrs, defStyleAttr, defStyleRes);
}
private void initialize(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
inflate(context, R.layout.layout_qr_code_view, this);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.QRCodeView, defStyleAttr, 0);
Resources resources = getResources();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
maskColor = typedArray.getColor(R.styleable.QRCodeView_maskColor, resources.getColor(R.color.qr_code_view_mask));
cornerColor = typedArray.getColor(R.styleable.QRCodeView_boxViewCornerColor, resources.getColor(R.color.qr_code_view_corner));
borderColor = typedArray.getColor(R.styleable.QRCodeView_boxViewBorderColor, resources.getColor(R.color.qr_code_view_border));
} else {
maskColor = typedArray.getColor(R.styleable.QRCodeView_boxViewCornerColor, resources.getColor(R.color.qr_code_view_mask, null));
cornerColor = typedArray.getColor(R.styleable.QRCodeView_boxViewCornerColor, resources.getColor(R.color.qr_code_view_corner, null));
borderColor = typedArray.getColor(R.styleable.QRCodeView_boxViewBorderColor, resources.getColor(R.color.qr_code_view_border, null));
}
cornerOffset = typedArray.getInt(R.styleable.QRCodeView_boxViewCornerOffset, (int) resources.getDimension(R.dimen.size_qr_box_view_corner_offset));
cornerLength = typedArray.getInt(R.styleable.QRCodeView_boxViewCornerLength, (int) resources.getDimension(R.dimen.length_qr_box_view_corner));
cornerSize = typedArray.getInt(R.styleable.QRCodeView_boxViewCornerSize, (int) resources.getDimension(R.dimen.size_qr_box_view_corner));
boxViewWidth = typedArray.getInt(R.styleable.QRCodeView_boxViewWidth, (int) resources.getDimension(R.dimen.width_qr_box_view));
boxViewHeight = typedArray.getInt(R.styleable.QRCodeView_boxViewHeight, (int) resources.getDimension(R.dimen.height_qr_box_view));
typedArray.recycle();
boxView = (FrameLayout) findViewById(R.id.fl_box_view);
textView = (TextView) findViewById(R.id.tv_desc);
LayoutParams params = (LayoutParams) boxView.getLayoutParams();
params.width = boxViewWidth;
params.height = boxViewHeight;
boxView.setLayoutParams(params);
setBackgroundResource(R.color.qr_code_view_mask);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
findViewById(R.id.btn_light).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
CheckBox checkBox = (CheckBox) view;
if (checkBox.isChecked()) {
checkBox.setText(R.string.action_light_off_desc);
} else {
checkBox.setText(R.string.action_light_on_desc);
}
if (lightOnClickListener != null) {
lightOnClickListener.onClick(view);
}
}
});
Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.exlore_line_move);
animation.setInterpolator(new LinearInterpolator());
findViewById(R.id.img_scan_line).setAnimation(animation);
}
@Override
public void onDraw(Canvas canvas) {
/** Draw the exterior dark mask*/
int width = getWidth();
int height = getHeight();
float boxViewX = boxView.getX();
float boxViewY = boxView.getY();
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(maskColor);
canvas.drawRect(0, boxViewY, boxViewX, boxViewY + boxViewHeight, paint);// left rect
canvas.drawRect(boxViewX + boxViewWidth, boxViewY, width, boxViewY + boxViewHeight, paint);// right rect
canvas.drawRect(0, 0, width, boxViewY, paint);// top rect
canvas.drawRect(0, boxViewY + boxViewHeight, width, height, paint);// bottom rect
/** Draw the border lines*/
paint.setColor(borderColor);
canvas.drawLine(boxViewX, boxViewY, boxViewX + boxViewWidth, boxViewY, paint);
canvas.drawLine(boxViewX, boxViewY, boxViewX, boxViewY + boxViewHeight, paint);
canvas.drawLine(boxViewX + boxViewWidth, boxViewY + boxViewHeight, boxViewX, boxViewY + boxViewHeight, paint);
canvas.drawLine(boxViewX + boxViewWidth, boxViewY + boxViewHeight, boxViewX + boxViewWidth, boxViewY, paint);
/** Draw the corners*/
Rect rect = new Rect();
rect.set((int) boxViewX, (int) boxViewY, (int) boxViewX + boxViewWidth, (int) boxViewY + boxViewHeight);
paint.setColor(cornerColor);
/** top the corners*/
canvas.drawRect(rect.left - cornerSize + cornerOffset, rect.top - cornerSize + cornerOffset, rect.left + cornerLength - cornerSize + cornerOffset, rect.top + cornerOffset, paint);
canvas.drawRect(rect.left - cornerSize + cornerOffset, rect.top - cornerSize + cornerOffset, rect.left + cornerOffset, rect.top + cornerLength - cornerSize + cornerOffset, paint);
canvas.drawRect(rect.right - cornerLength + cornerSize - cornerOffset, rect.top - cornerSize + cornerOffset, rect.right + cornerSize - cornerOffset, rect.top + cornerOffset, paint);
canvas.drawRect(rect.right - cornerOffset, rect.top - cornerSize + cornerOffset, rect.right + cornerSize - cornerOffset, rect.top + cornerLength - cornerSize + cornerOffset, paint);
/** bottom the corners*/
canvas.drawRect(rect.left - cornerSize + cornerOffset, rect.bottom - cornerOffset, rect.left + cornerLength - cornerSize + cornerOffset, rect.bottom + cornerSize - cornerOffset, paint);
canvas.drawRect(rect.left - cornerSize + cornerOffset, rect.bottom - cornerLength + cornerSize - cornerOffset, rect.left + cornerOffset, rect.bottom + cornerSize - cornerOffset, paint);
canvas.drawRect(rect.right - cornerLength + cornerSize - cornerOffset, rect.bottom - cornerOffset, rect.right + cornerSize - cornerOffset, rect.bottom + cornerSize - cornerOffset, paint);
canvas.drawRect(rect.right - cornerOffset, rect.bottom - cornerLength + cornerSize - cornerOffset, rect.right + cornerSize - cornerOffset, rect.bottom + cornerSize - cornerOffset, paint);
}
public void setDescription(String text) {
if (textView != null) {
textView.setText(text);
}
}
public void setPickImageListener(OnClickListener onClickListener) {
if (onClickListener != null) {
findViewById(R.id.btn_photo).setOnClickListener(onClickListener);
}
}
public void setProduceQRListener(OnClickListener onClickListener) {
if (onClickListener != null) {
findViewById(R.id.btn_produce).setOnClickListener(onClickListener);
}
}
public void setLightOnClickListener(OnClickListener lightOnClickListener) {
this.lightOnClickListener = lightOnClickListener;
}
}
\ No newline at end of file
... ...
package com.yh_vendor.barcode;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.yh_vendor.RNNativeConfigModule;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class QRNativeConfig implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactApplicationContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new QRNativeConfigModule(reactApplicationContext));
return modules;
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactApplicationContext) {
return Collections.emptyList();
}
}
... ...
package com.yh_vendor.barcode;
import android.content.Intent;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class QRNativeConfigModule extends ReactContextBaseJavaModule {
private final ReactApplicationContext mContext;
private QRScanCompleteListener qrScanCompleteListener;
private interface QRScanCompleteListener {
String onScanComplete();
}
public QRNativeConfigModule(ReactApplicationContext reactContext) {
super(reactContext);
this.mContext = reactContext;
}
@Override
public String getName() {
return "QRNativeConfig";
}
@ReactMethod
public void startScanQRCode() {
QRActivity.mRNContext = mContext;
Intent intent = new Intent(mContext, QRActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
}
... ...
package com.yh_vendor.barcode;
import android.graphics.Bitmap;
import com.google.zxing.Result;
/**
* Created by UsherBaby on 2015/12/4.
*/
public class QRResult {
private Bitmap bitmap;
private Result result;
public QRResult(Bitmap bitmap, Result result) {
this.bitmap = bitmap;
this.result = result;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public Result getResult() {
return result;
}
public void setResult(Result result) {
this.result = result;
}
}
... ...
package com.yh_vendor.barcode;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Vibrator;
import android.util.Log;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
/**
* Created by UsherBaby on 2015/12/3.
*/
public class QRUtils {
/**
* decode a image file.
*
* @param url image file path
* @param reader Z_X_ing MultiFormatReader
*/
public static QRResult decode(String url, MultiFormatReader reader) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(url, options);
if (options.outWidth >= 1920) {
options.inSampleSize = 6;
} else if (options.outWidth >= 1280) {
options.inSampleSize = 5;
} else if (options.outWidth >= 1024) {
options.inSampleSize = 4;
} else if (options.outWidth >= 960) {
options.inSampleSize = 3;
}
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(url);
if (bitmap == null) return null;
int width = bitmap.getWidth(), height = bitmap.getHeight();
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
Result result = decode(new RGBLuminanceSource(width, height, pixels), reader);
if (result != null) {
return new QRResult(bitmap, result);
}
bitmap.recycle();
return null;
} catch (Exception e) {
Log.e("decode exception", e.toString());
return null;
}
}
/**
* decode a LuminanceSource bitmap.
*
* @param source LuminanceSource bitmap
* @param reader Z_X_ing MultiFormatReader
*/
public static Result decode(LuminanceSource source, MultiFormatReader reader) {
Result result = null;
if (source != null) {
BinaryBitmap bBitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
result = reader.decodeWithState(bBitmap);
} catch (ReaderException e) {
result = null;
} finally {
reader.reset();
}
}
return result;
}
public static void vibrate(Context context) {
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(300);
}
}
... ...
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="3000"
android:fromXDelta="0"
android:fromYDelta="0"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:toXDelta="0"
android:toYDelta="100%p">
</translate>
</set>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@android:color/black"/>
</layer-list>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/light_checked" android:state_checked="true" />
<item android:drawable="@drawable/light_normal" />
</selector>
... ...
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/photo_pressed" android:state_pressed="true" />
<item android:drawable="@drawable/photo_normal" />
</selector>
... ...
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/produce_pressed" android:state_pressed="true"/>
<item android:drawable="@drawable/produce_normal"/>
</selector>
... ...
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".barcode.QRActivity">
<SurfaceView
android:id="@+id/sv_preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.yh_vendor.barcode.QRCodeView
android:id="@+id/qr_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:id="@+id/v_empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"></View>
</FrameLayout>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/result_view"
android:orientation="horizontal"
android:padding="6dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:gravity="right|center_vertical"
android:orientation="vertical">
<ImageView
android:id="@+id/img_barcode"
android:layout_width="140dip"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:adjustViewBounds="true"
android:maxHeight="140dip"
android:maxWidth="140dip"
android:scaleType="centerCrop"
android:src="@drawable/explore_icon"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_format"
style="@style/style_dialog_result_desc"
android:text="@string/label_format" />
<TextView
android:id="@+id/tv_type"
style="@style/style_dialog_result_desc"
android:text="@string/label_type" />
<TextView
android:id="@+id/tv_time"
style="@style/style_dialog_result_desc"
android:text="@string/label_time" />
<TextView
android:id="@+id/tv_meta"
style="@style/style_dialog_result_desc"
android:text="@string/label_meta" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.0"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/tv_value"
style="@style/style_dialog_result_value"
android:autoLink="web"
android:textColorLink="@color/result_text"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_value_supplement"
style="@style/style_dialog_result_value" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="@dimen/height_qr_box_view_desc"
android:layout_above="@+id/fl_box_view"
android:layout_centerHorizontal="true"
android:gravity="center"
android:singleLine="true"
android:text="@string/default_desc"
android:textColor="@android:color/white"
android:textSize="@dimen/f_qr_box_view_desc" />
<!--we need to keep scanner view locates in center-->
<FrameLayout
android:id="@+id/fl_box_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<ImageView
android:id="@+id/img_scan_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
android:layout_margin="2dip"
android:background="@drawable/explore_line"
android:contentDescription="@string/app_name"
android:scaleType="centerCrop" />
</FrameLayout>
<LinearLayout
android:id="@+id/ll_action_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:gravity="center"
android:orientation="horizontal"
android:padding="6dp"
android:visibility="gone">
<Button
android:id="@+id/btn_photo"
style="@style/style_qr_box_view_button"
android:drawableTop="@drawable/photo"
android:text="@string/action_photo_desc" />
<CheckBox
android:id="@+id/btn_light"
style="@style/style_qr_box_view_button"
android:button="@null"
android:drawableTop="@drawable/light"
android:text="@string/action_light_on_desc" />
<Button
android:id="@+id/btn_produce"
style="@style/style_qr_box_view_button"
android:drawableTop="@drawable/produce"
android:text="@string/action_produce_desc" />
</LinearLayout>
</merge>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="QRCodeView">
<attr name="boxViewWidth" format="dimension"></attr>
<attr name="boxViewHeight" format="dimension"></attr>
<attr name="maskColor" format="color"></attr>
<attr name="boxViewCornerColor" format="color"></attr>
<attr name="boxViewBorderColor" format="color"></attr>
<attr name="boxViewCornerSize" format="dimension"></attr>
<attr name="boxViewCornerLength" format="dimension"></attr>
<attr name="boxViewCornerOffset" format="dimension"></attr>
</declare-styleable>
</resources>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#000000</color>
<color name="contents_text">#ff000000</color>
<color name="encode_view">#ffffffff</color>
<color name="possible_result_points">#c0ffbd21</color>
<!-- Android standard ICS color -->
<color name="result_minor_text">#60000000</color>
<color name="result_points">#c099cc00</color>
<!-- Android standard ICS color -->
<color name="result_text">#60000000</color>
<color name="result_view">#ffffffff</color>
<color name="status_text">#ffffffff</color>
<color name="transparent">#00000000</color>
<color name="viewfinder_laser">#ffcc0000</color>
<!-- Android standard ICS color -->
<color name="qr_code_view_mask">#60000000</color>
<color name="qr_code_view_corner">#FF2A7C3B</color>
<color name="qr_code_view_border">#ffffffff</color>
</resources>
\ No newline at end of file
... ...
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<dimen name="size_qr_box_view_corner">8dp</dimen>
<dimen name="size_qr_box_view_corner_offset">4dp</dimen>
<dimen name="length_qr_box_view_corner">30dp</dimen>
<dimen name="f_qr_box_view_desc">16sp</dimen>
<dimen name="f_qr_box_action_desc">12sp</dimen>
<dimen name="ml_qr_box_action">10dp</dimen>
<dimen name="width_qr_box_view">240dp</dimen>
<dimen name="height_qr_box_view">240dp</dimen>
<dimen name="height_qr_box_view_desc">35dp</dimen>
</resources>
\ No newline at end of file
... ...
<resources>
<string name="app_name">贩售通</string>
<string name="scan">描码</string>
<string name="default_desc">将取景框对准码区,即可自动扫描</string>
<string name="action_photo_desc">相册</string>
<string name="action_light_on_desc">开灯</string>
<string name="action_light_off_desc">关灯</string>
<string name="action_produce_desc">创建二维码</string>
<string name="label_format">格式:{format}</string>
<string name="label_meta">元数据:{meta}</string>
<string name="label_code_value">https://www.google.com</string>
<string name="label_time">时间:{time}</string>
<string name="label_type">类型:{type}</string>
</resources>
... ...
... ... @@ -5,5 +5,37 @@
<!-- Customize your theme here. -->
<item name="android:windowBackground">@drawable/splash</item>
</style>
<style name="style_qr_box_view_button">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">@dimen/f_qr_box_action_desc</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:background">@null</item>
<item name="android:layout_marginLeft">@dimen/ml_qr_box_action</item>
</style>
<style name="style_dialog_result_desc">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">@color/result_minor_text</item>
<item name="android:layout_marginTop">6dp</item>
<item name="android:gravity">right</item>
</style>
<style name="style_dialog_result_value">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">@color/result_text</item>
<item name="android:layout_marginTop">6dp</item>
<item name="android:textIsSelectable">true</item>
<item name="android:paddingLeft">12dp</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
<item name="android:text">@string/label_code_value</item>
</style>
<style name="Black_Theme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@drawable/black_theme</item>
</style>
</resources>
... ...
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<style name="CaptureTheme" parent="android:Theme.Holo">
<item name="android:windowFullscreen">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowActionModeOverlay">true</item>
</style>
</resources>
... ...
... ... @@ -5,6 +5,10 @@ import LoadMoreIndicator from '../indicator/LoadMoreIndicator';
import LoadingIndicator from '../indicator/LoadingIndicator';
import moment from 'moment';
import DeliverGoodsCell from './DeliverGoodsCell';
import {NativeModules} from 'react-native';
import { DeviceEventEmitter } from 'react-native';
let QRNativeConfig = NativeModules.QRNativeConfig;
import {
StyleSheet,
... ... @@ -30,6 +34,7 @@ export default class DeliverGoods extends Component {
this.state = {
express: '1',
showPicker: false,
qrCode: ''
};
}
... ... @@ -89,8 +94,11 @@ export default class DeliverGoods extends Component {
<TextInput style={styles.numberInputText}
ref = 'textInput1'
placeholder={'输入物流单号'}
onChangeText={(text) => this.setState({qrCode: text})}
value={this.state.qrCode}
/>
<TouchableOpacity onPress={() => {
QRNativeConfig.startScanQRCode();
}}>
<View style={styles.camera}>
</View>
... ... @@ -110,6 +118,15 @@ export default class DeliverGoods extends Component {
</View>
);
}
componentWillMount() {
let that = this;
DeviceEventEmitter.addListener('scanQRComplete', function(param) {
that.setState({qrCode: param.QRCode})
console.log(that.state.qrCode);
});
}
}
let {width, height} = Dimensions.get('window');
... ...