布局================================================================
mian_activity----------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.daydayup.day07_erwei.MainActivity"> <ImageView android:id="@+id/scan" android:layout_width="30dp" android:layout_height="30dp" android:src="@drawable/sao_hei" /> <TextView android:id="@+id/result_text" android:text="结果:" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
activity_capture------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:orientation="vertical" > <SurfaceView android:id="@+id/capture_preview" android:layout_width="match_parent" android:layout_height="match_parent" /> <RelativeLayout android:id="@+id/capture_container" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/capture_mask_top" android:layout_width="match_parent" android:layout_height="120dp" android:layout_alignParentTop="true" android:background="@drawable/shadow" /> <RelativeLayout android:id="@+id/capture_crop_view" android:layout_width="200dp" android:layout_height="200dp" android:layout_below="@id/capture_mask_top" android:layout_centerHorizontal="true" android:background="@drawable/qr_code_bg" > <ImageView android:id="@+id/capture_scan_line" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginBottom="5dp" android:layout_marginTop="5dp" android:src="@drawable/scan_line" /> </RelativeLayout> <ImageView android:id="@+id/capture_mask_bottom" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_below="@id/capture_crop_view" android:background="@drawable/shadow" /> <ImageView android:id="@+id/capture_mask_left" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_above="@id/capture_mask_bottom" android:layout_alignParentLeft="true" android:layout_below="@id/capture_mask_top" android:layout_toLeftOf="@id/capture_crop_view" android:background="@drawable/shadow" /> <ImageView android:id="@+id/capture_mask_right" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_above="@id/capture_mask_bottom" android:layout_alignParentRight="true" android:layout_below="@id/capture_mask_top" android:layout_toRightOf="@id/capture_crop_view" android:background="@drawable/shadow" /> </RelativeLayout> </RelativeLayout>
activity_result----------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:gravity="center_horizontal" android:orientation="vertical" > <ImageView android:id="@+id/result_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/darker_gray" android:scaleType="fitXY" /> <TextView android:id="@+id/result_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_marginTop="20dp" android:background="#D8D8D8" android:gravity="left|top" android:padding="10dp" android:textColor="@android:color/black" android:textSize="14sp" /> </LinearLayout>
Values.ids.xml
package com.daydayup.day07_erwei.qrcode; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.TypedValue; import android.widget.ImageView; import android.widget.LinearLayout.LayoutParams; import android.widget.TextView; import com.daydayup.day07_erwei.R; import com.daydayup.day07_erwei.qrcode.decode.DecodeThread; public class ResultActivity extends Activity { private ImageView mResultImage; private TextView mResultText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_result); Bundle extras = getIntent().getExtras(); mResultImage = (ImageView) findViewById(R.id.result_image); mResultText = (TextView) findViewById(R.id.result_text); if (null != extras) { int width = extras.getInt("width"); int height = extras.getInt("height"); LayoutParams lps = new LayoutParams(width, height); lps.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics()); lps.leftMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()); lps.rightMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()); mResultImage.setLayoutParams(lps); String result = extras.getString("result"); mResultText.setText(result); Bitmap barcode = null; byte[] compressedBitmap = extras.getByteArray(DecodeThread.BARCODE_BITMAP); if (compressedBitmap != null) { barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null); // Mutable copy: barcode = barcode.copy(Bitmap.Config.RGB_565, true); } mResultImage.setImageBitmap(barcode); } } }
MianActivity================================================================
package com.daydayup.day07_erwei; import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import com.daydayup.day07_erwei.qrcode.CaptureActivity; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity===="; private final int REQUEST_CODE = 0; private TextView result_tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initPermission(); ImageView scan = findViewById(R.id.scan); result_tv = findViewById(R.id.result_text); scan.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //点击开始扫描 Intent intent = new Intent(MainActivity.this, CaptureActivity.class); startActivityForResult(intent,REQUEST_CODE); } }); } private void initPermission() { if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[] {Manifest.permission.CAMERA}, 1); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Log.d(TAG, "接收到数据-----: "); Bundle extras = data.getBundleExtra("data"); String result = extras.getString("result"); result_tv.setText(result+"----------"); } }
AutoFocusManage================================================
/* * Copyright (C) 2012 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.camera; import java.util.ArrayList; import java.util.Collection; import java.util.concurrent.RejectedExecutionException; import android.annotation.SuppressLint; import android.content.Context; import android.hardware.Camera; import android.os.AsyncTask; import android.os.Build; import android.util.Log; public class AutoFocusManager implements Camera.AutoFocusCallback { private static final String TAG = AutoFocusManager.class.getSimpleName(); private static final long AUTO_FOCUS_INTERVAL_MS = 2000L; private static final Collection<String> FOCUS_MODES_CALLING_AF; static { FOCUS_MODES_CALLING_AF = new ArrayList<String>(2); FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_AUTO); FOCUS_MODES_CALLING_AF.add(Camera.Parameters.FOCUS_MODE_MACRO); } private boolean stopped; private boolean focusing; private final boolean useAutoFocus; private final Camera camera; private AsyncTask<?, ?, ?> outstandingTask; public AutoFocusManager(Context context, Camera camera) { this.camera = camera; String currentFocusMode = camera.getParameters().getFocusMode(); useAutoFocus = FOCUS_MODES_CALLING_AF.contains(currentFocusMode); Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus); start(); } @Override public synchronized void onAutoFocus(boolean success, Camera theCamera) { focusing = false; autoFocusAgainLater(); } @SuppressLint("NewApi") private synchronized void autoFocusAgainLater() { if (!stopped && outstandingTask == null) { AutoFocusTask newTask = new AutoFocusTask(); try { if (Build.VERSION.SDK_INT >= 11) { newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { newTask.execute(); } outstandingTask = newTask; } catch (RejectedExecutionException ree) { Log.w(TAG, "Could not request auto focus", ree); } } } public synchronized void start() { if (useAutoFocus) { outstandingTask = null; if (!stopped && !focusing) { try { camera.autoFocus(this); focusing = true; } catch (RuntimeException re) { // Have heard RuntimeException reported in Android 4.0.x+; // continue? Log.w(TAG, "Unexpected exception while focusing", re); // Try again later to keep cycle going autoFocusAgainLater(); } } } } private synchronized void cancelOutstandingTask() { if (outstandingTask != null) { if (outstandingTask.getStatus() != AsyncTask.Status.FINISHED) { outstandingTask.cancel(true); } outstandingTask = null; } } public synchronized void stop() { stopped = true; if (useAutoFocus) { cancelOutstandingTask(); // Doesn't hurt to call this even if not focusing try { camera.cancelAutoFocus(); } catch (RuntimeException re) { // Have heard RuntimeException reported in Android 4.0.x+; // continue? Log.w(TAG, "Unexpected exception while cancelling focusing", re); } } } private final class AutoFocusTask extends AsyncTask<Object, Object, Object> { @Override protected Object doInBackground(Object... voids) { try { Thread.sleep(AUTO_FOCUS_INTERVAL_MS); } catch (InterruptedException e) { // continue } start(); return null; } } }
CameraConfigurationManager======================================
/* * Copyright (C) 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.camera; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Point; import android.hardware.Camera; import android.util.Log; import android.view.Display; import android.view.WindowManager; /** * * 邮箱: 1076559197@qq.com | tauchen1990@gmail.com * * 作者: 陈涛 * * 日期: 2014年8月20日 * * 描述: 该类主要负责设置相机的参数信息,获取最佳的预览界面 * */ public final class CameraConfigurationManager { private static final String TAG = "CameraConfiguration"; private static final int MIN_PREVIEW_PIXELS = 480 * 320; private static final double MAX_ASPECT_DISTORTION = 0.15; private final Context context; // 屏幕分辨率 private Point screenResolution; // 相机分辨率 private Point cameraResolution; public CameraConfigurationManager(Context context) { this.context = context; } public void initFromCameraParameters(Camera camera) { Camera.Parameters parameters = camera.getParameters(); WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); Point theScreenResolution = new Point(); theScreenResolution = getDisplaySize(display); screenResolution = theScreenResolution; Log.i(TAG, "Screen resolution: " + screenResolution); /** 因为换成了竖屏显示,所以不替换屏幕宽高得出的预览图是变形的 */ Point screenResolutionForCamera = new Point(); screenResolutionForCamera.x = screenResolution.x; screenResolutionForCamera.y = screenResolution.y; if (screenResolution.x < screenResolution.y) { screenResolutionForCamera.x = screenResolution.y; screenResolutionForCamera.y = screenResolution.x; } cameraResolution = findBestPreviewSizeValue(parameters, screenResolutionForCamera); Log.i(TAG, "Camera resolution x: " + cameraResolution.x); Log.i(TAG, "Camera resolution y: " + cameraResolution.y); } @SuppressWarnings("deprecation") @SuppressLint("NewApi") private Point getDisplaySize(final Display display) { final Point point = new Point(); try { display.getSize(point); } catch (NoSuchMethodError ignore) { point.x = display.getWidth(); point.y = display.getHeight(); } return point; } public void setDesiredCameraParameters(Camera camera, boolean safeMode) { Camera.Parameters parameters = camera.getParameters(); if (parameters == null) { Log.w(TAG, "Device error: no camera parameters are available. Proceeding without configuration."); return; } Log.i(TAG, "Initial camera parameters: " + parameters.flatten()); if (safeMode) { Log.w(TAG, "In camera config safe mode -- most settings will not be honored"); } parameters.setPreviewSize(cameraResolution.x, cameraResolution.y); camera.setParameters(parameters); Camera.Parameters afterParameters = camera.getParameters(); Camera.Size afterSize = afterParameters.getPreviewSize(); if (afterSize != null && (cameraResolution.x != afterSize.width || cameraResolution.y != afterSize.height)) { Log.w(TAG, "Camera said it supported preview size " + cameraResolution.x + 'x' + cameraResolution.y + ", but after setting it, preview size is " + afterSize.width + 'x' + afterSize.height); cameraResolution.x = afterSize.width; cameraResolution.y = afterSize.height; } /** 设置相机预览为竖屏 */ camera.setDisplayOrientation(90); } public Point getCameraResolution() { return cameraResolution; } public Point getScreenResolution() { return screenResolution; } /** * 从相机支持的分辨率中计算出最适合的预览界面尺寸 * * @param parameters * @param screenResolution * @return */ private Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) { List<Camera.Size> rawSupportedSizes = parameters.getSupportedPreviewSizes(); if (rawSupportedSizes == null) { Log.w(TAG, "Device returned no supported preview sizes; using default"); Camera.Size defaultSize = parameters.getPreviewSize(); return new Point(defaultSize.width, defaultSize.height); } // Sort by size, descending List<Camera.Size> supportedPreviewSizes = new ArrayList<Camera.Size>(rawSupportedSizes); Collections.sort(supportedPreviewSizes, new Comparator<Camera.Size>() { @Override public int compare(Camera.Size a, Camera.Size b) { int aPixels = a.height * a.width; int bPixels = b.height * b.width; if (bPixels < aPixels) { return -1; } if (bPixels > aPixels) { return 1; } return 0; } }); if (Log.isLoggable(TAG, Log.INFO)) { StringBuilder previewSizesString = new StringBuilder(); for (Camera.Size supportedPreviewSize : supportedPreviewSizes) { previewSizesString.append(supportedPreviewSize.width).append('x').append(supportedPreviewSize.height).append(' '); } Log.i(TAG, "Supported preview sizes: " + previewSizesString); } double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y; // Remove sizes that are unsuitable Iterator<Camera.Size> it = supportedPreviewSizes.iterator(); while (it.hasNext()) { Camera.Size supportedPreviewSize = it.next(); int realWidth = supportedPreviewSize.width; int realHeight = supportedPreviewSize.height; if (realWidth * realHeight < MIN_PREVIEW_PIXELS) { it.remove(); continue; } boolean isCandidatePortrait = realWidth < realHeight; int maybeFlippedWidth = isCandidatePortrait ? realHeight : realWidth; int maybeFlippedHeight = isCandidatePortrait ? realWidth : realHeight; double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight; double distortion = Math.abs(aspectRatio - screenAspectRatio); if (distortion > MAX_ASPECT_DISTORTION) { it.remove(); continue; } if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) { Point exactPoint = new Point(realWidth, realHeight); Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint); return exactPoint; } } // If no exact match, use largest preview size. This was not a great // idea on older devices because // of the additional computation needed. We're likely to get here on // newer Android 4+ devices, where // the CPU is much more powerful. if (!supportedPreviewSizes.isEmpty()) { Camera.Size largestPreview = supportedPreviewSizes.get(0); Point largestSize = new Point(largestPreview.width, largestPreview.height); Log.i(TAG, "Using largest suitable preview size: " + largestSize); return largestSize; } // If there is nothing at all suitable, return current preview size Camera.Size defaultPreview = parameters.getPreviewSize(); Point defaultSize = new Point(defaultPreview.width, defaultPreview.height); Log.i(TAG, "No suitable preview sizes, using default: " + defaultSize); return defaultSize; } }
CameraManager===============================================
/* * Copyright (C) 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.camera; import java.io.IOException; import android.content.Context; import android.graphics.Point; import android.hardware.Camera; import android.hardware.Camera.Size; import android.os.Handler; import android.util.Log; import android.view.SurfaceHolder; import com.daydayup.day07_erwei.qrcode.camera.open.OpenCameraInterface; /** * 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. * * @author dswitkin@google.com (Daniel Switkin) */ public class CameraManager { private static final String TAG = CameraManager.class.getSimpleName(); private final Context context; private final CameraConfigurationManager configManager; private Camera camera; private AutoFocusManager autoFocusManager; private boolean initialized; private boolean previewing; private int requestedCameraId = -1; /** * Preview frames are delivered here, which we pass on to the registered * handler. Make sure to clear the handler so it will only receive one * message. */ private final PreviewCallback previewCallback; public CameraManager(Context context) { this.context = context; this.configManager = new CameraConfigurationManager(context); previewCallback = new PreviewCallback(configManager); } /** * Opens the camera driver and initializes the hardware parameters. * * @param holder * The surface object which the camera will draw preview frames * into. * @throws IOException * Indicates the camera driver failed to open. */ public synchronized void openDriver(SurfaceHolder holder) throws IOException { Camera theCamera = camera; if (theCamera == null) { if (requestedCameraId >= 0) { theCamera = OpenCameraInterface.open(requestedCameraId); } else { theCamera = OpenCameraInterface.open(); } if (theCamera == null) { throw new IOException(); } camera = theCamera; } theCamera.setPreviewDisplay(holder); if (!initialized) { initialized = true; configManager.initFromCameraParameters(theCamera); } Camera.Parameters parameters = theCamera.getParameters(); String parametersFlattened = parameters == null ? null : parameters.flatten(); // Save // these, // temporarily try { configManager.setDesiredCameraParameters(theCamera, false); } catch (RuntimeException re) { // Driver failed Log.w(TAG, "Camera rejected parameters. Setting only minimal safe-mode parameters"); Log.i(TAG, "Resetting to saved camera params: " + parametersFlattened); // Reset: if (parametersFlattened != null) { parameters = theCamera.getParameters(); parameters.unflatten(parametersFlattened); try { theCamera.setParameters(parameters); configManager.setDesiredCameraParameters(theCamera, true); } catch (RuntimeException re2) { // Well, darn. Give up Log.w(TAG, "Camera rejected even safe-mode parameters! No configuration"); } } } } public synchronized boolean isOpen() { return camera != null; } /** * Closes the camera driver if still in use. */ public synchronized void closeDriver() { if (camera != null) { camera.release(); camera = null; // Make sure to clear these each time we close the camera, so that // any scanning rect // requested by intent is forgotten. } } /** * Asks the camera hardware to begin drawing preview frames to the screen. */ public synchronized void startPreview() { Camera theCamera = camera; if (theCamera != null && !previewing) { theCamera.startPreview(); previewing = true; autoFocusManager = new AutoFocusManager(context, camera); } } /** * Tells the camera to stop drawing preview frames. */ public synchronized void stopPreview() { if (autoFocusManager != null) { autoFocusManager.stop(); autoFocusManager = null; } if (camera != null && previewing) { camera.stopPreview(); previewCallback.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 synchronized void requestPreviewFrame(Handler handler, int message) { Camera theCamera = camera; if (theCamera != null && previewing) { previewCallback.setHandler(handler, message); theCamera.setOneShotPreviewCallback(previewCallback); } } /** * Allows third party apps to specify the camera ID, rather than determine * it automatically based on available cameras and their orientation. * * @param cameraId * camera ID of the camera to use. A negative value means * "no preference". */ public synchronized void setManualCameraId(int cameraId) { requestedCameraId = cameraId; } /** * 获取相机分辨率 * * @return */ public Point getCameraResolution() { return configManager.getCameraResolution(); } public Size getPreviewSize() { if (null != camera) { return camera.getParameters().getPreviewSize(); } return null; } }
PreviewCallback================================================
/* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.camera; import android.graphics.Point; import android.hardware.Camera; import android.os.Handler; import android.os.Message; import android.util.Log; public class PreviewCallback implements Camera.PreviewCallback { private static final String TAG = PreviewCallback.class.getSimpleName(); private final CameraConfigurationManager configManager; private Handler previewHandler; private int previewMessage; public PreviewCallback(CameraConfigurationManager configManager) { this.configManager = configManager; } public void setHandler(Handler previewHandler, int previewMessage) { this.previewHandler = previewHandler; this.previewMessage = previewMessage; } @Override public void onPreviewFrame(byte[] data, Camera camera) { Point cameraResolution = configManager.getCameraResolution(); Handler thePreviewHandler = previewHandler; if (cameraResolution != null && thePreviewHandler != null) { Message message = thePreviewHandler.obtainMessage(previewMessage, cameraResolution.x, cameraResolution.y, data); message.sendToTarget(); previewHandler = null; } else { Log.d(TAG, "Got preview callback, but no handler or resolution available"); } } }
DecodeFormatManage============================================
/* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.decode; import java.util.Collection; import java.util.EnumSet; import java.util.Set; import com.google.zxing.BarcodeFormat; public class DecodeFormatManager { // 1D解码 private static final Set<BarcodeFormat> PRODUCT_FORMATS; private static final Set<BarcodeFormat> INDUSTRIAL_FORMATS; private static final Set<BarcodeFormat> ONE_D_FORMATS; // 二维码解码 private static final Set<BarcodeFormat> QR_CODE_FORMATS; static { PRODUCT_FORMATS = EnumSet.of(BarcodeFormat.UPC_A, BarcodeFormat.UPC_E, BarcodeFormat.EAN_13, BarcodeFormat.EAN_8, BarcodeFormat.RSS_14, BarcodeFormat.RSS_EXPANDED); INDUSTRIAL_FORMATS = EnumSet.of(BarcodeFormat.CODE_39, BarcodeFormat.CODE_93, BarcodeFormat.CODE_128, BarcodeFormat.ITF, BarcodeFormat.CODABAR); ONE_D_FORMATS = EnumSet.copyOf(PRODUCT_FORMATS); ONE_D_FORMATS.addAll(INDUSTRIAL_FORMATS); QR_CODE_FORMATS = EnumSet.of(BarcodeFormat.QR_CODE); } public static Collection<BarcodeFormat> getQrCodeFormats() { return QR_CODE_FORMATS; } public static Collection<BarcodeFormat> getBarCodeFormats() { return ONE_D_FORMATS; } }
DecodeHandler================================================
/* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.decode; import java.io.ByteArrayOutputStream; import java.util.Map; import android.graphics.Bitmap; import android.graphics.Rect; import android.hardware.Camera.Size; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import com.daydayup.day07_erwei.R; import com.daydayup.day07_erwei.qrcode.CaptureActivity; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; import com.google.zxing.MultiFormatReader; import com.google.zxing.PlanarYUVLuminanceSource; import com.google.zxing.ReaderException; import com.google.zxing.Result; import com.google.zxing.common.HybridBinarizer; public class DecodeHandler extends Handler { private final CaptureActivity activity; private final MultiFormatReader multiFormatReader; private boolean running = true; public DecodeHandler(CaptureActivity activity, Map<DecodeHintType, Object> hints) { multiFormatReader = new MultiFormatReader(); multiFormatReader.setHints(hints); this.activity = activity; } @Override public void handleMessage(Message message) { if (!running) { return; } switch (message.what) { case R.id.decode: decode((byte[]) message.obj, message.arg1, message.arg2); break; case R.id.quit: running = false; Looper.myLooper().quit(); break; } } /** * 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) { Size size = activity.getCameraManager().getPreviewSize(); // 这里需要将获取的data翻转一下,因为相机默认拿的的横屏的数据 byte[] rotatedData = new byte[data.length]; for (int y = 0; y < size.height; y++) { for (int x = 0; x < size.width; x++) rotatedData[x * size.height + size.height - y - 1] = data[x + y * size.width]; } // 宽高也要调整 int tmp = size.width; size.width = size.height; size.height = tmp; Result rawResult = null; PlanarYUVLuminanceSource source = buildLuminanceSource(rotatedData, size.width, size.height); if (source != null) { BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); try { rawResult = multiFormatReader.decodeWithState(bitmap); } catch (ReaderException re) { // continue } finally { multiFormatReader.reset(); } } Handler handler = activity.getHandler(); if (rawResult != null) { // Don't log the barcode contents for security. if (handler != null) { Message message = Message.obtain(handler, R.id.decode_succeeded, rawResult); Bundle bundle = new Bundle(); bundleThumbnail(source, bundle); message.setData(bundle); message.sendToTarget(); } } else { if (handler != null) { Message message = Message.obtain(handler, R.id.decode_failed); message.sendToTarget(); } } } private static void bundleThumbnail(PlanarYUVLuminanceSource source, Bundle bundle) { int[] pixels = source.renderThumbnail(); int width = source.getThumbnailWidth(); int height = source.getThumbnailHeight(); Bitmap bitmap = Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888); ByteArrayOutputStream out = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 50, out); bundle.putByteArray(DecodeThread.BARCODE_BITMAP, out.toByteArray()); } /** * 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 = activity.getCropRect(); if (rect == null) { return null; } // Go ahead and assume it's YUV rather than die. return new PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, rect.width(), rect.height(), false); } }
DecodeThread===================================================
/* * Copyright (C) 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.decode; import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.EnumSet; import java.util.Map; import java.util.concurrent.CountDownLatch; import android.os.Handler; import android.os.Looper; import com.daydayup.day07_erwei.qrcode.CaptureActivity; import com.google.zxing.BarcodeFormat; import com.google.zxing.DecodeHintType; /** * This thread does all the heavy lifting of decoding the images. * * @author dswitkin@google.com (Daniel Switkin) */ public class DecodeThread extends Thread { public static final String BARCODE_BITMAP = "barcode_bitmap"; public static final int BARCODE_MODE = 0X100; public static final int QRCODE_MODE = 0X200; public static final int ALL_MODE = 0X300; private final CaptureActivity activity; private final Map<DecodeHintType, Object> hints; private Handler handler; private final CountDownLatch handlerInitLatch; public DecodeThread(CaptureActivity activity, int decodeMode) { this.activity = activity; handlerInitLatch = new CountDownLatch(1); hints = new EnumMap<DecodeHintType, Object>(DecodeHintType.class); Collection<BarcodeFormat> decodeFormats = new ArrayList<BarcodeFormat>(); decodeFormats.addAll(EnumSet.of(BarcodeFormat.AZTEC)); decodeFormats.addAll(EnumSet.of(BarcodeFormat.PDF_417)); switch (decodeMode) { case BARCODE_MODE: decodeFormats.addAll(DecodeFormatManager.getBarCodeFormats()); break; case QRCODE_MODE: decodeFormats.addAll(DecodeFormatManager.getQrCodeFormats()); break; case ALL_MODE: decodeFormats.addAll(DecodeFormatManager.getBarCodeFormats()); decodeFormats.addAll(DecodeFormatManager.getQrCodeFormats()); break; default: break; } hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats); } public Handler getHandler() { try { handlerInitLatch.await(); } catch (InterruptedException ie) { // continue? } return handler; } @Override public void run() { Looper.prepare(); handler = new DecodeHandler(activity, hints); handlerInitLatch.countDown(); Looper.loop(); } }
BeepManager=================================================
/* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.utils; import java.io.Closeable; import java.io.IOException; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; import android.content.res.AssetFileDescriptor; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Vibrator; import android.preference.PreferenceManager; import android.util.Log; import com.daydayup.day07_erwei.R; /** * Manages beeps and vibrations for {@link CaptureActivity}. */ public class BeepManager implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, Closeable { private static final String TAG = BeepManager.class.getSimpleName(); private static final float BEEP_VOLUME = 0.10f; private static final long VIBRATE_DURATION = 200L; private final Activity activity; private MediaPlayer mediaPlayer; private boolean playBeep; private boolean vibrate; public BeepManager(Activity activity) { this.activity = activity; this.mediaPlayer = null; updatePrefs(); } private synchronized void updatePrefs() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); playBeep = shouldBeep(prefs, activity); vibrate = true; if (playBeep && mediaPlayer == null) { // The volume on STREAM_SYSTEM is not adjustable, and users found it // too loud, // so we now play on the music stream. activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); mediaPlayer = buildMediaPlayer(activity); } } public synchronized void playBeepSoundAndVibrate() { if (playBeep && mediaPlayer != null) { mediaPlayer.start(); } if (vibrate) { Vibrator vibrator = (Vibrator) activity.getSystemService(Context.VIBRATOR_SERVICE); vibrator.vibrate(VIBRATE_DURATION); } } private static boolean shouldBeep(SharedPreferences prefs, Context activity) { boolean shouldPlayBeep = true; if (shouldPlayBeep) { // See if sound settings overrides this AudioManager audioService = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE); if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) { shouldPlayBeep = false; } } return shouldPlayBeep; } private MediaPlayer buildMediaPlayer(Context activity) { MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); mediaPlayer.setOnCompletionListener(this); mediaPlayer.setOnErrorListener(this); try { AssetFileDescriptor file = activity.getResources().openRawResourceFd(R.raw.beep); try { mediaPlayer.setDataSource(file.getFileDescriptor(), file.getStartOffset(), file.getLength()); } finally { file.close(); } mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME); mediaPlayer.prepare(); return mediaPlayer; } catch (IOException ioe) { Log.w(TAG, ioe); mediaPlayer.release(); return null; } } @Override public void onCompletion(MediaPlayer mp) { // When the beep has finished playing, rewind to queue up another one. mp.seekTo(0); } @Override public synchronized boolean onError(MediaPlayer mp, int what, int extra) { if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) { // we are finished, so put up an appropriate error toast if required // and finish activity.finish(); } else { // possibly media player error, so release and recreate mp.release(); mediaPlayer = null; updatePrefs(); } return true; } @Override public synchronized void close() { if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } }
CaptureActivityHandler==========================================
/* * Copyright (C) 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.utils; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import com.daydayup.day07_erwei.R; import com.daydayup.day07_erwei.qrcode.CaptureActivity; import com.daydayup.day07_erwei.qrcode.camera.CameraManager; import com.daydayup.day07_erwei.qrcode.decode.DecodeThread; import com.google.zxing.Result; /** * This class handles all the messaging which comprises the state machine for * capture. * * @author dswitkin@google.com (Daniel Switkin) */ public class CaptureActivityHandler extends Handler { private final CaptureActivity activity; private final DecodeThread decodeThread; private final CameraManager cameraManager; private State state; private enum State { PREVIEW, SUCCESS, DONE } public CaptureActivityHandler(CaptureActivity activity, CameraManager cameraManager, int decodeMode) { this.activity = activity; decodeThread = new DecodeThread(activity, decodeMode); decodeThread.start(); state = State.SUCCESS; // Start ourselves capturing previews and decoding. this.cameraManager = cameraManager; cameraManager.startPreview(); restartPreviewAndDecode(); } @Override public void handleMessage(Message message) { switch (message.what) { case R.id.restart_preview: restartPreviewAndDecode(); break; case R.id.decode_succeeded: state = State.SUCCESS; Bundle bundle = message.getData(); activity.handleDecode((Result) message.obj, bundle); break; case R.id.decode_failed: // We're decoding as fast as possible, so when one decode fails, // start another. state = State.PREVIEW; cameraManager.requestPreviewFrame(decodeThread.getHandler(), R.id.decode); break; case R.id.return_scan_result: activity.setResult(Activity.RESULT_OK, (Intent) message.obj); activity.finish(); break; } } public void quitSynchronously() { state = State.DONE; cameraManager.stopPreview(); Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit); quit.sendToTarget(); try { // Wait at most half a second; should be enough time, and onPause() // will timeout quickly decodeThread.join(500L); } 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.requestPreviewFrame(decodeThread.getHandler(), R.id.decode); } } }
InactivityTimer=====================================================
/* * Copyright (C) 2010 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode.utils; import android.annotation.SuppressLint; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.AsyncTask; import android.os.BatteryManager; import android.os.Build; import android.util.Log; /** * Finishes an activity after a period of inactivity if the device is on battery * power. */ public class InactivityTimer { private static final String TAG = InactivityTimer.class.getSimpleName(); private static final long INACTIVITY_DELAY_MS = 5 * 60 * 1000L; private Activity activity; private BroadcastReceiver powerStatusReceiver; private boolean registered; private AsyncTask<Object, Object, Object> inactivityTask; public InactivityTimer(Activity activity) { this.activity = activity; powerStatusReceiver = new PowerStatusReceiver(); registered = false; onActivity(); } @SuppressLint("NewApi") public synchronized void onActivity() { cancel(); inactivityTask = new InactivityAsyncTask(); if (Build.VERSION.SDK_INT >= 11) { inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else { inactivityTask.execute(); } } public synchronized void onPause() { cancel(); if (registered) { activity.unregisterReceiver(powerStatusReceiver); registered = false; } else { Log.w(TAG, "PowerStatusReceiver was never registered?"); } } public synchronized void onResume() { if (registered) { Log.w(TAG, "PowerStatusReceiver was already registered?"); } else { activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); registered = true; } onActivity(); } private synchronized void cancel() { AsyncTask<?, ?, ?> task = inactivityTask; if (task != null) { task.cancel(true); inactivityTask = null; } } public void shutdown() { cancel(); } private class PowerStatusReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { // 0 indicates that we're on battery boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0; if (onBatteryNow) { InactivityTimer.this.onActivity(); } else { InactivityTimer.this.cancel(); } } } } private class InactivityAsyncTask extends AsyncTask<Object, Object, Object> { @Override protected Object doInBackground(Object... objects) { try { Thread.sleep(INACTIVITY_DELAY_MS); Log.i(TAG, "Finishing activity due to inactivity"); activity.finish(); } catch (InterruptedException e) { // continue without killing } return null; } } }
CaptureActivity=================================================
/* * Copyright (C) 2008 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.daydayup.day07_erwei.qrcode; import java.io.IOException; import java.lang.reflect.Field; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.Window; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.TranslateAnimation; import android.widget.ImageView; import android.widget.RelativeLayout; import com.daydayup.day07_erwei.MainActivity; import com.daydayup.day07_erwei.R; import com.daydayup.day07_erwei.qrcode.camera.CameraManager; import com.daydayup.day07_erwei.qrcode.decode.DecodeThread; import com.daydayup.day07_erwei.qrcode.utils.BeepManager; import com.daydayup.day07_erwei.qrcode.utils.CaptureActivityHandler; import com.daydayup.day07_erwei.qrcode.utils.InactivityTimer; import com.google.zxing.Result; /** * This activity opens the camera and does the actual scanning on a background * thread. It draws a viewfinder to help the user place the barcode correctly, * shows feedback as the image processing is happening, and then overlays the * results when a scan is successful. * * @author dswitkin@google.com (Daniel Switkin) * @author Sean Owen */ public final class CaptureActivity extends Activity implements SurfaceHolder.Callback { private static final String TAG = CaptureActivity.class.getSimpleName()+"-----------"; private CameraManager cameraManager; private CaptureActivityHandler handler; private InactivityTimer inactivityTimer; private BeepManager beepManager; private SurfaceView scanPreview = null; private RelativeLayout scanContainer; private RelativeLayout scanCropView; private ImageView scanLine; private Rect mCropRect = null; public Handler getHandler() { return handler; } public CameraManager getCameraManager() { return cameraManager; } private boolean isHasSurface = false; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_capture); scanPreview = (SurfaceView) findViewById(R.id.capture_preview); scanContainer = (RelativeLayout) findViewById(R.id.capture_container); scanCropView = (RelativeLayout) findViewById(R.id.capture_crop_view); scanLine = (ImageView) findViewById(R.id.capture_scan_line); inactivityTimer = new InactivityTimer(this); beepManager = new BeepManager(this); TranslateAnimation animation = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.9f); animation.setDuration(4500); animation.setRepeatCount(-1); animation.setRepeatMode(Animation.RESTART); scanLine.startAnimation(animation); } @Override protected void onResume() { super.onResume(); // CameraManager must be initialized here, not in onCreate(). This is // necessary because we don't // want to open the camera driver and measure the screen size if we're // going to show the help on // first launch. That led to bugs where the scanning rectangle was the // wrong size and partially // off screen. cameraManager = new CameraManager(getApplication()); handler = null; if (isHasSurface) { // The activity was paused but not stopped, so the surface still // exists. Therefore // surfaceCreated() won't be called, so init the camera here. initCamera(scanPreview.getHolder()); } else { // Install the callback and wait for surfaceCreated() to init the // camera. scanPreview.getHolder().addCallback(this); } inactivityTimer.onResume(); } @Override protected void onPause() { if (handler != null) { handler.quitSynchronously(); handler = null; } inactivityTimer.onPause(); beepManager.close(); cameraManager.closeDriver(); if (!isHasSurface) { scanPreview.getHolder().removeCallback(this); } super.onPause(); } @Override protected void onDestroy() { inactivityTimer.shutdown(); super.onDestroy(); } @Override public void surfaceCreated(SurfaceHolder holder) { if (holder == null) { Log.e(TAG, "*** WARNING *** surfaceCreated() gave us a null surface!"); } if (!isHasSurface) { isHasSurface = true; initCamera(holder); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { isHasSurface = false; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /** * A valid barcode has been found, so give an indication of success and show * the results. * * @param rawResult The contents of the barcode. * @param bundle The extras */ public void handleDecode(Result rawResult, Bundle bundle) { inactivityTimer.onActivity(); beepManager.playBeepSoundAndVibrate(); bundle.putInt("width", mCropRect.width()); bundle.putInt("height", mCropRect.height()); bundle.putString("result", rawResult.getText()); Intent intent = getIntent(); intent.putExtra("data", bundle); setResult(1, intent); Log.d(TAG, "结果-------"); finish(); // startActivity(new Intent(CaptureActivity.this, ResultActivity.class).putExtras(bundle)); } private void initCamera(SurfaceHolder surfaceHolder) { if (surfaceHolder == null) { throw new IllegalStateException("No SurfaceHolder provided"); } if (cameraManager.isOpen()) { Log.w(TAG, "initCamera() while already open -- late SurfaceView callback?"); return; } try { cameraManager.openDriver(surfaceHolder); // Creating the handler starts the preview, which can also throw a // RuntimeException. if (handler == null) { handler = new CaptureActivityHandler(this, cameraManager, DecodeThread.ALL_MODE); } initCrop(); } catch (IOException ioe) { Log.w(TAG, ioe); displayFrameworkBugMessageAndExit(); } catch (RuntimeException e) { // Barcode Scanner has seen crashes in the wild of this variety: // java.?lang.?RuntimeException: Fail to connect to camera service Log.w(TAG, "Unexpected error initializing camera", e); displayFrameworkBugMessageAndExit(); } } private void displayFrameworkBugMessageAndExit() { // camera error AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(getString(R.string.app_name)); builder.setMessage("相机打开出错,请稍后重试"); builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); builder.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { finish(); } }); builder.show(); } public void restartPreviewAfterDelay(long delayMS) { if (handler != null) { handler.sendEmptyMessageDelayed(R.id.restart_preview, delayMS); } } public Rect getCropRect() { return mCropRect; } /** * 初始化截取的矩形区域 */ private void initCrop() { int cameraWidth = cameraManager.getCameraResolution().y; int cameraHeight = cameraManager.getCameraResolution().x; /** 获取布局中扫描框的位置信息 */ int[] location = new int[2]; scanCropView.getLocationInWindow(location); int cropLeft = location[0]; int cropTop = location[1] - getStatusBarHeight(); int cropWidth = scanCropView.getWidth(); int cropHeight = scanCropView.getHeight(); /** 获取布局容器的宽高 */ int containerWidth = scanContainer.getWidth(); int containerHeight = scanContainer.getHeight(); /** 计算最终截取的矩形的左上角顶点x坐标 */ int x = cropLeft * cameraWidth / containerWidth; /** 计算最终截取的矩形的左上角顶点y坐标 */ int y = cropTop * cameraHeight / containerHeight; /** 计算最终截取的矩形的宽度 */ int width = cropWidth * cameraWidth / containerWidth; /** 计算最终截取的矩形的高度 */ int height = cropHeight * cameraHeight / containerHeight; /** 生成最终的截取的矩形 */ mCropRect = new Rect(x, y, width + x, height + y); } private int getStatusBarHeight() { try { Class<?> c = Class.forName("com.android.internal.R$dimen"); Object obj = c.newInstance(); Field field = c.getField("status_bar_height"); int x = Integer.parseInt(field.get(obj).toString()); return getResources().getDimensionPixelSize(x); } catch (Exception e) { e.printStackTrace(); } return 0; } }
ResultActivity==========================================================
package com.daydayup.day07_erwei.qrcode; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.TypedValue; import android.widget.ImageView; import android.widget.LinearLayout.LayoutParams; import android.widget.TextView; import com.daydayup.day07_erwei.R; import com.daydayup.day07_erwei.qrcode.decode.DecodeThread; public class ResultActivity extends Activity { private ImageView mResultImage; private TextView mResultText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_result); Bundle extras = getIntent().getExtras(); mResultImage = (ImageView) findViewById(R.id.result_image); mResultText = (TextView) findViewById(R.id.result_text); if (null != extras) { int width = extras.getInt("width"); int height = extras.getInt("height"); LayoutParams lps = new LayoutParams(width, height); lps.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, getResources().getDisplayMetrics()); lps.leftMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()); lps.rightMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, getResources().getDisplayMetrics()); mResultImage.setLayoutParams(lps); String result = extras.getString("result"); mResultText.setText(result); Bitmap barcode = null; byte[] compressedBitmap = extras.getByteArray(DecodeThread.BARCODE_BITMAP); if (compressedBitmap != null) { barcode = BitmapFactory.decodeByteArray(compressedBitmap, 0, compressedBitmap.length, null); // Mutable copy: barcode = barcode.copy(Bitmap.Config.RGB_565, true); } mResultImage.setImageBitmap(barcode); } } }
依赖=========================================================================
apply plugin: 'com.android.application' android { compileSdkVersion 26 defaultConfig { applicationId "com.daydayup.day07_erwei" minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support.constraint:constraint-layout:1.1.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.1' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' implementation files('libs/zxing.jar') }
权限=========================================================================
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.FLASHLIGHT" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<activity android:name=".qrcode.CaptureActivity"></activity> <activity android:name=".qrcode.ResultActivity"></activity>