zxing工具类QRCodeUtils

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.util.DisplayMetrics;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.PlanarYUVLuminanceSource;
import com.google.zxing.Result;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.GlobalHistogramBinarizer;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeWriter;
import com.yukesoft.xinkaapp.R;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import java.util.regex.Pattern;

/**
 * Created by Administrator on 2018/1/31.
 * 二维码图片解析和生成二维码工具类
 * <p>
 * 注意1:二维码解析操作较耗时长,建议在异步线程操作
 * 注意2:生成二维码图片参数较多并且操作耗时,这里使用了构建者模式,默认在异步线程操作
 * <p>
 * 生成二维码使用方法:QRCodeUtils.writeQRImage(context)…设置二维码各种样式…builde("文字",new QRCodeUtils.CallBackQRImage());
 *
 * 解析二维码方法:String text = QRCodeUtils.readQRCode(二维码图片)  ※该方法建议在异步线程中执行
 * <p>
 * <p>
 * 注意3:请确保app已获取到 READ_EXTERNAL_STORAGE 权限
 * 注意4:该工具类基于zxing ,使用时请先导入zxingCore 或基于zxing定制的第三方框架
 * zxingCore.jar最新版(截至2018-05-30)下载地址:https://repo1.maven.org/maven2/com/google/zxing/core/3.3.3/core-3.3.3.jar
 */

public class QRCodeUtils {

    //解析二维码开始

    /**
     * 解析二维码
     *
     * @param path
     * @return
     */
    public static String readQRCode(@NonNull String path) {
        return analysisImage2(path);
    }

    /**
     * 解析二维码
     *
     * @param file
     * @return
     */
    public static String readQRCode(File file) {
        if (file != null && file.exists()) {
            //先直接生成bitmap看能不能解析成功,不能的话再从系统文件获取bitmap然后解析
            return readQRCode(file.getPath());
        } else
            return null;
    }

    /**
     * 解析二维码
     *
     * @param context
     * @param uri     图片uri
     * @return
     */
    public static String readQRCode(Context context, Uri uri) {
        return readQRCode(AllClass.Utils.uriToPath(context, uri));
    }

    public static String readQRCode(Bitmap bitmap) {
        bitmap = AllClass.Utils.compressScale(bitmap);
        String codeText = null;
        codeText = analysisImage(bitmap);
        return codeText;
    }

    /**
     * 解析二维码图片,支持条形码
     *
     * @param scanBitmap
     * @return
     */
    private static String analysisImage(Bitmap scanBitmap) {
        byte[] data = getYUV420sp(scanBitmap.getWidth(), scanBitmap.getHeight(), scanBitmap);
        Hashtable<DecodeHintType, Object> hints = new Hashtable();
        Vector<BarcodeFormat> decodeFormats = new Vector<BarcodeFormat>();

        /*//支持多种类型
        if (decodeFormats == null || decodeFormats.isEmpty()) {
            //设置支持的类型
            decodeFormats.addAll(AllClass.DecodeFormatManager.PRODUCT_FORMATS);
            decodeFormats.addAll(AllClass.DecodeFormatManager.ONE_D_FORMATS);
            decodeFormats.addAll(AllClass.DecodeFormatManager.QR_CODE_FORMATS);
            decodeFormats.addAll(AllClass.DecodeFormatManager.DATA_MATRIX_FORMATS);
        }*/

        //一般支持QR_CODE类型足够了
        decodeFormats.add(BarcodeFormat.QR_CODE);

        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); // 设置二维码内容的编码
        hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);

        PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data,
                scanBitmap.getWidth(),
                scanBitmap.getHeight(),
                0, 0,
                scanBitmap.getWidth(),
                scanBitmap.getHeight(),
                false);

        BinaryBitmap bitmap1 = new BinaryBitmap(new GlobalHistogramBinarizer(source));
        BinaryBitmap bitmap2 = new BinaryBitmap(new HybridBinarizer(source));
        MultiFormatReader reader = new MultiFormatReader();
        Result result = null;
        String text = null;

        //GlobalHistogramBinarizer 扫描效率较高,但精确度不如HybridBinarizer,适合小图片扫描
        //而HybridBinarizer精确度高,但效率相对较低,适合二维码较复杂的情况,这里两种都使用
        try {
            result = reader.decode(bitmap1, hints);
            text = result.getText();
        } catch (NotFoundException e) {
            e.printStackTrace();
        }
        try {
            if (text == null || text.length() == 0) {
                result = reader.decode(bitmap2, hints);
                text = result.getText();
            }
        } catch (NotFoundException e) {
            e.printStackTrace();
        }


        return text;
    }


    private static String analysisImage2(String path) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true; // 先获取原大小
        Bitmap mBitmap = BitmapFactory.decodeFile(path, options);
        options.inJustDecodeBounds = false; // 获取新的大小

        int sampleSize = (int) (options.outWidth / (float) 256);

        if (sampleSize <= 0)
            sampleSize = 1;
        options.inSampleSize = sampleSize;
        mBitmap = BitmapFactory.decodeFile(path, options);
        String codeText = null;
        codeText = analysisImage(mBitmap);
        return codeText;
    }

    private static byte[] getYUV420sp(int inputWidth, int inputHeight, Bitmap scaled) {
        int[] argb = new int[inputWidth * inputHeight];

        scaled.getPixels(argb, 0, inputWidth, 0, 0, inputWidth, inputHeight);

        int requiredWidth = inputWidth % 2 == 0 ? inputWidth : inputWidth + 1;
        int requiredHeight = inputHeight % 2 == 0 ? inputHeight : inputHeight + 1;

        byte[] yuv = new byte[requiredWidth * requiredHeight * 3 / 2];

        encodeYUV420SP(yuv, argb, inputWidth, inputHeight);

        scaled.recycle();
        return yuv;

    }

    private static void encodeYUV420SP(byte[] yuv420sp, int[] argb, int width, int height) {
        // 帧图片的像素大小
        final int frameSize = width * height;
        // ---YUV数据---
        int Y, U, V;
        // Y的index从0开始
        int yIndex = 0;
        // UV的index从frameSize开始
        int uvIndex = frameSize;

        // ---颜色数据---
        int R, G, B;
        //
        int argbIndex = 0;

        // ---循环所有像素点,RGB转YUV---
        for (int j = 0; j < height; j++) {
            for (int i = 0; i < width; i++) {

                R = (argb[argbIndex] & 0xff0000) >> 16;
                G = (argb[argbIndex] & 0xff00) >> 8;
                B = (argb[argbIndex] & 0xff);
                argbIndex++;

                Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
                U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
                V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;

                Y = Math.max(0, Math.min(Y, 255));
                U = Math.max(0, Math.min(U, 255));
                V = Math.max(0, Math.min(V, 255));
                yuv420sp[yIndex++] = (byte) Y;
                if ((j % 2 == 0) && (i % 2 == 0)) {
                    //
                    yuv420sp[uvIndex++] = (byte) V;
                    //
                    yuv420sp[uvIndex++] = (byte) U;
                }
            }
        }
    }

    /**
     *解析图片二维码 完
     */


    //生成二维码开始

    /**
     * 生成二维码图片
     *
     * @param content         内容
     * @param width           要生成的二维码宽度
     * @param height          要生成的二维码高度
     * @param foregroundColor 二维码前景色
     * @param backgroundColor 二维码背景色
     * @param logoBmp         logo图片
     * @param margin          边框的宽
     * @return 生成的二维码
     */
    private static Bitmap writeQRImage(String content, int width, int height
            , int foregroundColor, int backgroundColor, Bitmap logoBmp, int margin
            , Bitmap backBmp,int qRCodeInBaskRatio,QRCodeInBack qrCodeInBack) {
        Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 图像数据转换,使用了矩阵转换
        BitMatrix bitMatrix = null;
        Bitmap bitmap = null;
        try {
            bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
            //更改边框大小,更改后需要重新计算宽高
            bitMatrix = updateBit(bitMatrix, margin);
            width = bitMatrix.getWidth();
            height = bitMatrix.getHeight();

            int[] pixels = new int[width * height];
            // 按照二维码的算法,逐个生成二维码的图片,两个for循环是图片横列扫描的结果
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    if (bitMatrix.get(x, y)) {
                        pixels[y * width + x] = foregroundColor;
                    } else//其他的地方为白色
                        pixels[y * width + x] = backgroundColor;
                }
            }
            // 生成二维码图片的格式,使用ARGB_8888
            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            //设置像素矩阵的范围
            bitmap.setPixels(pixels, 0, width, 0, 0, width, height);

        } catch (WriterException e) {
            e.printStackTrace();
        }
        if (logoBmp != null && bitmap != null)
            bitmap = addLogoToQRImage(logoBmp, bitmap, width, height);


        if (backBmp != null)
            bitmap = addBackQRImage(backBmp, bitmap,qRCodeInBaskRatio,qrCodeInBack);

        return bitmap;
    }

    /**
     * 给二维码添加背景图片
     *
     * @param backBmp 背景图片
     * @param qRImage 二维码
     * @return
     */
    private static Bitmap addBackQRImage(Bitmap backBmp, Bitmap qRImage,int qRCodeInBaskRatio,QRCodeInBack qrCodeInBack) {
        // 获取图片宽高

        if(qRCodeInBaskRatio <=0)
            qRCodeInBaskRatio = 3;

        int qrWidth = qRImage.getWidth();
        int qrheight = qRImage.getHeight();
        if (qrWidth == 0 || qrheight == 0) {
            return backBmp;
        }
        //背景图片大小

        int width = backBmp.getWidth();
        int height = backBmp.getHeight();
        int scale = Math.min(width, height);

        // 图片绘制在二维码中央,合成二维码图片
        // 二维码大小为整体大小的1/2
        float scaleFactor = (float) scale * 1.0f / qRCodeInBaskRatio / qrWidth;
        Canvas canvas = new Canvas(backBmp);
        canvas.drawBitmap(backBmp, 0, 0, null);
        switch (qrCodeInBack){
            case BOTTOM_RIGHT:
                //右下角
                canvas.scale(scaleFactor, scaleFactor, width,
                        height);
                canvas.drawBitmap(qRImage, (width - qrWidth),
                        (height - qrheight), null);
                break;
            case CENTRE:
                //中间
                canvas.scale(scaleFactor,scaleFactor,width/2,height/2);
                canvas.drawBitmap(qRImage,(width - qrWidth)/2,(height - qrheight)/2,null);
                break;
            case TOP_LEFT:
                //左上角
                canvas.scale(scaleFactor,scaleFactor,0,0);
                canvas.drawBitmap(qRImage,0,0,null);
                break;
            case BOTTOM_LIFT:
                //左下角
                canvas.scale(scaleFactor,scaleFactor,0,height);
                canvas.drawBitmap(qRImage,0,(height - qrheight),null);
                break;
            case TOP_RIGHT:
                //右上角
                canvas.scale(scaleFactor,scaleFactor,width,0);
                canvas.drawBitmap(qRImage,(width - qrWidth),0,null);
                break;
        }
        canvas.save();
        canvas.restore();
        return backBmp;
    }


    public enum QRCodeInBack{
        TOP_LEFT,
        BOTTOM_RIGHT,
        TOP_RIGHT,
        BOTTOM_LIFT,
        CENTRE;

    }


    /**
     * 设置边框大小
     *
     * @param matrix
     * @param margin 边框大小
     * @return
     */
    private static BitMatrix updateBit(BitMatrix matrix, int margin) {

        int tempM = margin * 2;
        int[] rec = matrix.getEnclosingRectangle(); // 获取二维码图案的属性
        int resWidth = rec[2] + tempM;
        int resHeight = rec[3] + tempM;
        BitMatrix resMatrix = new BitMatrix(resWidth, resHeight); // 按照自定义边框生成新的BitMatrix
        resMatrix.clear();
        for (int i = margin; i < resWidth - margin; i++) { // 循环,将二维码图案绘制到新的bitMatrix中
            for (int j = margin; j < resHeight - margin; j++) {
                if (matrix.get(i - margin + rec[0], j - margin + rec[1])) {
                    resMatrix.set(i, j);
                }
            }
        }
        return resMatrix;
    }

    /**
     * 添加logo
     *
     * @param logoBmp logo
     * @param qRImage 二维码图片
     * @param width   二维码宽度
     * @param height  二维码高度
     * @return
     */
    private static Bitmap addLogoToQRImage(Bitmap logoBmp, Bitmap qRImage, int width, int height) {
        // 获取图片宽高
        int logoWidth = logoBmp.getWidth();
        int logoHeight = logoBmp.getHeight();
        if (logoWidth == 0 || logoHeight == 0) {
            return qRImage;
        }
        // 图片绘制在二维码中央,合成二维码图片
        // logo大小为二维码整体大小的1/6
        float scaleFactor = width * 1.0f / 6 / logoWidth;
        try {
            Canvas canvas = new Canvas(qRImage);
            canvas.drawBitmap(qRImage, 0, 0, null);
            canvas.scale(scaleFactor, scaleFactor, width / 2,
                    height / 2);
            canvas.drawBitmap(logoBmp, (width - logoWidth) / 2,
                    (height - logoHeight) / 2, null);
            canvas.save();
            canvas.restore();
            return qRImage;
        } catch (Exception e) {
            qRImage = null;
            e.getStackTrace();
        }
        return qRImage;
    }

    //生成二维码图片,这里使用构建者模式
    public static WriteQRImage writeQRImage(Context context) {
        return new WriteQRImage(context);
    }

    public static class WriteQRImage {
        private int width;
        private int height;
        private int foregroundColor;
        private int backgroundColor;
        private Bitmap logoBmp = null;
        private CallBackQRImage callBackQRImage;
        private int margin = 0;
        private Bitmap backBmp = null;
        private int qRCodeInBaskRatio;
        private QRCodeInBack qrCodeInBack;
        private Resources resources;

        private WriteQRImage(Context context) {
            resources = context.getResources();
            DisplayMetrics dm = resources.getDisplayMetrics();
            int widthWin = dm.widthPixels;
            int heightWin = dm.heightPixels;

            width = Math.min(widthWin, heightWin) / 2;
            height = width;
            foregroundColor = Color.BLACK;
            backgroundColor = Color.WHITE;
        }

        //设置二维码宽高,默认为屏幕的1/2
        public WriteQRImage setWidthAndHeight(int width, int height) {
            this.width = width;
            this.height = height;
            return this;
        }

        //二维码前景色,默认为黑色
        public WriteQRImage setForegroundColor(int foregroundColor) {
            this.foregroundColor = foregroundColor;
            return this;
        }

        //二维码背景色,默认为白色
        public WriteQRImage setBackgroundColor(int backgroundColor) {
            this.backgroundColor = backgroundColor;
            return this;
        }
        //设置logog
        public WriteQRImage setLogoBmp(Bitmap logoBmp) {
            this.logoBmp = logoBmp;
            return this;
        }

        //设置logog
        public WriteQRImage setLogoBmp(int logoRes) {
            this.logoBmp = BitmapFactory.decodeResource(resources,logoRes);
            return this;
        }

        //设置边框大小,默认为30
        public WriteQRImage setMargin(int margin) {
            this.margin = margin;
            return this;
        }

        //设置背景图片
        public WriteQRImage setBackBmp(Bitmap backBmp,int qRCodeInBaskRatio,QRCodeInBack qrCodeInBack) {
            this.backBmp = backBmp;
            this.qRCodeInBaskRatio = qRCodeInBaskRatio;
            this.qrCodeInBack = qrCodeInBack;
            return this;
        }

        /**
         * 生成二维码
         *
         * @param content         二维码内容
         * @param callBackQRImage
         */
        public void builde(final String content, CallBackQRImage callBackQRImage) {

            this.callBackQRImage = callBackQRImage;
            if (margin == 0)
                margin = 30;

            if (content == null) {
                if (callBackQRImage != null)
                    callBackQRImage.callBackQRImage(null);
                return;
            }

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Bitmap bitmap = writeQRImage(content, width, height, foregroundColor, backgroundColor, logoBmp, margin, backBmp,qRCodeInBaskRatio,qrCodeInBack);
                    Message message = Message.obtain();
                    message.obj = bitmap;
                    handler.sendMessage(message);
                }
            }).start();
        }

        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Bitmap bitmap = (Bitmap) msg.obj;
                if (callBackQRImage != null)
                    callBackQRImage.callBackQRImage(bitmap);
            }
        };

    }


    public interface CallBackQRImage {
        void callBackQRImage(Bitmap qRImage);
    }

    //生成二维码,完

    //其他需要的类
    private static class AllClass {
        //内置工具类
        private static class Utils {

            /**
             * bitmap压缩
             *
             * @param image
             * @return
             */
            public static Bitmap compressScale(Bitmap image) {
                int pixelW = 400;
                float pixelH = 400;
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                image.compress(Bitmap.CompressFormat.JPEG, 100, baos);

                // 判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
                if (baos.toByteArray().length / 1024 > 1024) {
                    baos.reset();// 重置baos即清空baos
                    image.compress(Bitmap.CompressFormat.JPEG, 80, baos);// 这里压缩50%,把压缩后的数据存放到baos中
                }
                ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
                BitmapFactory.Options newOpts = new BitmapFactory.Options();
                // 开始读入图片,此时把options.inJustDecodeBounds 设回true了
                newOpts.inJustDecodeBounds = true;
                Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
                newOpts.inJustDecodeBounds = false;
                int w = newOpts.outWidth;
                int h = newOpts.outHeight;

                float hh = pixelH;
                float ww = pixelW;
                // 缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
                int be = 1;// be=1表示不缩放
                if (w > h && w > ww) {// 如果宽度大的话根据宽度固定大小缩放
                    be = (int) (newOpts.outWidth / ww);
                } else if (w < h && h > hh) { // 如果高度高的话根据高度固定大小缩放
                    be = (int) (newOpts.outHeight / hh);
                }
                if (be <= 0)
                    be = 1;
                newOpts.inSampleSize = be; // 设置缩放比例
                System.out.println(be + "<<<<<<<be");
                // newOpts.inPreferredConfig = Config.RGB_565;//降低图片从ARGB888到RGB565

                // 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
                isBm = new ByteArrayInputStream(baos.toByteArray());
                bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);

                return bitmap;// 压缩好比例大小后再进行质量压缩

                //return bitmap;
            }


            /**
             * uri 转path
             *
             * @param context
             * @param uri
             * @return
             */
            public static String uriToPath(final Context context, final Uri uri) {

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && DocumentsContract.isDocumentUri(context, uri))
                    uriToPath2(context, uri);
                else
                    return uriToPath1(context, uri);
                return null;
            }


            /**
             * 4.4以上uri转path
             *
             * @param context
             * @param uri
             * @return
             */
            private static String uriToPath2(Context context, final Uri uri) {
                if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];

                    if ("primary".equalsIgnoreCase(type)) {
                        return Environment.getExternalStorageDirectory() + "/" + split[1];
                    }
                }
                // DownloadsProvider
                else if (isDownloadsDocument(uri)) {
                    final String id = DocumentsContract.getDocumentId(uri);
                    final Uri contentUri = ContentUris.withAppendedId(
                            Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

                    return getDataColumn(context, contentUri, null, null);
                } else if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];

                    Uri contentUri = null;
                    if ("image".equals(type)) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    } else if ("video".equals(type)) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    } else if ("audio".equals(type)) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    }

                    final String selection = "_id=?";
                    final String[] selectionArgs = new String[]{split[1]};

                    return getDataColumn(context, contentUri, selection, selectionArgs);
                }
                return null;
            }


            /**
             * android4.4以下uri转path
             *
             * @param context
             * @param uri
             * @return
             */
            private static String uriToPath1(final Context context, final Uri uri) {
                if (null == uri) return null;
                final String scheme = uri.getScheme();
                String data = null;
                if (scheme == null)
                    data = uri.getPath();
                else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
                    data = uri.getPath();
                } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
                    Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
                    if (null != cursor) {
                        if (cursor.moveToFirst()) {
                            int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                            if (index == -1) {
                                index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                            }
                            if (index > -1) {
                                data = cursor.getString(index);
                            }
                        }
                        cursor.close();
                    }
                }
                return data;
            }


            /**
             * Get the value of the data column for this Uri. This is useful for
             * MediaStore Uris, and other file-based ContentProviders.
             *
             * @param context       The context.
             * @param uri           The Uri to query.
             * @param selection     (Optional) Filter used in the query.
             * @param selectionArgs (Optional) Selection arguments used in the query.
             * @return The value of the _data column, which is typically a file path.
             */
            private static String getDataColumn(Context context, Uri uri, String selection,
                                                String[] selectionArgs) {

                Cursor cursor = null;
                final String column = "_data";
                final String[] projection = {column};

                try {
                    cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                            null);
                    if (cursor != null && cursor.moveToFirst()) {
                        final int column_index = cursor.getColumnIndexOrThrow(column);
                        return cursor.getString(column_index);
                    }
                } finally {
                    if (cursor != null)
                        cursor.close();
                }
                return null;
            }

            /**
             * @param uri The Uri to check.
             * @return Whether the Uri authority is ExternalStorageProvider.
             */
            private static boolean isExternalStorageDocument(Uri uri) {
                return "com.android.externalstorage.documents".equals(uri.getAuthority());
            }

            /**
             * @param uri The Uri to check.
             * @return Whether the Uri authority is DownloadsProvider.
             */
            private static boolean isDownloadsDocument(Uri uri) {
                return "com.android.providers.downloads.documents".equals(uri.getAuthority());
            }

            /**
             * @param uri The Uri to check.
             * @return Whether the Uri authority is MediaProvider.
             */
            private static boolean isMediaDocument(Uri uri) {
                return "com.android.providers.media.documents".equals(uri.getAuthority());
            }

            //uri转path完
        }

        //配置解码格式类
        private static class DecodeFormatManager {

            private static final Pattern COMMA_PATTERN = Pattern.compile(",");

            public static final Vector<BarcodeFormat> PRODUCT_FORMATS;
            public static final Vector<BarcodeFormat> ONE_D_FORMATS;
            public static final Vector<BarcodeFormat> QR_CODE_FORMATS;
            public static final Vector<BarcodeFormat> DATA_MATRIX_FORMATS;

            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.RSS14);
                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;
            }

            private static 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 BarcodeFormat}s, such as {@link BarcodeFormat#EAN_13}.
                     * Example: "EAN_13,EAN_8,QR_CODE"
                     * <p>
                     * This overrides {@link #MODE}.
                     */
                    public static final String SCAN_FORMATS = "SCAN_FORMATS";

                    /**
                     * @see 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() {
                    }
                }
            }

        }
    }
}

猜你喜欢

转载自blog.csdn.net/jingzz1/article/details/84395685