Commit 853e66ed by gao.chao

扫码

parent fbe78c09
...@@ -16,8 +16,6 @@ ...@@ -16,8 +16,6 @@
<uses-permission android:name="android.permission.USE_SIP" /> <uses-permission android:name="android.permission.USE_SIP" />
<application <application
android:name=".MyApplication" android:name=".MyApplication"
android:allowBackup="true" android:allowBackup="true"
...@@ -25,7 +23,7 @@ ...@@ -25,7 +23,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppThemeNoActionBar" > android:theme="@style/AppThemeNoActionBar">
<activity android:name=".MainActivity"> <activity android:name=".MainActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
...@@ -42,10 +40,11 @@ ...@@ -42,10 +40,11 @@
<activity android:name=".ViewActviity" /> <activity android:name=".ViewActviity" />
<activity android:name=".QRActivity" /> <activity android:name=".QRActivity" />
<activity android:name=".TitleActivity" /> <activity android:name=".TitleActivity" />
<activity android:name=".DownLoadAPKActivity"/> <activity android:name=".DownLoadAPKActivity" />
<activity android:name=".FragmentInteractiveActivity"/> <activity android:name=".FragmentInteractiveActivity" />
<activity android:name=".FragmentInteractiveActivity2"/> <activity android:name=".FragmentInteractiveActivity2" />
<activity android:name=".PageActivity"/> <activity android:name=".PageActivity" />
<activity android:name=".MyScanActivity" />
</application> </application>
<!-- 配置APP ID --> <!-- 配置APP ID -->
......
package com.mayi.demo;
import com.mayi.fastdevelop.commonpage.zxing.BaseScanActivity;
public class MyScanActivity extends BaseScanActivity{
@Override
public void handleData(String resultString) {
showToast(resultString);
restartPreview();
}
}
...@@ -6,6 +6,8 @@ import android.view.View; ...@@ -6,6 +6,8 @@ import android.view.View;
import com.mayi.fastdevelop.base.BaseActivity; import com.mayi.fastdevelop.base.BaseActivity;
import com.mayi.fastdevelop.commonpage.WebActivity; import com.mayi.fastdevelop.commonpage.WebActivity;
import com.mayi.fastdevelop.commonpage.zxing.BaseScanActivity;
import com.mayi.fastdevelop.util.ToolUtils;
import com.mayi.fastdevelop.view.OnMultiClickListener; import com.mayi.fastdevelop.view.OnMultiClickListener;
public class PageActivity extends BaseActivity { public class PageActivity extends BaseActivity {
...@@ -35,7 +37,7 @@ public class PageActivity extends BaseActivity { ...@@ -35,7 +37,7 @@ public class PageActivity extends BaseActivity {
findViewById(R.id.b3).setOnClickListener(new OnMultiClickListener() { findViewById(R.id.b3).setOnClickListener(new OnMultiClickListener() {
@Override @Override
public void onMultiClick(View v) { public void onMultiClick(View v) {
gotoActivity(DownLoadAPKActivity.class); ToolUtils.goScanActivity(v.getContext(),MyScanActivity.class);
} }
}); });
findViewById(R.id.b4).setOnClickListener(new OnMultiClickListener() { findViewById(R.id.b4).setOnClickListener(new OnMultiClickListener() {
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
android:id="@+id/b3" android:id="@+id/b3"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="下载安装APP" /> android:text="二维码扫描" />
<Button <Button
android:id="@+id/b4" android:id="@+id/b4"
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.mayi.fastdevelop"> package="com.mayi.fastdevelop">
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" /> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
......
package com.mayi.fastdevelop.commonpage.zxing;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.support.annotation.Nullable;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import com.google.zxing.Result;
import com.mayi.fastdevelop.R;
import com.mayi.fastdevelop.base.BaseActivity;
import com.mayi.fastdevelop.commonpage.zxing.camera.CameraManager;
import com.mayi.fastdevelop.commonpage.zxing.decoding.CaptureActivityHandler;
import com.mayi.fastdevelop.commonpage.zxing.decoding.InactivityTimer;
import com.mayi.fastdevelop.commonpage.zxing.view.ViewfinderView;
import com.mayi.fastdevelop.view.CustomTitleBar;
import com.mayi.fastdevelop.view.OnMultiClickListener;
import java.io.IOException;
/**
* 扫描
* 进入页面前要进行权限判断
*/
public abstract class BaseScanActivity extends BaseActivity implements Callback {
private static final long VIBRATE_DURATION = 100L;
private CaptureActivityHandler handler;
private ViewfinderView viewfinderView;
private boolean hasSurface;
private InactivityTimer inactivityTimer;
private boolean vibrate;
private boolean flag = true;
private SurfaceView surfaceView;
CustomTitleBar mCustomTitleBar;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_scanner);
CameraManager.init(getApplicationContext());
hasSurface = false;
inactivityTimer = new InactivityTimer(this);
surfaceView = findViewById(R.id.scanner_view);
viewfinderView = findViewById(R.id.viewfinder_content);
initTitleBar();
}
private void initTitleBar() {
mCustomTitleBar = findViewById(R.id.im_view_title);
mCustomTitleBar.setTextLeft("");
mCustomTitleBar.setTextCenter(getString(R.string.capture));
mCustomTitleBar.setLeftImageResource(R.mipmap.icon_back);
mCustomTitleBar.setOnClickLeftViewListener(new OnMultiClickListener() {
@Override
public void onMultiClick(View v) {
finish();
}
});
mCustomTitleBar.setTextRight(getString(R.string.open_light));
mCustomTitleBar.setOnClickRightTextListener(new OnMultiClickListener() {
@Override
public void onMultiClick(View v) {
light();
}
});
}
/**
* 打开闪光灯
*/
protected void light() {
if (flag) {
flag = false;
CameraManager.get().openLight();
mCustomTitleBar.setTextRight(getString(R.string.close_light));
} else {
flag = true;
CameraManager.get().offLight();
mCustomTitleBar.setTextRight(getString(R.string.open_light));
}
}
@Override
protected void onResume() {
super.onResume();
SurfaceHolder surfaceHolder = surfaceView.getHolder();
if (hasSurface) {
initCamera(surfaceHolder);
} else {
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
vibrate = true;
}
@Override
protected void onPause() {
if (handler != null) {
handler.quitSynchronously();
handler = null;
}
CameraManager.get().closeDriver();
if (!hasSurface) {
SurfaceHolder surfaceHolder = surfaceView.getHolder();
surfaceHolder.removeCallback(this);
}
super.onPause();
}
@Override
protected void onDestroy() {
super.onDestroy();
inactivityTimer.shutdown();
}
/**
* 处理程序扫描结果
*/
public void handleDecode(Result result) {
inactivityTimer.onActivity();
playBeepSoundAndVibrate();
handleData(result.getText());
}
public abstract void handleData(String resultString);
/**
* 重启扫描
*/
public void restartPreview() {
Message message = new Message();
message.what = R.id.restart_preview;
if (handler == null) handler = new CaptureActivityHandler(this);
handler.sendMessageDelayed(message, 2000);
}
private void initCamera(SurfaceHolder surfaceHolder) {
try {
CameraManager.get().openDriver(surfaceHolder);
} catch (IOException ioe) {
return;
} catch (RuntimeException e) {
e.printStackTrace();
Toast.makeText(this, getString(R.string.error_take_photo), Toast.LENGTH_LONG).show();
return;
}
if (handler == null) {
handler = new CaptureActivityHandler(this);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!hasSurface) {
hasSurface = true;
initCamera(holder);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
hasSurface = false;
}
public Handler getHandler() {
return handler;
}
public void drawViewfinder() {
viewfinderView.drawViewfinder();
}
private void playBeepSoundAndVibrate() {
if (vibrate) {
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
if (vibrator != null) {
vibrator.vibrate(VIBRATE_DURATION);
}
}
}
}
\ No newline at end of file
package com.mayi.fastdevelop.commonpage.zxing.camera;
import android.hardware.Camera;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
final class AutoFocusCallback implements Camera.AutoFocusCallback {
private static final String TAG = AutoFocusCallback.class.getSimpleName();
private static final long AUTOFOCUS_INTERVAL_MS = 1000L;
private Handler autoFocusHandler;
private int autoFocusMessage;
void setHandler(Handler autoFocusHandler, int autoFocusMessage) {
this.autoFocusHandler = autoFocusHandler;
this.autoFocusMessage = autoFocusMessage;
}
public void onAutoFocus(boolean success, Camera camera) {
if (autoFocusHandler != null) {
Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
autoFocusHandler.sendMessageDelayed(message, AUTOFOCUS_INTERVAL_MS);
autoFocusHandler = null;
} else {
Log.d(TAG, "Got auto-focus callback, but no handler for it");
}
}
}
package com.mayi.fastdevelop.commonpage.zxing.camera;
import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import java.util.regex.Pattern;
final class CameraConfigurationManager {
private static final String TAG = CameraConfigurationManager.class.getSimpleName();
private static final int TEN_DESIRED_ZOOM = 27;
private static final Pattern COMMA_PATTERN = Pattern.compile(",");
private final Context context;
private Point screenResolution;
private Point cameraResolution;
private int previewFormat;
private String previewFormatString;
CameraConfigurationManager(Context context) {
this.context = context;
}
/**
* Reads, one time, values from the camera that are needed by the app.
*/
void initFromCameraParameters(Camera camera) {
Camera.Parameters parameters = camera.getParameters();
previewFormat = parameters.getPreviewFormat();
previewFormatString = parameters.get("preview-format");
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (manager != null) {
Display display = manager.getDefaultDisplay();
screenResolution = new Point(display.getWidth(), display.getHeight());
}
//图片拉伸
Point screenResolutionForCamera = new Point();
screenResolutionForCamera.x = screenResolution.x;
screenResolutionForCamera.y = screenResolution.y;
// preview size is always something like 480*320, other 320*480
if (screenResolution.x < screenResolution.y) {
screenResolutionForCamera.x = screenResolution.y;
screenResolutionForCamera.y = screenResolution.x;
}
cameraResolution = getCameraResolution(parameters, screenResolutionForCamera);
Log.d(TAG, "Camera resolution: " + screenResolution);
}
/**
* Sets the camera up to take preview images which are used for both preview and decoding.
* We detect the preview format here so that buildLuminanceSource() can build an appropriate
* LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
* and the planar Y can be used for barcode scanning without a copy in some cases.
*/
void setDesiredCameraParameters(Camera camera) {
Camera.Parameters parameters = camera.getParameters();
Log.d(TAG, "Setting preview size: " + cameraResolution);
parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
setFlash(parameters);
setZoom(parameters);
//setSharpness(parameters);
//modify here
camera.setDisplayOrientation(90);
camera.setParameters(parameters);
}
Point getCameraResolution() {
return cameraResolution;
}
Point getScreenResolution() {
return screenResolution;
}
int getPreviewFormat() {
return previewFormat;
}
String getPreviewFormatString() {
return previewFormatString;
}
private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) {
String previewSizeValueString = parameters.get("preview-size-values");
// saw this on Xperia
if (previewSizeValueString == null) {
previewSizeValueString = parameters.get("preview-size-value");
}
Point cameraResolution = null;
if (previewSizeValueString != null) {
Log.d(TAG, "preview-size-values parameter: " + previewSizeValueString);
cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
}
if (cameraResolution == null) {
// Ensure that the camera resolution is a multiple of 8, as the screen may not be.
cameraResolution = new Point(
(screenResolution.x >> 3) << 3,
(screenResolution.y >> 3) << 3);
}
return cameraResolution;
}
/**
* 获取匹配到的最合适的屏幕尺寸 防止图片变形
*/
private static Point findBestPreviewSizeValue(CharSequence previewSizeValueString, Point screenResolution) {
int bestX = 0;
int bestY = 0;
int diff = Integer.MAX_VALUE;
for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {
previewSize = previewSize.trim();
int dimPosition = previewSize.indexOf('x');
if (dimPosition < 0) {
Log.w(TAG, "Bad preview-size: " + previewSize);
continue;
}
int newX;
int newY;
try {
newX = Integer.parseInt(previewSize.substring(0, dimPosition));
newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
} catch (NumberFormatException nfe) {
Log.w(TAG, "Bad preview-size: " + previewSize);
continue;
}
int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
if (newDiff == 0) {
bestX = newX;
bestY = newY;
break;
} else if (newDiff < diff) {
bestX = newX;
bestY = newY;
diff = newDiff;
}
}
Log.i("ANT","bestX="+bestX+" bestY="+bestY);
if (bestX > 0 && bestY > 0) {
return new Point(bestX, bestY);
}
return null;
}
private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) {
int tenBestValue = 0;
for (String stringValue : COMMA_PATTERN.split(stringValues)) {
stringValue = stringValue.trim();
double value;
try {
value = Double.parseDouble(stringValue);
} catch (NumberFormatException nfe) {
return tenDesiredZoom;
}
int tenValue = (int) (10.0 * value);
if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
tenBestValue = tenValue;
}
}
return tenBestValue;
}
private void setFlash(Camera.Parameters parameters) {
// And this is a hack-hack to work around a different value on the Behold II
// Restrict Behold II check to Cupcake, per Samsung's advice
//if (Build.MODEL.contains("Behold II") &&
// CameraManager.SDK_INT == Build.VERSION_CODES.CUPCAKE) {
if (Build.MODEL.contains("Behold II") && CameraManager.SDK_INT == 3) { // 3 = Cupcake
parameters.set("flash-value", 1);
} else {
parameters.set("flash-value", 2);
}
// This is the standard setting to turn the flash off that all devices should honor.
parameters.set("flash-mode", "off");
}
private void setZoom(Camera.Parameters parameters) {
String zoomSupportedString = parameters.get("zoom-supported");
if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
return;
}
int tenDesiredZoom = TEN_DESIRED_ZOOM;
String maxZoomString = parameters.get("max-zoom");
if (maxZoomString != null) {
try {
int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
if (tenDesiredZoom > tenMaxZoom) {
tenDesiredZoom = tenMaxZoom;
}
} catch (NumberFormatException nfe) {
Log.w(TAG, "Bad max-zoom: " + maxZoomString);
}
}
String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
if (takingPictureZoomMaxString != null) {
try {
int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
if (tenDesiredZoom > tenMaxZoom) {
tenDesiredZoom = tenMaxZoom;
}
} catch (NumberFormatException nfe) {
Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
}
}
String motZoomValuesString = parameters.get("mot-zoom-values");
if (motZoomValuesString != null) {
tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
}
String motZoomStepString = parameters.get("mot-zoom-step");
if (motZoomStepString != null) {
try {
double motZoomStep = Double.parseDouble(motZoomStepString.trim());
int tenZoomStep = (int) (10.0 * motZoomStep);
if (tenZoomStep > 1) {
tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
}
} catch (NumberFormatException nfe) {
// continue
}
}
// Set zoom. This helps encourage the user to pull back.
// Some devices like the Behold have a zoom parameter
if (maxZoomString != null || motZoomValuesString != null) {
parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
}
// Most devices, like the Hero, appear to expose this zoom parameter.
// It takes on values like "27" which appears to mean 2.7x zoom
if (takingPictureZoomMaxString != null) {
parameters.set("taking-picture-zoom", tenDesiredZoom);
}
}
}
package com.mayi.fastdevelop.commonpage.zxing.camera;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Build;
import android.os.Handler;
import android.view.SurfaceHolder;
import java.io.IOException;
/**
* This object wraps the Camera service object and expects to be the only one talking to it. The
* implementation encapsulates the steps needed to take preview-sized images, which are used for
* both preview and decoding.
*/
public final class CameraManager {
private static CameraManager cameraManager;
private Camera.Parameters parameter;
private final Context context;
private final CameraConfigurationManager configManager;
private Camera camera;
private Rect framingRect;
private Rect framingRectInPreview;
private boolean initialized;
private boolean previewing;
private final boolean useOneShotPreviewCallback;
private final PreviewCallback previewCallback;
private final AutoFocusCallback autoFocusCallback;
static final int SDK_INT; // Later we can use Build.VERSION.SDK_INT
static {
int sdkInt;
try {
sdkInt = Integer.parseInt(Build.VERSION.SDK);
} catch (NumberFormatException nfe) {
sdkInt = 10000;
}
SDK_INT = sdkInt;
}
public static void init(Context context) {
if (cameraManager == null) {
cameraManager = new CameraManager(context);
}
}
public static CameraManager get() {
return cameraManager;
}
private CameraManager(Context context) {
this.context = context;
this.configManager = new CameraConfigurationManager(context);
useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > 3; // 3 = Cupcake
previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback);
autoFocusCallback = new AutoFocusCallback();
}
public void openDriver(SurfaceHolder holder) throws IOException {
if (camera == null) {
camera = Camera.open();
if (camera == null) {
throw new IOException();
}
camera.setPreviewDisplay(holder);
if (!initialized) {
initialized = true;
configManager.initFromCameraParameters(camera);
}
configManager.setDesiredCameraParameters(camera);
FlashlightManager.enableFlashlight();
}
}
public void closeDriver() {
if (camera != null) {
FlashlightManager.disableFlashlight();
camera.release();
camera = null;
}
}
/**
* Asks the camera hardware to begin drawing preview frames to the screen.
*/
public void startPreview() {
if (camera != null && !previewing) {
try {
camera.startPreview();
previewing = true;
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
/**
* Tells the camera to stop drawing preview frames.
*/
public void stopPreview() {
if (camera != null && previewing) {
if (!useOneShotPreviewCallback) {
camera.setPreviewCallback(null);
}
camera.stopPreview();
previewCallback.setHandler(null, 0);
autoFocusCallback.setHandler(null, 0);
previewing = false;
}
}
/**
* A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
* in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
* respectively.
*
* @param handler The handler to send the message to.
* @param message The what field of the message to be sent.
*/
public void requestPreviewFrame(Handler handler, int message) {
if (camera != null && previewing) {
previewCallback.setHandler(handler, message);
if (useOneShotPreviewCallback) {
camera.setOneShotPreviewCallback(previewCallback);
} else {
camera.setPreviewCallback(previewCallback);
}
}
}
public void requestAutoFocus(Handler handler, int message) {
if (camera != null && previewing) {
autoFocusCallback.setHandler(handler, message);
camera.autoFocus(autoFocusCallback);
}
}
public void openLight() {
if (camera != null) {
parameter = camera.getParameters();
parameter.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameter);
}
}
public void offLight() {
if (camera != null) {
parameter = camera.getParameters();
parameter.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(parameter);
}
}
/**
* Calculates the framing rect which the UI should draw to show the user where to place the
* barcode. This target helps with alignment as well as forces the user to hold the device
* far enough away to ensure the image will be in focus.
*
* @return The rectangle to draw on screen in window coordinates.
*/
public Rect getFramingRect() {
Point screenResolution = configManager.getScreenResolution();
if (screenResolution == null)
return null;
if (framingRect == null) {
if (camera == null) {
return null;
}
//修改扫描框大小
int leng = screenResolution.x > screenResolution.y ? screenResolution.y : screenResolution.x;
leng = leng * 7 / 10;
int leftOffset = (screenResolution.x - leng) / 2;
int topOffset = (screenResolution.y - leng) / 3;
framingRect = new Rect(leftOffset, topOffset, leftOffset + leng, topOffset + leng);
}
return framingRect;
}
/**
* Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
* not UI / screen.
*/
public Rect getFramingRectInPreview() {
if (framingRectInPreview == null) {
Rect rect = new Rect(getFramingRect());
Point cameraResolution = configManager.getCameraResolution();
Point screenResolution = configManager.getScreenResolution();
rect.left = rect.left * cameraResolution.y / screenResolution.x;
rect.right = rect.right * cameraResolution.y / screenResolution.x;
rect.top = rect.top * cameraResolution.x / screenResolution.y;
rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
framingRectInPreview = rect;
}
return framingRectInPreview;
}
/**
* A factory method to build the appropriate LuminanceSource object based on the format
* of the preview buffers, as described by Camera.Parameters.
*
* @param data A preview frame.
* @param width The width of the image.
* @param height The height of the image.
* @return A PlanarYUVLuminanceSource instance.
*/
public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
Rect rect = getFramingRectInPreview();
int previewFormat = configManager.getPreviewFormat();
String previewFormatString = configManager.getPreviewFormatString();
switch (previewFormat) {
// This is the standard Android format which all devices are REQUIRED to support.
// In theory, it's the only one we should ever care about.
case PixelFormat.YCbCr_420_SP:
// This format has never been seen in the wild, but is compatible as we only care
// about the Y channel, so allow it.
case PixelFormat.YCbCr_422_SP:
return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height());
default:
// The Samsung Moment incorrectly uses this variant instead of the 'sp' version.
// Fortunately, it too has all the Y data up front, so we can read it.
if ("yuv420p".equals(previewFormatString)) {
return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top,
rect.width(), rect.height());
}
}
throw new IllegalArgumentException("Unsupported picture format: " +
previewFormat + '/' + previewFormatString);
}
}
package com.mayi.fastdevelop.commonpage.zxing.camera;
import android.os.IBinder;
import android.util.Log;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* This class is used to activate the weak light on some camera phones (not flash)
* in order to illuminate surfaces for scanning. There is no official way to do this,
* but, classes which allow access to this function still exist on some devices.
* This therefore proceeds through a great deal of reflection.
* <p>
* See <a href="http://almondmendoza.com/2009/01/05/changing-the-screen-brightness-programatically/">
* http://almondmendoza.com/2009/01/05/changing-the-screen-brightness-programatically/</a> and
* <a href="http://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java">
* http://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java</a>.
* Thanks to Ryan Alford for pointing out the availability of this class.
*/
final class FlashlightManager {
private static final String TAG = FlashlightManager.class.getSimpleName();
private static final Object iHardwareService;
private static final Method setFlashEnabledMethod;
static {
iHardwareService = getHardwareService();
setFlashEnabledMethod = getSetFlashEnabledMethod(iHardwareService);
if (iHardwareService == null) {
Log.v(TAG, "This device does supports control of a flashlight");
} else {
Log.v(TAG, "This device does not support control of a flashlight");
}
}
private FlashlightManager() {
}
static void enableFlashlight() {
setFlashlight(false);
}
static void disableFlashlight() {
setFlashlight(false);
}
private static Object getHardwareService() {
Class<?> serviceManagerClass = maybeForName("android.os.ServiceManager");
if (serviceManagerClass == null) {
return null;
}
Method getServiceMethod = maybeGetMethod(serviceManagerClass, "getService", String.class);
if (getServiceMethod == null) {
return null;
}
Object hardwareService = invoke(getServiceMethod, null, "hardware");
if (hardwareService == null) {
return null;
}
Class<?> iHardwareServiceStubClass = maybeForName("android.os.IHardwareService$Stub");
if (iHardwareServiceStubClass == null) {
return null;
}
Method asInterfaceMethod = maybeGetMethod(iHardwareServiceStubClass, "asInterface", IBinder.class);
if (asInterfaceMethod == null) {
return null;
}
return invoke(asInterfaceMethod, null, hardwareService);
}
private static Method getSetFlashEnabledMethod(Object iHardwareService) {
if (iHardwareService == null) {
return null;
}
Class<?> proxyClass = iHardwareService.getClass();
return maybeGetMethod(proxyClass, "setFlashlightEnabled", boolean.class);
}
private static Class<?> maybeForName(String name) {
try {
return Class.forName(name);
} catch (ClassNotFoundException cnfe) {
// OK
return null;
} catch (RuntimeException re) {
Log.w(TAG, "Unexpected error while finding class " + name, re);
return null;
}
}
private static Method maybeGetMethod(Class<?> clazz, String name, Class<?>... argClasses) {
try {
return clazz.getMethod(name, argClasses);
} catch (NoSuchMethodException nsme) {
// OK
return null;
} catch (RuntimeException re) {
Log.w(TAG, "Unexpected error while finding method " + name, re);
return null;
}
}
private static Object invoke(Method method, Object instance, Object... args) {
try {
return method.invoke(instance, args);
} catch (IllegalAccessException e) {
Log.w(TAG, "Unexpected error while invoking " + method, e);
return null;
} catch (InvocationTargetException e) {
Log.w(TAG, "Unexpected error while invoking " + method, e.getCause());
return null;
} catch (RuntimeException re) {
Log.w(TAG, "Unexpected error while invoking " + method, re);
return null;
}
}
private static void setFlashlight(boolean active) {
if (iHardwareService != null) {
invoke(setFlashEnabledMethod, iHardwareService, active);
}
}
}
package com.mayi.fastdevelop.commonpage.zxing.camera;
import com.google.zxing.LuminanceSource;
public final class PlanarYUVLuminanceSource extends LuminanceSource {
private final byte[] yuvData;
private final int dataWidth;
private final int dataHeight;
private final int left;
private final int top;
public PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dataHeight, int left, int top,
int width, int height) {
super(width, height);
if (left + width > dataWidth || top + height > dataHeight) {
throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
}
this.yuvData = yuvData;
this.dataWidth = dataWidth;
this.dataHeight = dataHeight;
this.left = left;
this.top = top;
}
@Override
public byte[] getRow(int y, byte[] row) {
if (y < 0 || y >= getHeight()) {
throw new IllegalArgumentException("Requested row is outside the image: " + y);
}
int width = getWidth();
if (row == null || row.length < width) {
row = new byte[width];
}
int offset = (y + top) * dataWidth + left;
System.arraycopy(yuvData, offset, row, 0, width);
return row;
}
@Override
public byte[] getMatrix() {
int width = getWidth();
int height = getHeight();
// If the caller asks for the entire underlying image, save the copy and give them the
// original data. The docs specifically warn that result.length must be ignored.
if (width == dataWidth && height == dataHeight) {
return yuvData;
}
int area = width * height;
byte[] matrix = new byte[area];
int inputOffset = top * dataWidth + left;
// If the width matches the full width of the underlying data, perform a single copy.
if (width == dataWidth) {
System.arraycopy(yuvData, inputOffset, matrix, 0, area);
return matrix;
}
// Otherwise copy one cropped row at a time.
byte[] yuv = yuvData;
for (int y = 0; y < height; y++) {
int outputOffset = y * width;
System.arraycopy(yuv, inputOffset, matrix, outputOffset, width);
inputOffset += dataWidth;
}
return matrix;
}
@Override
public boolean isCropSupported() {
return true;
}
}
package com.mayi.fastdevelop.commonpage.zxing.camera;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
final class PreviewCallback implements Camera.PreviewCallback {
private static final String TAG = PreviewCallback.class.getSimpleName();
private final CameraConfigurationManager configManager;
private final boolean useOneShotPreviewCallback;
private Handler previewHandler;
private int previewMessage;
PreviewCallback(CameraConfigurationManager configManager, boolean useOneShotPreviewCallback) {
this.configManager = configManager;
this.useOneShotPreviewCallback = useOneShotPreviewCallback;
}
void setHandler(Handler previewHandler, int previewMessage) {
this.previewHandler = previewHandler;
this.previewMessage = previewMessage;
}
public void onPreviewFrame(byte[] data, Camera camera) {
Point cameraResolution = configManager.getCameraResolution();
if (!useOneShotPreviewCallback) {
camera.setPreviewCallback(null);
}
if (previewHandler != null) {
Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,
cameraResolution.y, data);
message.sendToTarget();
previewHandler = null;
} else {
Log.d(TAG, "Got preview callback, but no handler for it");
}
}
}
package com.mayi.fastdevelop.commonpage.zxing.decoding;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.google.zxing.Result;
import com.mayi.fastdevelop.R;
import com.mayi.fastdevelop.commonpage.zxing.BaseScanActivity;
import com.mayi.fastdevelop.commonpage.zxing.camera.CameraManager;
/**
* This class handles all the messaging which comprises the state machine for capture.
*/
public final class CaptureActivityHandler extends Handler {
private static final String TAG = CaptureActivityHandler.class.getSimpleName();
private final BaseScanActivity activity;
private final DecodeThread decodeThread;
private State state;
private enum State {
PREVIEW,
SUCCESS,
DONE
}
public CaptureActivityHandler(BaseScanActivity activity) {
this.activity = activity;
decodeThread = new DecodeThread(activity);
decodeThread.start();
state = State.SUCCESS;
// Start ourselves capturing previews and decoding.
CameraManager.get().startPreview();
restartPreviewAndDecode();
}
@Override
public void handleMessage(Message message) {
int id = message.what;
if (id == R.id.auto_focus) {
if (state == State.PREVIEW) {
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
}
} else if (id == R.id.restart_preview) {
Log.d(TAG, "Got restart preview message");
restartPreviewAndDecode();
} else if (id == R.id.decode_succeeded) {
Log.d(TAG, "Got decode succeeded message");
state = State.SUCCESS;
activity.handleDecode((Result) message.obj);
} else if (id == R.id.decode_failed) {
// We're decoding as fast as possible, so when one decode fails, startBaiduVoice another.
state = State.PREVIEW;
CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
} else if (id == R.id.return_scan_result) {
Log.d(TAG, "Got return scan result message");
activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
activity.finish();
} else if (id == R.id.launch_product_query) {
Log.d(TAG, "Got product query message");
String url = (String) message.obj;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
activity.startActivity(intent);
}
}
public void quitSynchronously() {
state = State.DONE;
CameraManager.get().stopPreview();
Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
quit.sendToTarget();
try {
decodeThread.join();
} catch (InterruptedException e) {
// continue
}
// Be absolutely sure we don't send any queued up messages
removeMessages(R.id.decode_succeeded);
removeMessages(R.id.decode_failed);
}
private void restartPreviewAndDecode() {
if (state == State.SUCCESS) {
state = State.PREVIEW;
CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
activity.drawViewfinder();
}
}
}
package com.mayi.fastdevelop.commonpage.zxing.decoding;
import android.content.Intent;
import android.net.Uri;
import com.google.zxing.BarcodeFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import java.util.regex.Pattern;
final class DecodeFormatManager {
static final Vector<BarcodeFormat> PRODUCT_FORMATS;
static final Vector<BarcodeFormat> ONE_D_FORMATS;
static final Vector<BarcodeFormat> QR_CODE_FORMATS;
static final Vector<BarcodeFormat> DATA_MATRIX_FORMATS;
private static final Pattern COMMA_PATTERN = Pattern.compile(",");
static {
PRODUCT_FORMATS = new Vector<BarcodeFormat>(5);
PRODUCT_FORMATS.add(BarcodeFormat.UPC_A);
PRODUCT_FORMATS.add(BarcodeFormat.UPC_E);
PRODUCT_FORMATS.add(BarcodeFormat.EAN_13);
PRODUCT_FORMATS.add(BarcodeFormat.EAN_8);
PRODUCT_FORMATS.add(BarcodeFormat.RSS_14);
ONE_D_FORMATS = new Vector<BarcodeFormat>(PRODUCT_FORMATS.size() + 4);
ONE_D_FORMATS.addAll(PRODUCT_FORMATS);
ONE_D_FORMATS.add(BarcodeFormat.CODE_39);
ONE_D_FORMATS.add(BarcodeFormat.CODE_93);
ONE_D_FORMATS.add(BarcodeFormat.CODE_128);
ONE_D_FORMATS.add(BarcodeFormat.ITF);
QR_CODE_FORMATS = new Vector<BarcodeFormat>(1);
QR_CODE_FORMATS.add(BarcodeFormat.QR_CODE);
DATA_MATRIX_FORMATS = new Vector<BarcodeFormat>(1);
DATA_MATRIX_FORMATS.add(BarcodeFormat.DATA_MATRIX);
}
private DecodeFormatManager() {
}
static Vector<BarcodeFormat> parseDecodeFormats(Intent intent) {
List<String> scanFormats = null;
String scanFormatsString = intent.getStringExtra(Intents.Scan.SCAN_FORMATS);
if (scanFormatsString != null) {
scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));
}
return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE));
}
static Vector<BarcodeFormat> parseDecodeFormats(Uri inputUri) {
List<String> formats = inputUri.getQueryParameters(Intents.Scan.SCAN_FORMATS);
if (formats != null && formats.size() == 1 && formats.get(0) != null) {
formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));
}
return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE));
}
private static Vector<BarcodeFormat> parseDecodeFormats(Iterable<String> scanFormats,
String decodeMode) {
if (scanFormats != null) {
Vector<BarcodeFormat> formats = new Vector<BarcodeFormat>();
try {
for (String format : scanFormats) {
formats.add(BarcodeFormat.valueOf(format));
}
return formats;
} catch (IllegalArgumentException iae) {
// ignore it then
}
}
if (decodeMode != null) {
if (Intents.Scan.PRODUCT_MODE.equals(decodeMode)) {
return PRODUCT_FORMATS;
}
if (Intents.Scan.QR_CODE_MODE.equals(decodeMode)) {
return QR_CODE_FORMATS;
}
if (Intents.Scan.DATA_MATRIX_MODE.equals(decodeMode)) {
return DATA_MATRIX_FORMATS;
}
if (Intents.Scan.ONE_D_MODE.equals(decodeMode)) {
return ONE_D_FORMATS;
}
}
return null;
}
}
package com.mayi.fastdevelop.commonpage.zxing.decoding;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.mayi.fastdevelop.R;
import com.mayi.fastdevelop.commonpage.zxing.BaseScanActivity;
import com.mayi.fastdevelop.commonpage.zxing.camera.CameraManager;
import com.mayi.fastdevelop.commonpage.zxing.camera.PlanarYUVLuminanceSource;
final class DecodeHandler extends Handler {
private static final String TAG = DecodeHandler.class.getSimpleName();
private final BaseScanActivity activity;
private final QRCodeReader mQRCodeReader;
DecodeHandler(BaseScanActivity activity) {
this.activity = activity;
this.mQRCodeReader = new QRCodeReader();
}
@Override
public void handleMessage(Message message) {
int id = message.what;
if (id == R.id.decode) {
decode((byte[]) message.obj, message.arg1, message.arg2);
} else if (id == R.id.quit) {
if (Looper.myLooper() != null) {
Looper.myLooper().quit();
}
}
}
/**
* Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
* reuse the same reader objects from one decode to the next.
*
* @param data The YUV preview frame.
* @param width The width of the preview frame.
* @param height The height of the preview frame.
*/
private void decode(byte[] data, int width, int height) {
long start = System.currentTimeMillis();
Result rawResult = null;
//modify here
byte[] rotatedData = new byte[data.length];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++)
rotatedData[x * height + height - y - 1] = data[x + y * width];
}
int tmp = width; // Here we are swapping, that's the difference to #11
width = height;
height = tmp;
PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height);
if (source != null) {
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
try {
rawResult = mQRCodeReader.decode(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
}
if (rawResult != null) {
long end = System.currentTimeMillis();
Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
Message message = Message.obtain(activity.getHandler(), R.id.decode_succeeded, rawResult);
message.sendToTarget();
} else {
Message message = Message.obtain(activity.getHandler(), R.id.decode_failed);
message.sendToTarget();
}
}
}
package com.mayi.fastdevelop.commonpage.zxing.decoding;
import android.os.Handler;
import android.os.Looper;
import com.mayi.fastdevelop.commonpage.zxing.BaseScanActivity;
import java.util.concurrent.CountDownLatch;
final class DecodeThread extends Thread {
private final BaseScanActivity activity;
private Handler handler;
private final CountDownLatch handlerInitLatch;
DecodeThread(BaseScanActivity activity) {
this.activity = activity;
handlerInitLatch = new CountDownLatch(1);
}
Handler getHandler() {
try {
handlerInitLatch.await();
} catch (InterruptedException ie) {
// continue?
}
return handler;
}
@Override
public void run() {
Looper.prepare();
handler = new DecodeHandler(activity);
handlerInitLatch.countDown();
Looper.loop();
}
}
package com.mayi.fastdevelop.commonpage.zxing.decoding;
import android.app.Activity;
import android.content.DialogInterface;
/**
* Simple listener used to exit the app in a few cases.
*/
public final class FinishListener
implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener, Runnable {
private final Activity activityToFinish;
public FinishListener(Activity activityToFinish) {
this.activityToFinish = activityToFinish;
}
public void onCancel(DialogInterface dialogInterface) {
run();
}
public void onClick(DialogInterface dialogInterface, int i) {
run();
}
public void run() {
activityToFinish.finish();
}
}
package com.mayi.fastdevelop.commonpage.zxing.decoding;
import android.app.Activity;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* 扫描静默等待时间控制
*/
public final class InactivityTimer {
private static final int INACTIVITY_DELAY_SECONDS = 3 * 60; //默认无操作最多等待时间
private final ScheduledExecutorService inactivityTimer = Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory());
private final Activity activity;
private ScheduledFuture<?> inactivityFuture = null;
public InactivityTimer(Activity activity) {
this.activity = activity;
onActivity();
}
public void onActivity() {
cancel();
inactivityFuture = inactivityTimer.schedule(new FinishListener(activity),
INACTIVITY_DELAY_SECONDS,
TimeUnit.SECONDS);
}
private void cancel() {
if (inactivityFuture != null) {
inactivityFuture.cancel(true);
inactivityFuture = null;
}
}
public void shutdown() {
cancel();
inactivityTimer.shutdown();
}
private static final class DaemonThreadFactory implements ThreadFactory {
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable);
thread.setDaemon(true);
return thread;
}
}
}
\ No newline at end of file
package com.mayi.fastdevelop.commonpage.zxing.decoding;
/**
* This class provides the constants to use when sending an Intent to Barcode Scanner.
* These strings are effectively API and cannot be changed.
*/
public final class Intents {
private Intents() {
}
public static final class Scan {
/**
* Send this intent to open the Barcodes app in scanning mode, find a barcode, and return
* the results.
*/
public static final String ACTION = "com.google.zxing.client.android.SCAN";
/**
* By default, sending Scan.ACTION will decode all barcodes that we understand. However it
* may be useful to limit scanning to certain formats. Use Intent.putExtra(MODE, value) with
* one of the values below ({@link #PRODUCT_MODE}, {@link #ONE_D_MODE}, {@link #QR_CODE_MODE}).
* Optional.
* <p>
* Setting this is effectively shorthnad for setting explicit formats with {@link #SCAN_FORMATS}.
* It is overridden by that setting.
*/
public static final String MODE = "SCAN_MODE";
/**
* Comma-separated list of formats to scan for. The values must match the names of
* {@link com.google.zxing.BarcodeFormat}s, such as {@link com.google.zxing.BarcodeFormat#EAN_13}.
* Example: "EAN_13,EAN_8,QR_CODE"
* <p>
* This overrides {@link #MODE}.
*/
public static final String SCAN_FORMATS = "SCAN_FORMATS";
/**
* @see com.google.zxing.DecodeHintType#CHARACTER_SET
*/
public static final String CHARACTER_SET = "CHARACTER_SET";
/**
* Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get
* prices, reviews, etc. for products.
*/
public static final String PRODUCT_MODE = "PRODUCT_MODE";
/**
* Decode only 1D barcodes (currently UPC, EAN, Code 39, and Code 128).
*/
public static final String ONE_D_MODE = "ONE_D_MODE";
/**
* Decode only QR codes.
*/
public static final String QR_CODE_MODE = "QR_CODE_MODE";
/**
* Decode only Data Matrix codes.
*/
public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE";
/**
* If a barcode is found, Barcodes returns RESULT_OK to onActivityResult() of the app which
* requested the scan via startSubActivity(). The barcodes contents can be retrieved with
* intent.getStringExtra(RESULT). If the user presses Back, the result code will be
* RESULT_CANCELED.
*/
public static final String RESULT = "SCAN_RESULT";
/**
* Call intent.getStringExtra(RESULT_FORMAT) to determine which barcode format was found.
* See Contents.Format for possible values.
*/
public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT";
/**
* Setting this to false will not save scanned codes in the history.
*/
public static final String SAVE_HISTORY = "SAVE_HISTORY";
private Scan() {
}
}
public static final class Encode {
/**
* Send this intent to encode a piece of data as a QR code and display it full screen, so
* that another person can scan the barcode from your screen.
*/
public static final String ACTION = "com.google.zxing.client.android.ENCODE";
/**
* The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a
* Bundle, depending on the type and format specified. Non-QR Code formats should
* just use a String here. For QR Code, see Contents for details.
*/
public static final String DATA = "ENCODE_DATA";
/**
* The type of data being supplied if the format is QR Code. Use
* Intent.putExtra(TYPE, type) with one of Contents.Type.
*/
public static final String TYPE = "ENCODE_TYPE";
/**
* The barcode format to be displayed. If this isn't specified or is blank,
* it defaults to QR Code. Use Intent.putExtra(FORMAT, format), where
* format is one of Contents.Format.
*/
public static final String FORMAT = "ENCODE_FORMAT";
private Encode() {
}
}
public static final class SearchBookContents {
/**
* Use Google Book Search to search the contents of the book provided.
*/
public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";
/**
* The book to search, identified by ISBN number.
*/
public static final String ISBN = "ISBN";
/**
* An optional field which is the text to search for.
*/
public static final String QUERY = "QUERY";
private SearchBookContents() {
}
}
public static final class WifiConnect {
/**
* Internal intent used to trigger connection to a wi-fi network.
*/
public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT";
/**
* The network to connect to, all the configuration provided here.
*/
public static final String SSID = "SSID";
/**
* The network to connect to, all the configuration provided here.
*/
public static final String TYPE = "TYPE";
/**
* The network to connect to, all the configuration provided here.
*/
public static final String PASSWORD = "PASSWORD";
private WifiConnect() {
}
}
public static final class Share {
/**
* Give the user a choice of items to encode as a barcode, then render it as a QR Code and
* display onscreen for a friend to scan with their phone.
*/
public static final String ACTION = "com.google.zxing.client.android.SHARE";
private Share() {
}
}
}
package com.mayi.fastdevelop.commonpage.zxing.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
import com.google.zxing.ResultPoint;
import com.mayi.fastdevelop.R;
import com.mayi.fastdevelop.commonpage.zxing.camera.CameraManager;
import java.util.Collection;
import java.util.HashSet;
public final class ViewfinderView extends View {
private static final long ANIMATION_DELAY = 10L;
private static final int OPAQUE = 0xFF;
private static final int CORNER_RECT_WIDTH = 8; //扫描区边角的宽
private static final int CORNER_RECT_HEIGHT = 40; //扫描区边角的高
private static final int SCANNER_LINE_MOVE_DISTANCE = 5; //扫描线移动距离
private static final int SCANNER_LINE_HEIGHT = 10; //扫描线宽度
private final Paint paint;
private Bitmap resultBitmap;
//模糊区域颜色
private final int maskColor;
private final int resultColor;
//扫描区域边框颜色
private final int frameColor;
//扫描线颜色
private final int laserColor;
//四角颜色
private final int cornerColor;
//扫描点的颜色
private final int resultPointColor;
//扫描区域提示文本
private final String labelText;
//扫描区域提示文本颜色
private final int labelTextColor;
private final float labelTextSize;
public static int scannerStart = 0;
public static int scannerEnd = 0;
private Collection<ResultPoint> possibleResultPoints;
private Collection<ResultPoint> lastPossibleResultPoints;
// This constructor is used when the class is built from an XML resource.
public ViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs);
//初始化自定义属性信息
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView);
laserColor = array.getColor(R.styleable.ViewfinderView_laser_color, 0x00FF00);
cornerColor = array.getColor(R.styleable.ViewfinderView_corner_color, 0x00FF00);
frameColor = array.getColor(R.styleable.ViewfinderView_frame_color, 0xFFFFFF);
resultPointColor = array.getColor(R.styleable.ViewfinderView_result_point_color, 0xC0FFFF00);
maskColor = array.getColor(R.styleable.ViewfinderView_mask_color, 0x60000000);
resultColor = array.getColor(R.styleable.ViewfinderView_result_color, 0xB0000000);
labelTextColor = array.getColor(R.styleable.ViewfinderView_label_text_color, 0x90FFFFFF);
labelText = array.getString(R.styleable.ViewfinderView_label_text);
labelTextSize = array.getFloat(R.styleable.ViewfinderView_label_text_size, 36f);
// Initialize these once for performance rather than calling them every time in onDraw().
paint = new Paint();
paint.setAntiAlias(true);
possibleResultPoints = new HashSet<>(5);
}
@Override
public void onDraw(Canvas canvas) {
Rect frame = CameraManager.get().getFramingRect();
if (frame == null) {
return;
}
if (scannerStart == 0 || scannerEnd == 0) {
scannerStart = frame.top;
scannerEnd = frame.bottom;
}
int width = canvas.getWidth();
int height = canvas.getHeight();
// Draw the exterior (i.e. outside the framing rect) darkened
drawExterior(canvas, frame, width, height);
if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle
paint.setAlpha(OPAQUE);
canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
} else {
// Draw a two pixel solid black border inside the framing rect
drawFrame(canvas, frame);
// 绘制边角
drawCorner(canvas, frame);
//绘制提示信息
drawTextInfo(canvas, frame);
// Draw a red "laser scanner" line through the middle to show decoding is active
drawLaserScanner(canvas, frame);
Collection<ResultPoint> currentPossible = possibleResultPoints;
Collection<ResultPoint> currentLast = lastPossibleResultPoints;
if (currentPossible.isEmpty()) {
lastPossibleResultPoints = null;
} else {
possibleResultPoints = new HashSet<>(5);
lastPossibleResultPoints = currentPossible;
paint.setAlpha(OPAQUE);
paint.setColor(resultPointColor);
for (ResultPoint point : currentPossible) {
canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint);
}
}
if (currentLast != null) {
paint.setAlpha(OPAQUE / 2);
paint.setColor(resultPointColor);
for (ResultPoint point : currentLast) {
canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint);
}
}
// Request another update at the animation interval, but only repaint the laser line,
// not the entire viewfinder mask.
//指定重绘区域,该方法会在子线程中执行
postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
}
}
//绘制文本
private void drawTextInfo(Canvas canvas, Rect frame) {
paint.setColor(labelTextColor);
paint.setTextSize(labelTextSize);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(labelText, frame.left + frame.width() / 2, frame.bottom + 100, paint);
}
//绘制边角
private void drawCorner(Canvas canvas, Rect frame) {
paint.setColor(cornerColor);
//左上
canvas.drawRect(frame.left, frame.top, frame.left + CORNER_RECT_WIDTH, frame.top + CORNER_RECT_HEIGHT, paint);
canvas.drawRect(frame.left, frame.top, frame.left + CORNER_RECT_HEIGHT, frame.top + CORNER_RECT_WIDTH, paint);
//右上
canvas.drawRect(frame.right - CORNER_RECT_WIDTH, frame.top, frame.right, frame.top + CORNER_RECT_HEIGHT, paint);
canvas.drawRect(frame.right - CORNER_RECT_HEIGHT, frame.top, frame.right, frame.top + CORNER_RECT_WIDTH, paint);
//左下
canvas.drawRect(frame.left, frame.bottom - CORNER_RECT_WIDTH, frame.left + CORNER_RECT_HEIGHT, frame.bottom, paint);
canvas.drawRect(frame.left, frame.bottom - CORNER_RECT_HEIGHT, frame.left + CORNER_RECT_WIDTH, frame.bottom, paint);
//右下
canvas.drawRect(frame.right - CORNER_RECT_WIDTH, frame.bottom - CORNER_RECT_HEIGHT, frame.right, frame.bottom, paint);
canvas.drawRect(frame.right - CORNER_RECT_HEIGHT, frame.bottom - CORNER_RECT_WIDTH, frame.right, frame.bottom, paint);
}
//绘制扫描线
private void drawLaserScanner(Canvas canvas, Rect frame) {
paint.setColor(laserColor);
//扫描线闪烁效果
/*
paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
int middle = frame.height() / 2 + frame.top;
canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
*/
//线性渐变
/*
LinearGradient linearGradient = new LinearGradient(
frame.left, scannerStart,
frame.left, scannerStart + SCANNER_LINE_HEIGHT,
shadeColor(laserColor),
laserColor,
Shader.TileMode.MIRROR);
*/
RadialGradient radialGradient = new RadialGradient(
(float) (frame.left + frame.width() / 2),
(float) (scannerStart + SCANNER_LINE_HEIGHT / 2),
360f,
laserColor,
shadeColor(laserColor),
Shader.TileMode.MIRROR);
/*SweepGradient sweepGradient = new SweepGradient(
(float) (frame.left + frame.width() / 2),
(float) (scannerStart + SCANNER_LINE_HEIGHT),
shadeColor(laserColor),
laserColor);*/
/*ComposeShader composeShader = new ComposeShader(radialGradient, linearGradient, PorterDuff.Mode.ADD);*/
paint.setShader(radialGradient);
if (scannerStart <= scannerEnd) {
//矩形
// canvas.drawRect(frame.left, scannerStart, frame.right, scannerStart + SCANNER_LINE_HEIGHT, paint);
//椭圆
RectF rectF = new RectF(frame.left + 2 * SCANNER_LINE_HEIGHT, scannerStart, frame.right - 2 * SCANNER_LINE_HEIGHT, scannerStart +
SCANNER_LINE_HEIGHT);
canvas.drawOval(rectF, paint);
scannerStart += SCANNER_LINE_MOVE_DISTANCE;
} else {
scannerStart = frame.top;
}
paint.setShader(null);
}
//处理颜色模糊
public int shadeColor(int color) {
String hax = Integer.toHexString(color);
String result = "20" + hax.substring(2);
return Integer.valueOf(result, 16);
}
// 绘制扫描区边框 Draw a two pixel solid black border inside the framing rect
private void drawFrame(Canvas canvas, Rect frame) {
paint.setColor(frameColor);
canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);
}
// 绘制模糊区域 Draw the exterior (i.e. outside the framing rect) darkened
private void drawExterior(Canvas canvas, Rect frame, int width, int height) {
paint.setColor(resultBitmap != null ? resultColor : maskColor);
canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
canvas.drawRect(0, frame.bottom + 1, width, height, paint);
}
public void drawViewfinder() {
resultBitmap = null;
invalidate();
}
/**
* Draw a bitmap with the result points highlighted instead of the live scanning display.
*
* @param barcode An image of the decoded barcode.
*/
public void drawResultBitmap(Bitmap barcode) {
resultBitmap = barcode;
invalidate();
}
public void addPossibleResultPoint(ResultPoint point) {
possibleResultPoints.add(point);
}
}
package com.mayi.fastdevelop.util;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import com.mayi.fastdevelop.R;
import com.yanzhenjie.permission.AndPermission;
import com.yanzhenjie.permission.Permission;
import java.util.List;
public class ToolUtils {
/**
* 跳转扫码二维码页,先进行照相机权限判断,请求
*/
public static void goScanActivity(final Context context, final Class activityClass) {
if (AndPermission.hasPermissions(context, Manifest.permission.CAMERA)) {
context.startActivity(new Intent(context, activityClass));
} else {
PermissionUtil.requestPermission(new PermissionUtil.PermissionCallback() {
@Override
public void onSuccess(List<String> data) {
context.startActivity(new Intent(context, activityClass));
}
@Override
public void onFail(List<String> data) {
Toast.makeText(context, context.getString(R.string.error_take_photo), Toast.LENGTH_LONG).show();
}
}, Permission.CAMERA);
}
}
}
<?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">
<SurfaceView
android:id="@+id/scanner_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.mayi.fastdevelop.commonpage.zxing.view.ViewfinderView xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/viewfinder_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:corner_color="@android:color/white"
app:frame_color="@color/viewfinder_frame"
app:label_text="@string/scan_tips"
app:label_text_color="@android:color/white"
app:label_text_size="34"
app:laser_color="@color/laser_color"
app:mask_color="@color/viewfinder_mask"
app:result_color="@color/result_view"
app:result_point_color="@color/result_point_color" />
<TextView
android:id="@+id/txt_scale_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:ellipsize="end"
android:gravity="center_vertical|left"
android:lineSpacingExtra="3dp"
android:text="11@string/qr_sclaing"
android:textColor="@android:color/white"
android:textColorHint="@color/txt_color_hint"
android:textSize="@dimen/txt_size_32px"
android:textStyle="bold"
android:visibility="gone"
tools:visibility="gone" />
<com.mayi.fastdevelop.view.CustomTitleBar
android:id="@+id/im_view_title"
android:layout_width="match_parent"
android:layout_height="@dimen/title_bar_height" />
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--corner_color 边角颜色,
scanner_color 扫描线颜色
possible_result_color 扫描点颜色
frame_color 扫描框边线颜色
mask_color 模糊区域颜色
label_text 框上方提示 -->
<declare-styleable name="ViewfinderView">
<attr name="corner_color" format="color"/>
<attr name="laser_color" format="color"/>
<attr name="frame_color" format="color"/>
<attr name="mask_color" format="color"/>
<attr name="result_point_color" format="color"/>
<attr name="result_color" format="color"/>
<attr name="label_text_color" format="color"/>
<attr name="label_text" format="string"/>
<attr name="label_text_size" format="float"/>
</declare-styleable>
</resources>
\ No newline at end of file
...@@ -98,4 +98,11 @@ ...@@ -98,4 +98,11 @@
<color name="statistics_progress_bar_start_color">#ffba43</color> <color name="statistics_progress_bar_start_color">#ffba43</color>
<color name="statistics_progress_bar_end_color">#ff8521</color> <color name="statistics_progress_bar_end_color">#ff8521</color>
<color name="statistics_radar_color">#cdcdcd</color> <color name="statistics_radar_color">#cdcdcd</color>
<color name="viewfinder_frame">#90FFFFFF</color>
<color name="laser_color">#0F0</color>
<color name="viewfinder_mask">#60000000</color>
<color name="result_view">#B0000000</color>
<color name="result_point_color">#C0FFFF00</color>
</resources> </resources>
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<!-- Messages IDs -->
<item type="id" name="auto_focus"/>
<item type="id" name="decode"/>
<item type="id" name="decode_failed"/>
<item type="id" name="decode_succeeded"/>
<item type="id" name="encode_failed"/>
<item type="id" name="encode_succeeded"/>
<item type="id" name="launch_product_query"/>
<item type="id" name="quit"/>
<item type="id" name="restart_preview"/>
<item type="id" name="return_scan_result"/>
<item type="id" name="search_book_contents_failed"/>
<item type="id" name="search_book_contents_succeeded"/>
<item type="id" name="gridview" />
<item type="id" name="webview" />
<item type="id" name="about_version_code"/>
<item type="id" name="split"/>
<item type="id" name="stateView"></item>
</resources>
...@@ -12,7 +12,11 @@ ...@@ -12,7 +12,11 @@
<string name="downloading">正在下载</string> <string name="downloading">正在下载</string>
<string name="install_apk_error">安装APK错误</string> <string name="install_apk_error">安装APK错误</string>
<string name="go_browsers">跳转浏览器,下载安装APK</string> <string name="go_browsers">跳转浏览器,下载安装APK</string>
<string name="album">相册</string> <string name="album">相册</string>
<string name="photograph">拍照</string> <string name="photograph">拍照</string>
<string name="capture">扫描二维码</string>
<string name="error_take_photo">打开摄像头失败,请检查权限设置</string>
<string name="scan_tips">将二维码放入框内,即可自动扫描</string>
<string name="open_light">打开闪光灯</string>
<string name="close_light">关闭闪光灯</string>
</resources> </resources>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment