wjc
2023-06-06 5308d04e20f3dca6d56ccc3e2b460374540716a6
2023年06月06日18:19:36

自定义二维码扫码页
42个文件已添加
13个文件已修改
3968 ■■■■■ 已修改文件
.idea/misc.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/build.gradle 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/AndroidManifest.xml 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/hdl/photovoltaic/base/BaseFragment.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/hdl/photovoltaic/ui/MyPowerStationActivity.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/hdl/photovoltaic/ui/device/FastScanActivity.java 415 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/hdl/photovoltaic/ui/powerstation/HouseListFragment.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable/back.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable/fast_scan_light_close.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable/fast_scan_light_open.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_fast_scan.xml 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/toolbar_top_view_52.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/values/colors.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/values/strings.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gradle.properties 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
settings.gradle 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/.gitignore 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/build.gradle 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/libs/zxing_3.3.0.jar 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/proguard-rules.pro 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/AndroidManifest.xml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/ContextHelper.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/DeviceHelper.java 469 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/Extras.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/IZxingActivity.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/camera/AutoFocusManager.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/camera/CameraConfigurationManager.java 207 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/camera/CameraManager.java 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/camera/PreviewCallback.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/camera/open/OpenCameraInterface.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/decode/DecodeFormatManager.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/decode/DecodeHandler.java 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/decode/DecodeThread.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/decode/RGBLuminanceSource.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/qrcode/CaptureActivity.java 398 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/utils/BeepManager.java 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/utils/CaptureActivityHandler.java 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/utils/InactivityTimer.java 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/utils/Strings.java 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/utils/Validator.java 202 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/java/com/zxing/utils/ZXingBitmapUtils.java 333 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/drawable-xxhdpi/ic_shadow.png 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/drawable-xxhdpi/scan_capture.9.png 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/drawable-xxhdpi/scan_line.png 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/drawable/back.png 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/drawable/fast_scan_light_close.png 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/drawable/fast_scan_light_open.png 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/drawable/transparent_divider.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/layout/activity_capture.xml 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/layout/toolbar.xml 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/raw/beep.ogg 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/values/colors_ui.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/values/ids.xml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/values/strings.xml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
third-zxing/src/main/res/values/styles.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/misc.xml
@@ -3,7 +3,26 @@
  <component name="DesignSurface">
    <option name="filePathToZoomLevelMap">
      <map>
        <entry key="../../../../../layout/custom_preview.xml" value="0.22923076923076924" />
        <entry key="../../../.gradle/caches/transforms-2/files-2.1/7c2cbaa925629e10707989293f119941/jetified-zxing-android-embedded-3.4.0/res/layout/zxing_barcode_scanner.xml" value="0.20625" />
        <entry key="../../../.gradle/caches/transforms-2/files-2.1/7c2cbaa925629e10707989293f119941/jetified-zxing-android-embedded-3.4.0/res/layout/zxing_capture.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/activity_1.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/activity_123.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/activity_capture.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/activity_fast_scan.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/activity_home_login.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/activity_my_power_station.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/activity_new_capture.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/fragment_house_list.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/fragment_me.xml" value="0.1" />
        <entry key="app/src/main/res/layout/frgment_house_list_line.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/toolbar_top_view_52.xml" value="0.20625" />
        <entry key="app/src/main/res/layout/toolbar_top_view_53.xml" value="0.20625" />
        <entry key="third-zxing/src/main/res/drawable/transparent_divider.xml" value="0.1275" />
        <entry key="third-zxing/src/main/res/layout/activity_capture.xml" value="0.20625" />
        <entry key="third-zxing/src/main/res/layout/toolbar.xml" value="0.20625" />
        <entry key="third-zxing/src/main/res/layout/toolbar_top_view.xml" value="0.20625" />
        <entry key="third-zxing/src/main/res/layout/toolbar_top_view_52.xml" value="0.20625" />
      </map>
    </option>
  </component>
app/build.gradle
@@ -39,8 +39,11 @@
    implementation 'androidx.navigation:navigation-fragment:2.3.5'
    implementation 'androidx.navigation:navigation-ui:2.3.5'
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation project(path: ':third-zxing')
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    implementation 'org.greenrobot:eventbus:3.0.0'
}
app/src/main/AndroidManifest.xml
@@ -1,6 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hdl.photovoltaic">
    xmlns:tools="http://schemas.android.com/tools"
    package="com.hdl.photovoltaic" >
    <uses-permission
        android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
        tools:ignore="ProtectedPermissions" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <application
        android:name=".HDLApp"
@@ -9,7 +18,7 @@
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.PhotovoltaicDebug">
        android:theme="@style/Theme.PhotovoltaicDebug" >
        <activity
            android:name=".ui.device.FastScanActivity"
            android:exported="false" />
@@ -21,7 +30,7 @@
            android:exported="false" />
        <activity
            android:name=".ui.StartActivity"
            android:exported="true">
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
app/src/main/java/com/hdl/photovoltaic/base/BaseFragment.java
@@ -123,7 +123,7 @@
    /**
     * 显示View
     *
     * @param view
     * @param view -
     */
    public void setViewVisible(View view) {
        if (view.getVisibility() != View.VISIBLE && _mActivity != null) {
@@ -134,7 +134,7 @@
    /**
     * 隐藏View
     *
     * @param view
     * @param view -
     */
    protected void setViewGone(View view) {
        if (view.getVisibility() != View.GONE && _mActivity != null) {
@@ -145,7 +145,7 @@
    /**
     * 简单的跳转Activity
     *
     * @param clazz
     * @param clazz -
     */
    protected void startActivity(Class<?> clazz) {
        if (_mActivity != null) {
app/src/main/java/com/hdl/photovoltaic/ui/MyPowerStationActivity.java
@@ -58,7 +58,6 @@
    private void bottomViewChangeOfStyle() {
        if (this.currentFragmentIndex == 0) {
            viewBinding.myPowerStationFcv1.setVisibility(View.VISIBLE);
            viewBinding.myPowerStationFcv2.setVisibility(View.GONE);
            viewBinding.myPowerStationBottomIl1.iconIv.setImageDrawable(AppCompatResources.getDrawable(_mActivity, R.drawable.selectedpowerstation));
app/src/main/java/com/hdl/photovoltaic/ui/device/FastScanActivity.java
@@ -1,17 +1,78 @@
package com.hdl.photovoltaic.ui.device;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Rect;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.DecodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.hdl.photovoltaic.R;
import com.hdl.photovoltaic.base.CustomBaseActivity;
import com.hdl.photovoltaic.databinding.ActivityFastScanBinding;
import com.zxing.IZxingActivity;
import com.zxing.camera.CameraManager;
import com.zxing.decode.DecodeThread;
import com.zxing.decode.RGBLuminanceSource;
import com.zxing.utils.BeepManager;
import com.zxing.utils.CaptureActivityHandler;
import com.zxing.utils.InactivityTimer;
public class FastScanActivity extends CustomBaseActivity {
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Hashtable;
public class FastScanActivity extends CustomBaseActivity implements IZxingActivity, SurfaceHolder.Callback {
    private static final String TAG = com.zxing.qrcode.CaptureActivity.class.getSimpleName();
    private final int REQUEST_CODE = 33;
    private CameraManager cameraManager;
    private CaptureActivityHandler handler;
    private InactivityTimer inactivityTimer;
    private BeepManager beepManager;
    private SurfaceView scanPreview = null;
    private RelativeLayout scanContainer;
    private RelativeLayout scanCropView;
    private Rect mCropRect = null;
    private boolean isHasSurface = false;
    private ActivityFastScanBinding viewBinding;
    @Override
    public Handler getHandler() {
        return handler;
    }
    @Override
    public void drawViewfinder() {
    }
    @Override
    public CameraManager getCameraManager() {
        return cameraManager;
    }
    @Override
    public Object getContentView() {
@@ -21,6 +82,352 @@
    @Override
    public void onBindView(Bundle savedInstanceState) {
//        Window window = getWindow();
//        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//        //设置根视图
//        View mContentView = LayoutInflater.from(this).inflate(R.layout.activity_new_capture, null);
//        setContentView(mContentView);
        //初始化
        initView(savedInstanceState);
        //初始化界面监听器
        initEvent();
    }
    private void initView(Bundle savedInstanceState) {
        scanPreview = findViewById(R.id.new_capture_preview);
        scanContainer = findViewById(R.id.new_capture_rl);
        scanCropView = findViewById(R.id.new_capture_crop_view);
        ImageView scanLine = findViewById(R.id.new_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(2000);
        animation.setRepeatCount(-1);
        animation.setRepeatMode(Animation.RESTART);
        scanLine.startAnimation(animation);
    }
    private void initEvent() {
        viewBinding.newTopBackBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        viewBinding.newTopMoreBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //跳到入网
            }
        });
        viewBinding.newLightIv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.setSelected(!v.isSelected());
                if (v.isSelected()) {
                    viewBinding.newLightIv.setImageDrawable(AppCompatResources.getDrawable(FastScanActivity.this, com.zxing.R.drawable.fast_scan_light_open));
                } else {
                    viewBinding.newLightIv.setImageDrawable(AppCompatResources.getDrawable(FastScanActivity.this, com.zxing.R.drawable.fast_scan_light_close));
                }
                flashLightOnOrOff();
            }
        });
    }
    public void enterGallery() {
        // 进入图库
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        intent.putExtra("return-data", true);
        startActivityForResult(intent, REQUEST_CODE);
    }
    @Override
    protected void onResume() {
        super.onResume();
        cameraManager = new CameraManager(getApplication());
        handler = null;
        if (isHasSurface) {
            initCamera(scanPreview.getHolder());
        } else {
            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.d(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
     */
    @Override
    public void handleDecode(Result rawResult, Bundle bundle) {
        inactivityTimer.onActivity();
        beepManager.playBeepSoundAndVibrate();
        doProcess(rawResult.getText());
        restartPreviewAfterDelay(3000);
    }
    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);
            Toast.makeText(this, com.zxing.R.string.capture_no_camera, Toast.LENGTH_SHORT).show();
            finish();
        } catch (RuntimeException e) {
            Log.w(TAG, "Unexpected error initializing camera", e);
            Toast.makeText(this, com.zxing.R.string.capture_no_camera, Toast.LENGTH_SHORT).show();
            finish();
        }
    }
    public void restartPreviewAfterDelay(long delayMS) {
        if (handler != null) {
            handler.sendEmptyMessageDelayed(com.zxing.R.id.restart_preview, delayMS);
        }
    }
    @Override
    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;
    }
    private void doProcess(String result) {
        Log.d("panlili", "scanResult: " + result);
        /*if (!DeviceHelper.getNetworkState()) {
            Toast.makeText(this, R.string.capture_no_network, Toast.LENGTH_SHORT).show();
            return;
        }*/
        if (TextUtils.isEmpty(result)) {
            Toast.makeText(this, com.zxing.R.string.capture_no_result, Toast.LENGTH_SHORT).show();
        } else {
            Intent intent = new Intent();
            intent.putExtra("data", result);
            setResult(RESULT_OK, intent);
            finish();
        }
    }
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE && resultCode == RESULT_OK && data != null) {
            Uri originalUri = data.getData();
            if (originalUri != null) {
                String path = originalUri.getPath();
                String[] proj = {MediaStore.Images.Media.DATA};
                Cursor cursor = getContentResolver().query(originalUri, proj, null, null, null);
                if (cursor != null) {
                    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                    cursor.moveToFirst();
                    path = cursor.getString(column_index);
                    cursor.close();
                }
                if (!TextUtils.isEmpty(path)) {
                    handleQRCodeFormPhoto(path);
                } else {
                    Toast.makeText(this, "图片已损坏,请重新选择!", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    /**
     * 解析图库选择的二维码
     */
    public void handleQRCodeFormPhoto(final String filePath) {
        Thread dealThread = new Thread(new Runnable() {
            @Override
            public void run() {
                Hashtable<DecodeHintType, String> hints = new Hashtable<>();
                hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
                RGBLuminanceSource source = null;
                try {
                    source = new RGBLuminanceSource(filePath);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
                QRCodeReader reader = new QRCodeReader();
                Result result;
                try {
                    result = reader.decode(binaryBitmap, hints);
                    if (!TextUtils.isEmpty(result.getText())) {
                        dealUIInfo(result.getText());
                    } else {
                        dealUIInfo(null);
                    }
                } catch (NotFoundException | ChecksumException | FormatException e) {
                    dealUIInfo(null);
                    e.printStackTrace();
                }
            }
        });
        dealThread.start();
    }
    private void dealUIInfo(final Object progressInfo) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (progressInfo == null) {
                    Toast.makeText(FastScanActivity.this, com.zxing.R.string.capture_no_result2, Toast.LENGTH_SHORT).show();
                } else {
                    doProcess(progressInfo.toString());
                }
            }
        });
    }
    /**
     * 闪光灯开启或者关闭
     */
    private void flashLightOnOrOff() {
//
        android.hardware.Camera camera = cameraManager.getCamera();
        if (camera == null) {
            return;
        }
        android.hardware.Camera.Parameters parameters = camera.getParameters();
//        判断闪光灯当前状态
        if (Camera.Parameters.FLASH_MODE_OFF.equals(parameters.getFlashMode())) {
            onLight(camera, parameters);
        } else if (Camera.Parameters.FLASH_MODE_TORCH.equals(parameters.getFlashMode())) {
            offLight(camera, parameters);
        }
    }
    private void onLight(android.hardware.Camera camera, Camera.Parameters parameters) {
        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
        camera.setParameters(parameters);
    }
    private void offLight(android.hardware.Camera camera, Camera.Parameters parameters) {
        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
        camera.setParameters(parameters);
    }
}
app/src/main/java/com/hdl/photovoltaic/ui/powerstation/HouseListFragment.java
@@ -1,6 +1,7 @@
package com.hdl.photovoltaic.ui.powerstation;
import android.content.Context;
import android.content.Intent;
import android.hardware.camera2.CameraManager;
import android.os.Bundle;
import android.util.Log;
@@ -14,6 +15,7 @@
import com.hdl.photovoltaic.base.CustomBaseFragment;
import com.hdl.photovoltaic.ui.adapter.HouseInfoAdapter;
import com.hdl.photovoltaic.ui.bean.HouseInfoBean;
import com.hdl.photovoltaic.ui.device.FastScanActivity;
import com.hdl.photovoltaic.utils.FlashLightUtils;
import java.util.ArrayList;
@@ -22,7 +24,6 @@
public class HouseListFragment extends CustomBaseFragment {
    private FragmentHouseListBinding viewBinding;
    private HouseInfoAdapter houseInfoAdapter;
    private FlashLightUtils flashLightUtils;
    private CameraManager manager;
    private List<HouseInfoBean> houseInfoBeanList = null;
@@ -35,7 +36,6 @@
    @Override
    public void onBindView(Bundle savedInstanceState) {
        flashLightUtils = new FlashLightUtils(_mActivity);
        manager = (CameraManager) _mActivity.getSystemService(Context.CAMERA_SERVICE);
        initData();
@@ -49,12 +49,12 @@
    private void initEvent() {
        viewBinding.toolbarTopFragmentHouseListRl.topMoreIv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClass(_mActivity, FastScanActivity.class);
                startActivity(intent);
            }
        });
        //设置下拉箭头颜色
@@ -73,7 +73,6 @@
        viewBinding.toolbarTopFragmentHouseListRl.topTitleTv.setText(R.string.my_power_station_我的电站);
        viewBinding.toolbarTopFragmentHouseListRl.topMoreIv.setVisibility(View.VISIBLE);
        viewBinding.toolbarTopFragmentHouseListRl.topMoreIv.setImageResource(R.drawable.add);
        LinearLayoutManager linearLayout = new LinearLayoutManager(_mActivity);
        houseInfoAdapter = new HouseInfoAdapter(this.houseInfoBeanList);
        viewBinding.fragmentHouseSrlListRc.setLayoutManager(linearLayout);
@@ -89,11 +88,6 @@
            houseInfoBean.setName("电站" + i);
            this.houseInfoBeanList.add(houseInfoBean);
        }
    }
    private void openCamera() {
    }
app/src/main/res/drawable/back.png
app/src/main/res/drawable/fast_scan_light_close.png
app/src/main/res/drawable/fast_scan_light_open.png
app/src/main/res/layout/activity_fast_scan.xml
@@ -1,9 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/new_capture_rl"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.device.FastScanActivity">
    android:background="#636363">
</androidx.constraintlayout.widget.ConstraintLayout>
    <RelativeLayout
        android:id="@+id/new_top_bar_view"
        android:layout_width="match_parent"
        android:layout_height="52dp"
        android:background="#245EC3"
        android:orientation="horizontal">
        <!--1.返回按钮 增大点击区域-->
        <LinearLayout
            android:id="@+id/new_top_back_btn"
            android:layout_width="56dp"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:orientation="horizontal">
            <ImageView
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:layout_gravity="center"
                android:layout_marginLeft="16dp"
                android:scaleType="centerInside"
                android:src="@drawable/back" />
        </LinearLayout>
        <!--2.标题文本-->
        <TextView
            android:id="@+id/new_top_title_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginLeft="60dp"
            android:layout_marginRight="60dp"
            android:fontFamily="sans-serif-medium"
            android:gravity="center"
            android:maxLines="1"
            android:text="快速扫码"
            android:textColor="#FFFFFFFF"
            android:textSize="18sp" />
        <!--3.更多按钮 默认隐藏-->
        <LinearLayout
            android:id="@+id/new_top_more_btn"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentEnd="true"
            android:gravity="center_vertical"
            android:orientation="horizontal">
            <TextView
                android:id="@+id/new_top_connect_tv"
                android:layout_width="wrap_content"
                android:layout_height="20dp"
                android:layout_marginEnd="20dp"
                android:text="@string/device_手动连接"
                android:textColor="@color/text_FFFFFFFF"
                android:textSize="@dimen/text_14" />
        </LinearLayout>
    </RelativeLayout>
    <SurfaceView
        android:id="@+id/new_capture_preview"
        android:layout_width="367dp"
        android:layout_height="367dp"
        android:layout_centerInParent="true" />
    <RelativeLayout
        android:id="@+id/new_capture_crop_view"
        android:layout_width="367dp"
        android:layout_height="367dp"
        android:layout_centerInParent="true"
        android:background="@drawable/scan_capture">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="367dp"
            android:layout_marginTop="182dp">
            <ImageView
                android:id="@+id/new_capture_scan_line"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_marginTop="5dp"
                android:layout_marginBottom="5dp"
                android:src="@drawable/scan_line" />
        </RelativeLayout>
    </RelativeLayout>
    <ImageView
        android:id="@+id/new_light_iv"
        android:layout_width="127dp"
        android:layout_height="127dp"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:layout_marginBottom="13dp"
        android:background="@drawable/fast_scan_light_close" />
</RelativeLayout>
app/src/main/res/layout/toolbar_top_view_52.xml
@@ -57,6 +57,7 @@
            android:scaleType="centerInside"
            android:visibility="gone" />
    </LinearLayout>
</RelativeLayout>
app/src/main/res/values/colors.xml
@@ -29,6 +29,7 @@
    <color name="text_06B92A">#06B92A</color>
    <color name="text_F9FAFB">#F9FAFB</color>
    <color name="text_CBCDD1">#CBCDD1</color>/
    <color name="text_FF245EC3">#FF245EC3</color>
    <color name="text_FF245EC3">#FF245EC3</color>#
    <color name="text_636363">#636363</color>
</resources>
app/src/main/res/values/strings.xml
@@ -42,6 +42,7 @@
    <string name="my_power_station_离线">离线</string>
    <string name="my_power_station_故障">故障</string>
    <string name="my_power_station_运行">运行</string>
    <string name="device_手动连接">手动连接</string>
    <!--我的-->
gradle.properties
@@ -18,4 +18,6 @@
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.nonTransitiveRClass=true
# 可以将v4,v7库转成Android X
android.enableJetifier=true
settings.gradle
@@ -1,2 +1,3 @@
rootProject.name = "PhotovoltaicDebug"
include ':app'
include ':third-zxing'
third-zxing/.gitignore
New file
@@ -0,0 +1 @@
/build
third-zxing/build.gradle
New file
@@ -0,0 +1,45 @@
apply plugin: 'com.android.library'
android {
    compileSdkVersion 29
    buildToolsVersion "29.0.1"
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [moduleName: project.getName()]
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    android {
        lintOptions {
            abortOnError false
        }
    }
}
dependencies {
    api fileTree(include: ['*.jar'], dir: 'libs')
//    compileOnly fileTree(include: ['*.jar'], dir: 'libs')
    androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    testImplementation 'junit:junit:4.12'
    implementation 'com.android.support:support-annotations:28.0.0'
//    api 'com.android.support:appcompat-v7:28.0.0'
    implementation 'androidx.appcompat:appcompat:1.3.0'
}
third-zxing/libs/zxing_3.3.0.jar
Binary files differ
third-zxing/proguard-rules.pro
New file
@@ -0,0 +1,25 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/ye/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
third-zxing/src/main/AndroidManifest.xml
New file
@@ -0,0 +1,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zxing">
    <application >
        <activity
            android:name=".qrcode.CaptureActivity"
            android:configChanges="orientation|keyboardHidden|screenSize|locale"
            android:exported="false"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.Base"/>
    </application>
</manifest>
third-zxing/src/main/java/com/zxing/ContextHelper.java
New file
@@ -0,0 +1,131 @@
package com.zxing;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;
import com.zxing.utils.Strings;
public final class ContextHelper {
    private static Application application;
    private static Class splashCls;
    /**
     * 初始化
     *
     * @param application app
     */
    public static void init(Application application) {
        if (ContextHelper.application == null) {
            ContextHelper.application = application;
        }
    }
    public static Context getAppContext() {
        if (application != null) {
            return application.getApplicationContext();
        }
        return null;
    }
    public static Application getApp() {
        return application;
    }
    public static Resources getResources() {
        Context context = getAppContext();
        if (context != null) {
            return context.getResources();
        }
        return null;
    }
    public static void setSplashCls(Class cls) {
        ContextHelper.splashCls = cls;
    }
    public static Class getSplashCls() {
        return splashCls;
    }
    /**
     * 资源ID获取String
     */
    public static String getString(int stringId) {
        if (getAppContext() == null) {
            return Strings.EMPTY;
        }
        return getAppContext().getString(stringId);
    }
    public static String getString(int stringId, Object... formatArgs) {
        if (getAppContext() == null) {
            return Strings.EMPTY;
        }
        return getAppContext().getString(stringId, formatArgs);
    }
    public static int getDimensionPixelSize(int dimenId) {
        try {
            return getResources().getDimensionPixelSize(dimenId);
        } catch (Resources.NotFoundException e) {
            e.printStackTrace();
        }
        return 0;
    }
    public static int getDimen(int dimenId) {
        try {
            return getResources().getDimensionPixelSize(dimenId);
        } catch (Resources.NotFoundException e) {
            e.printStackTrace();
        }
        return 0;
    }
    /**
     * 获取应用的版本号
     */
    public static String getAppVersion() {
        Context context = getAppContext();
        if (context != null) {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo;
            try {
                packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
                return packageInfo.versionName;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
        return Strings.EMPTY;
    }
    public static boolean isUsable(Context context) {
        if (context == null) {
            return false;
        }
        if (context instanceof Activity && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return !((Activity) context).isDestroyed();
        }
        return true;
    }
    public static void startAppSetting(){
        if(getAppContext()!=null) {
            Intent intent = new Intent("android.settings.SETTINGS");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            getAppContext().startActivity(intent);
        }
    }
}
third-zxing/src/main/java/com/zxing/DeviceHelper.java
New file
@@ -0,0 +1,469 @@
package com.zxing;
import android.app.Activity;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Point;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.provider.MediaStore;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import com.zxing.utils.Strings;
import com.zxing.utils.Validator;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.List;
import java.util.Locale;
import static android.telephony.TelephonyManager.SIM_STATE_READY;
/**
 * 用途:取设备相关信息
 */
public class DeviceHelper {
    /**
     * 获取应用的版本号
     */
    public static String getAppVersion() {
        Context context = ContextHelper.getAppContext();
        if (context != null) {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packageInfo;
            try {
                packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
                return packageInfo.versionName;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
        return Strings.EMPTY;
    }
    public static void ClipData(String content) {
        ClipboardManager cm = (ClipboardManager) ContextHelper.getAppContext().getSystemService(Context.CLIPBOARD_SERVICE);
        // 将文本内容放到系统剪贴板里。
        if (cm != null) {
            cm.setText(content);
        }
    }
    /**
     * 启动应用的设置
     */
    public static void startAppSettings(Activity activity, int requestCode) {
        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
        intent.setData(uri);
        activity.startActivityForResult(intent, requestCode);
    }
    /**
     * 获取版本信息 versioncode
     */
    public static int getVersionCode() {
        final Context context = ContextHelper.getAppContext();
        int version = 1;
        if (context != null) {
            PackageManager packageManager = context.getPackageManager();
            PackageInfo packInfo = null;
            try {
                packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            if (packInfo != null) {
                version = packInfo.versionCode;
            }
        }
        return version;
    }
    /**
     * 获取设备的制造商
     */
    public static String getFactory() {
        return Build.MANUFACTURER;
    }
    /**
     * 获取系统版本号
     */
    public static String getPhoneOS() {
        return "Android " + getSysVersion() + " " + Build.VERSION.RELEASE;
    }
    /**
     * 版本是否在Android6.0 以上
     */
    public static boolean isOverMarshmallow() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }
    /**
     * 获取Android API版本
     */
    public static String getSysVersion() {
        return Build.VERSION.SDK_INT + Strings.EMPTY;
    }
    /**
     * 获取Android API版本
     */
    public static int getSysVersionInt() {
        return Build.VERSION.SDK_INT;
    }
    /**
     * 获取手机型号
     */
    public static String getPhoneModel() {
        String model = Build.BRAND + " " + Build.MODEL;
        if (!TextUtils.isEmpty(model) && model.length() > 50) {
            model = model.substring(0, 49);
        }
        return Validator.replaceHanzi(model);
    }
    /**
     * 判断IMEI是否为纯数字串
     */
    private static boolean isNumber(String str) {
        if (TextUtils.isEmpty(str)) {
            return false;
        }
        boolean isNumber = true;
        int i;
        char c;
        for (i = 0; i < str.length(); i++) {
            c = str.charAt(i);
            if (!((c >= '0') && (c <= '9')) || "000000000000000".equals(str) || "0".equals(str)) {
                isNumber = false;
                break;
            }
        }
        return isNumber;
    }
    private static String loadFileAsString(String fileName) throws Exception {
        FileReader reader = new FileReader(fileName);
        String text = loadReaderAsString(reader);
        reader.close();
        return text;
    }
    private static String loadReaderAsString(Reader reader) throws Exception {
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[4096];
        int readLength = reader.read(buffer);
        while (readLength >= 0) {
            builder.append(buffer, 0, readLength);
            readLength = reader.read(buffer);
        }
        return builder.toString();
    }
    /**
     * 判断mac地址是否合法
     */
    private static boolean isCorrectMacAddress(String address) {
        boolean flag = false;
        if (!TextUtils.isEmpty(address) && address.length() == 17) {
            address = address.replaceAll(":", Strings.EMPTY);
            flag = isHex(address);
        }
        return flag;
    }
    /**
     * 判断是否为纯16进制数字串
     */
    private static boolean isHex(String str) {
        boolean isHexFlg = true;
        int i;
        char c;
        for (i = 0; i < str.length(); i++) {
            c = str.charAt(i);
            if (!(((c >= '0') && (c <= '9')) ||
                    ((c >= 'A') && (c <= 'F')) ||
                    (c >= 'a') && (c <= 'f'))) {
                isHexFlg = false;
                break;
            }
        }
        return isHexFlg;
    }
    /**
     * 判断系统中是否存在可以启动的相机应用
     *
     * @return 存在返回true,不存在返回false
     */
    public static boolean hasCamera(Context context) {
        PackageManager packageManager = context.getPackageManager();
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        return list.size() > 0;
    }
    /**
     * 检测系统是否为MIUI
     */
    private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
    private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
    private static final String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";
    /**
     * 获取渠道
     */
    public static String getChannel() {
        return "";
    }
    /**
     * 获取手机宽高
     */
    public static String getPhonePixels(Activity activity) {
        if (activity != null) {
            DisplayMetrics dm = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
            int widthPixels = dm.widthPixels;
            int heightPixels = dm.heightPixels;
            return widthPixels + "-" + heightPixels;
        }
        return "0-0";
    }
    /**
     * x
     * 屏幕宽度
     */
    public static int getDeviceWidth(Context context) {
        if (context != null) {
            WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
            if (wm != null) {
                Point p = new Point();
                wm.getDefaultDisplay().getSize(p);
                return p.x;
            }
        }
        return 0;
    }
    /**
     * 屏幕宽度
     */
    public static int getDeviceWidth(Activity activity) {
        if (activity != null) {
            DisplayMetrics dm = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
            return dm.widthPixels;
        }
        return 0;
    }
    /**
     * 屏幕高度
     */
    public static int getDeviceHeight(Activity activity) {
        if (activity != null) {
            DisplayMetrics dm = new DisplayMetrics();
            activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
            return dm.heightPixels;
        }
        return 0;
    }
    /**
     * 判断当前有没有网络连接
     */
    public static boolean getNetworkState() {
        Context context = ContextHelper.getAppContext();
        if (context != null) {
            ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkinfo = manager.getActiveNetworkInfo();
            return !(networkinfo == null || !networkinfo.isAvailable());
        }
        return false;
    }
    /**
     * SD卡是否挂载
     */
    public static boolean mountedSdCard() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
    }
    /**
     * 检测应用是否安装
     **/
    public static boolean isApkInstalled(String packageName) {
        Context context = ContextHelper.getAppContext();
        if (context != null) {
            final PackageManager packageManager = context.getPackageManager();
            List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
            for (int i = 0; i < pinfo.size(); i++) {
                if (pinfo.get(i).packageName.equalsIgnoreCase(packageName)) {
                    return true;
                }
            }
            return false;
        }
        return false;
    }
    /**
     * 打电话
     */
    public static void callPhone(Activity activity, String phone) {
        Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phone));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        activity.startActivity(intent);
    }
    /**
     * 调用系统发送短信
     */
    public static void sendSMSView(Activity activity, String phone, String sms) {
        Uri smsToUri = Uri.parse("smsto:" + phone);
        Intent sendIntent = new Intent(Intent.ACTION_SENDTO, smsToUri);
        sendIntent.putExtra("sms_body", sms);
        activity.startActivity(sendIntent);
    }
    private static TelephonyManager getTelManager() {
        Context context = ContextHelper.getAppContext();
        if (context == null) {
            return null;
        }
        return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    }
    /**
     * 获取ISO国家码,相当于提供SIM卡的国家码
     */
    public static String getSimCountryIso() {
        if (getTelManager() != null) {
            return getTelManager().getSimCountryIso();
        }
        return Strings.EMPTY;
    }
    /**
     * 获取运营商名称
     */
    public static String getSimOperatorName() {
        if (getTelManager() != null && SIM_STATE_READY == getTelManager().getSimState()) {
            return getTelManager().getSimOperatorName();
        }
        return Strings.EMPTY;
    }
    /**
     * 获取系统运行内存大小 单位KB
     */
    public static long getTotalMemory() {
        String str1 = "/proc/meminfo";// 系统内存信息文件
        String str2;
        String[] arrayOfString;
        long initial_memory = 0;
        try {
            FileReader localFileReader = new FileReader(str1);
            BufferedReader localBufferedReader = new BufferedReader(
                    localFileReader, 8192);
            str2 = localBufferedReader.readLine();// 读取meminfo第一行,系统总内存大小
            if (TextUtils.isEmpty(str2)) {
                arrayOfString = str2.split("\\s+");
                initial_memory = Integer.valueOf(arrayOfString[1]);// 获得系统总内存,单位是KB
            }
            localBufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return initial_memory;// Byte转换为KB或者MB,内存大小规格化
    }
    /**
     * 设备语言编码
     */
    public static String getLanguage() {
        String language = Strings.EMPTY;
        Resources resources = ContextHelper.getResources();
        if (resources != null) {
            Locale locale = ContextHelper.getResources().getConfiguration().locale;
            language = locale.getLanguage();
        }
        return language;
    }
    /**
     * 获取机身总存储(不包含SD卡)
     */
    public static long getRomMemory() {
        long[] romInfo = new long[1];
        File path = Environment.getDataDirectory();
        StatFs stat = new StatFs(path.getPath());
        long blockSize = stat.getBlockSize();
        long totalBlocks = stat.getBlockCount();
        //Total rom memory
        romInfo[0] = blockSize * totalBlocks;
        return romInfo[0];
    }
    /**
     * 获取CPU最大频率(单位KHZ)
     */
    public static String getMaxCpuFreq() {
        StringBuilder result = new StringBuilder(Strings.EMPTY);
        ProcessBuilder cmd;
        try {
            String[] args = {"/system/bin/cat",
                    "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"};
            cmd = new ProcessBuilder(args);
            Process process = cmd.start();
            InputStream in = process.getInputStream();
            byte[] re = new byte[24];
            while (in.read(re) != -1) {
                result.append(new String(re));
            }
            in.close();
        } catch (IOException ex) {
            ex.printStackTrace();
            result = new StringBuilder("N/A");
        }
        return result.toString().trim();
    }
    /**
     * 是否取到所有信息
     */
    private static boolean isGetSuccess() {
        return !TextUtils.isEmpty(getPhoneModel()) && !TextUtils.isEmpty(getFactory())
                && !TextUtils.isEmpty(getMaxCpuFreq()) && getRomMemory() > 0 && getTotalMemory() > 0;
    }
}
third-zxing/src/main/java/com/zxing/Extras.java
New file
@@ -0,0 +1,34 @@
package com.zxing;
/**
 * 跨模块参数定义
 * 注意:此类仅仅用于存放跨模块的参数,模块内的参数请放在模块的constants理
 * <p>
 *
 */
public interface Extras {
    interface device{
        String EXREAS_CHANNEL = "extra_channel";
        String EXTRAS_DEVICE_DISPATCH = "extra_device_dispatch";
        String EXTRAS_FROM_DISPATCH = "extra_from_dispatch";
    }
    interface enterprise {
        String cropId = "extra_crop_id";
        String appId = "extra_app_id";
        String deptId = "extra_dept_id";
        String CREATE_DEPT = "extra_create_dept";//组织架构创建部门
    }
    /**
     * from
     **/
    interface FROM {
        String FROM = "from";
        String SCAN_BACK = "scan";
        String H5_SCAN_JUMP = "scan_jump";
    }
}
third-zxing/src/main/java/com/zxing/IZxingActivity.java
New file
@@ -0,0 +1,28 @@
package com.zxing;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import com.google.zxing.Result;
import com.zxing.camera.CameraManager;
public interface IZxingActivity {
    Handler getHandler();
    void startActivity(Intent intent);
    void setResult(int code, Intent intent);
    void finish();
    void drawViewfinder();
    CameraManager getCameraManager();
    Rect getCropRect();
    void handleDecode(Result obj, Bundle bundle);
}
third-zxing/src/main/java/com/zxing/camera/AutoFocusManager.java
New file
@@ -0,0 +1,114 @@
package com.zxing.camera;
import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.RejectedExecutionException;
public class AutoFocusManager implements Camera.AutoFocusCallback {
    private static final String TAG = AutoFocusManager.class.getSimpleName();
    private static final long AUTO_FOCUS_INTERVAL_MS = 1800L;
    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 final boolean useAutoFocus;
    private final Camera camera;
    private boolean stopped;
    private boolean focusing;
    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 {
                newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
                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;
        }
    }
}
third-zxing/src/main/java/com/zxing/camera/CameraConfigurationManager.java
New file
@@ -0,0 +1,207 @@
package com.zxing.camera;
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;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
/**
 * 描述: 该类主要负责设置相机的参数信息,获取最佳的预览界面
 */
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;
    }
}
third-zxing/src/main/java/com/zxing/camera/CameraManager.java
New file
@@ -0,0 +1,195 @@
package com.zxing.camera;
import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.hardware.Camera;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.os.Build;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;
import com.zxing.camera.open.OpenCameraInterface;
import java.io.IOException;
/**
 * This object wraps the Camera service object and expects to be the only one
 * talking to it. The implementation encapsulates the steps needed to take
 * preview-sized images, which are used for both preview and decoding.
 */
public class CameraManager {
    private static final String TAG = CameraManager.class.getSimpleName();
    private boolean status = false;     // 记录手机状态
    private final Context context;
    private final CameraConfigurationManager configManager;
    /**
     * 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;
    private Camera camera;
    private AutoFocusManager autoFocusManager;
    private boolean initialized;
    private boolean previewing;
    private int requestedCameraId = -1;
    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 Camera.Size getPreviewSize() {
        if (null != camera) {
            return camera.getParameters().getPreviewSize();
        }
        return null;
    }
    public Camera getCamera() {
       return camera;
    }
}
third-zxing/src/main/java/com/zxing/camera/PreviewCallback.java
New file
@@ -0,0 +1,40 @@
package com.zxing.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");
        }
    }
}
third-zxing/src/main/java/com/zxing/camera/open/OpenCameraInterface.java
New file
@@ -0,0 +1,69 @@
package com.zxing.camera.open;
import android.hardware.Camera;
import android.util.Log;
public class OpenCameraInterface {
    private static final String TAG = OpenCameraInterface.class.getName();
    /**
     * Opens the requested camera with {@link Camera#open(int)}, if one exists.
     *
     * @param cameraId camera ID of the camera to use. A negative value means
     *                 "no preference"
     * @return handle to {@link Camera} that was opened
     */
    public static Camera open(int cameraId) {
        int numCameras = Camera.getNumberOfCameras();
        if (numCameras == 0) {
            Log.w(TAG, "No cameras!");
            return null;
        }
        boolean explicitRequest = cameraId >= 0;
        if (!explicitRequest) {
            // Select a camera if no explicit camera requested
            int index = 0;
            while (index < numCameras) {
                Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
                Camera.getCameraInfo(index, cameraInfo);
                if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                    break;
                }
                index++;
            }
            cameraId = index;
        }
        Camera camera;
        if (cameraId < numCameras) {
            Log.i(TAG, "Opening camera #" + cameraId);
            camera = Camera.open(cameraId);
        } else {
            if (explicitRequest) {
                Log.w(TAG, "Requested camera does not exist: " + cameraId);
                camera = null;
            } else {
                Log.i(TAG, "No camera facing back; returning camera #0");
                camera = Camera.open(0);
            }
        }
        return camera;
    }
    /**
     * Opens a rear-facing camera with {@link Camera#open(int)}, if one exists,
     * or opens camera 0.
     *
     * @return handle to {@link Camera} that was opened
     */
    public static Camera open() {
        return open(-1);
    }
}
third-zxing/src/main/java/com/zxing/decode/DecodeFormatManager.java
New file
@@ -0,0 +1,37 @@
package com.zxing.decode;
import com.google.zxing.BarcodeFormat;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Set;
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;
    }
}
third-zxing/src/main/java/com/zxing/decode/DecodeHandler.java
New file
@@ -0,0 +1,136 @@
package com.zxing.decode;
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.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;
import com.zxing.IZxingActivity;
import com.zxing.R;
import java.io.ByteArrayOutputStream;
import java.util.Map;
public class DecodeHandler extends Handler {
    private final IZxingActivity activity;
    private final MultiFormatReader multiFormatReader;
    private boolean running = true;
    public DecodeHandler(IZxingActivity activity, Map<DecodeHintType, Object> hints) {
        multiFormatReader = new MultiFormatReader();
        multiFormatReader.setHints(hints);
        this.activity = activity;
    }
    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());
    }
    @Override
    public void handleMessage(Message message) {
        if (!running) {
            return;
        }
        if (message.what == R.id.decode) {
            decode((byte[]) message.obj, message.arg1, message.arg2);
        } else if (message.what == R.id.quit) {
            running = false;
            Looper.myLooper().quit();
        }
    }
    /**
     * Decode the data within the viewfinder rectangle, and time how long it
     * took. For efficiency, reuse the same reader objects from one decode to
     * the next.
     *
     * @param data   The YUV preview frame.
     * @param width  The width of the preview frame.
     * @param height The height of the preview frame.
     */
    private void decode(byte[] data, int width, int height) {
        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();
            }
        }
    }
    /**
     * 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);
    }
}
third-zxing/src/main/java/com/zxing/decode/DecodeThread.java
New file
@@ -0,0 +1,82 @@
package com.zxing.decode;
import android.os.Handler;
import android.os.Looper;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.zxing.IZxingActivity;
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;
/**
 * This thread does all the heavy lifting of decoding the images.
 */
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 IZxingActivity activity;
    private final Map<DecodeHintType, Object> hints;
    private final CountDownLatch handlerInitLatch;
    private Handler handler;
    public DecodeThread(IZxingActivity 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();
    }
}
third-zxing/src/main/java/com/zxing/decode/RGBLuminanceSource.java
New file
@@ -0,0 +1,72 @@
package com.zxing.decode;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import com.google.zxing.LuminanceSource;
import java.io.FileNotFoundException;
public class RGBLuminanceSource extends LuminanceSource {
    private final byte[] luminances;
    public RGBLuminanceSource(String path) throws FileNotFoundException {
        this(loadBitmap(path));
    }
    public RGBLuminanceSource(Bitmap bitmap) {
        super(bitmap.getWidth(), bitmap.getHeight());
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int[] pixels = new int[width * height];
        bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
        // In order to measure pure decoding speed, we convert the entire image
        // to a greyscale array
        // up front, which is the same as the Y channel of the
        // YUVLuminanceSource in the real app.
        luminances = new byte[width * height];
        for (int y = 0; y < height; y++) {
            int offset = y * width;
            for (int x = 0; x < width; x++) {
                int pixel = pixels[offset + x];
                int r = (pixel >> 16) & 0xff;
                int g = (pixel >> 8) & 0xff;
                int b = pixel & 0xff;
                if (r == g && g == b) {
                    // Image is already greyscale, so pick any channel.
                    luminances[offset + x] = (byte) r;
                } else {
                    // Calculate luminance cheaply, favoring green.
                    luminances[offset + x] = (byte) ((r + g + g + b) >> 2);
                }
            }
        }
    }
    @Override
    public byte[] getRow(int y, byte[] row) {
        if (y < 0 || y >= getHeight()) {
            throw new IllegalArgumentException(
                    "Requested row is outside the image: " + y);
        }
        int width = getWidth();
        if (row == null || row.length < width) {
            row = new byte[width];
        }
        System.arraycopy(luminances, y * width, row, 0, width);
        return row;
    }
    @Override
    public byte[] getMatrix() {
        return luminances;
    }
    private static Bitmap loadBitmap(String path) throws FileNotFoundException {
        Bitmap bitmap = BitmapFactory.decodeFile(path);
        if (bitmap == null) {
            throw new FileNotFoundException("Couldn't open " + path);
        }
        return bitmap;
    }
}
third-zxing/src/main/java/com/zxing/qrcode/CaptureActivity.java
New file
@@ -0,0 +1,398 @@
package com.zxing.qrcode;///*
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
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.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import androidx.appcompat.content.res.AppCompatResources;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.DecodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.NotFoundException;
import com.google.zxing.Result;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.zxing.IZxingActivity;
import com.zxing.R;
import com.zxing.camera.CameraManager;
import com.zxing.decode.DecodeThread;
import com.zxing.decode.RGBLuminanceSource;
import com.zxing.utils.BeepManager;
import com.zxing.utils.CaptureActivityHandler;
import com.zxing.utils.InactivityTimer;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Hashtable;
/**
 * 用途:扫一扫
 */
public final class CaptureActivity extends Activity implements IZxingActivity, SurfaceHolder.Callback {
    private static final String TAG = CaptureActivity.class.getSimpleName();
    private final int REQUEST_CODE = 33;
    private CameraManager cameraManager;
    private CaptureActivityHandler handler;
    private InactivityTimer inactivityTimer;
    private BeepManager beepManager;
    private SurfaceView scanPreview = null;
    private RelativeLayout scanContainer;
    private RelativeLayout scanCropView;
    private LinearLayout backll;
    private ImageView light_iv;
    private Rect mCropRect = null;
    private boolean isHasSurface = false;
    @Override
    public Handler getHandler() {
        return handler;
    }
    @Override
    public void drawViewfinder() {
    }
    @Override
    public CameraManager getCameraManager() {
        return cameraManager;
    }
    public int getRootLayoutId() {
        return R.layout.activity_capture;
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Window window = getWindow();
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        //设置根视图
        View mContentView = LayoutInflater.from(this).inflate(getRootLayoutId(), null);
        setContentView(mContentView);
        afterViewBind(mContentView, savedInstanceState);
    }
    public void afterViewBind(View rootView, Bundle savedInstanceState) {
        light_iv = findViewById(R.id.light_iv);
        backll = findViewById(R.id.top_back_btn);
        backll.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        scanPreview = findViewById(R.id.capture_preview);
        scanContainer = findViewById(R.id.capture_container);
        scanCropView = findViewById(R.id.capture_crop_view);
        ImageView scanLine = 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(2000);
        animation.setRepeatCount(-1);
        animation.setRepeatMode(Animation.RESTART);
        scanLine.startAnimation(animation);
        light_iv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                v.setSelected(!v.isSelected());
                if (v.isSelected()) {
//                    cameraManager.open();
                    light_iv.setImageDrawable(AppCompatResources.getDrawable(CaptureActivity.this, R.drawable.fast_scan_light_open));
                } else {
//                    cameraManager.close();
                    light_iv.setImageDrawable(AppCompatResources.getDrawable(CaptureActivity.this, R.drawable.fast_scan_light_close));
                }
            }
        });
    }
    public void enterGallery() {
        // 进入图库
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        intent.putExtra("return-data", true);
        startActivityForResult(intent, REQUEST_CODE);
    }
    @Override
    protected void onResume() {
        super.onResume();
        cameraManager = new CameraManager(getApplication());
        handler = null;
        if (isHasSurface) {
            initCamera(scanPreview.getHolder());
        } else {
            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.d(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
     */
    @Override
    public void handleDecode(Result rawResult, Bundle bundle) {
        inactivityTimer.onActivity();
        beepManager.playBeepSoundAndVibrate();
        doProcess(rawResult.getText());
        restartPreviewAfterDelay(3000);
    }
    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);
            Toast.makeText(this, R.string.capture_no_camera, Toast.LENGTH_SHORT).show();
            finish();
        } catch (RuntimeException e) {
            Log.w(TAG, "Unexpected error initializing camera", e);
            Toast.makeText(this, R.string.capture_no_camera, Toast.LENGTH_SHORT).show();
            finish();
        }
    }
    public void restartPreviewAfterDelay(long delayMS) {
        if (handler != null) {
            handler.sendEmptyMessageDelayed(R.id.restart_preview, delayMS);
        }
    }
    @Override
    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;
    }
    private void doProcess(String result) {
        Log.d("panlili", "scanResult: " + result);
        /*if (!DeviceHelper.getNetworkState()) {
            Toast.makeText(this, R.string.capture_no_network, Toast.LENGTH_SHORT).show();
            return;
        }*/
        if (TextUtils.isEmpty(result)) {
            Toast.makeText(this, R.string.capture_no_result, Toast.LENGTH_SHORT).show();
        } else {
            Intent intent = new Intent();
            intent.putExtra("data", result);
            setResult(RESULT_OK, intent);
            finish();
        }
    }
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE && resultCode == RESULT_OK && data != null) {
            Uri originalUri = data.getData();
            if (originalUri != null) {
                String path = originalUri.getPath();
                String[] proj = {MediaStore.Images.Media.DATA};
                Cursor cursor = getContentResolver().query(originalUri, proj, null, null, null);
                if (cursor != null) {
                    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                    cursor.moveToFirst();
                    path = cursor.getString(column_index);
                    cursor.close();
                }
                if (!TextUtils.isEmpty(path)) {
                    handleQRCodeFormPhoto(path);
                } else {
                    Toast.makeText(this, "图片已损坏,请重新选择!", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    /**
     * 解析图库选择的二维码
     */
    public void handleQRCodeFormPhoto(final String filePath) {
        Thread dealThread = new Thread(new Runnable() {
            @Override
            public void run() {
                Hashtable<DecodeHintType, String> hints = new Hashtable<>();
                hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
                RGBLuminanceSource source = null;
                try {
                    source = new RGBLuminanceSource(filePath);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source));
                QRCodeReader reader = new QRCodeReader();
                Result result;
                try {
                    result = reader.decode(binaryBitmap, hints);
                    if (!TextUtils.isEmpty(result.getText())) {
                        dealUIInfo(result.getText());
                    } else {
                        dealUIInfo(null);
                    }
                } catch (NotFoundException | ChecksumException | FormatException e) {
                    dealUIInfo(null);
                    e.printStackTrace();
                }
            }
        });
        dealThread.start();
    }
    private void dealUIInfo(final Object progressInfo) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (progressInfo == null) {
                    Toast.makeText(CaptureActivity.this, R.string.capture_no_result2, Toast.LENGTH_SHORT).show();
                } else {
                    doProcess(progressInfo.toString());
                }
            }
        });
    }
}
third-zxing/src/main/java/com/zxing/utils/BeepManager.java
New file
@@ -0,0 +1,125 @@
package com.zxing.utils;
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.zxing.R;
import java.io.Closeable;
import java.io.IOException;
/**
 * Manages beeps and vibrations for {}.
 */
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 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 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 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;
        }
    }
}
third-zxing/src/main/java/com/zxing/utils/CaptureActivityHandler.java
New file
@@ -0,0 +1,95 @@
package com.zxing.utils;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import com.google.zxing.Result;
import com.zxing.IZxingActivity;
import com.zxing.R;
import com.zxing.camera.CameraManager;
import com.zxing.decode.DecodeThread;
/**
 * This class handles all the messaging which comprises the state machine for
 * capture.
 */
public class CaptureActivityHandler extends Handler {
    private final IZxingActivity activity;
    private final DecodeThread decodeThread;
    private final CameraManager cameraManager;
    private State state;
    public CaptureActivityHandler(IZxingActivity 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) {
        if (message.what == R.id.restart_preview) {
            restartPreviewAndDecode();
        } else if (message.what == R.id.decode_succeeded) {
            state = State.SUCCESS;
            Bundle bundle = message.getData();
            activity.handleDecode((Result) message.obj, bundle);
        } else if (message.what == 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);
        } else if (message.what == R.id.return_scan_result) {
            activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
            activity.finish();
        }
    }
    public void quitSynchronously() {
        state = State.DONE;
        try {
            cameraManager.stopPreview();
        } catch (RuntimeException e) {
        }
        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);
        }
    }
    private enum State {
        PREVIEW, SUCCESS, DONE
    }
}
third-zxing/src/main/java/com/zxing/utils/InactivityTimer.java
New file
@@ -0,0 +1,108 @@
package com.zxing.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;
        }
    }
}
third-zxing/src/main/java/com/zxing/utils/Strings.java
New file
@@ -0,0 +1,179 @@
package com.zxing.utils;
import android.text.TextUtils;
import java.util.Iterator;
import java.util.regex.Pattern;
public abstract class Strings {
    public static final String EMPTY = "";
    public static final String BLANK = " ";
    public static final String EQUAL = "=";
    public static final String AND = "&";
    public static final String QMARK = "?";
    public static final String TRUE = "true";
    public static final String FALSE = "false";
    public static final String CANCEL = "cancel";
    public static final String NULL_STR = "null";
    public static final String SUCCESS = "success";
    public static final String FAIL = "fail";
    public static final String ZERO = "0";
    public static final String SEMICOLON = ";";
    public static final String SPLITE = "/";
    public static final String AT = "@";
    public static final String COMMA = ",";
    public static final String FILE_PRE = "file://";
    public static final String HTTP_PRE = "http";
    public static final String COLON = ":";
    public static final String WRAP = "";
    public static final String STAR = "*";
    public static final String MORE = "...";
    /**
     * 去除字符串中的空格
     */
    public static String trimAll(CharSequence s) {
        if (s == null || s.length() == 0) return Strings.EMPTY;
        StringBuilder sb = new StringBuilder(s.length());
        for (int i = 0, L = s.length(); i < L; i++) {
            char c = s.charAt(i);
            if (c != ' ') sb.append(c);
        }
        return sb.toString();
    }
    /**
     * 判断是否为手机号码
     */
    public static boolean isPhoneNum(String phoneNum) {
        if (phoneNum == null || phoneNum.length() != 11) return false;
        if (!TextUtils.isDigitsOnly(phoneNum)) return false;
        Pattern p = Pattern.compile("^((13[0-9])|(14[0-9])|(15[^4,\\D])|(17[0-9])|(18[0-9]))\\d{8}$");
        return p.matcher(phoneNum).find();
    }
    /**
     * 判断是否为座机号码
     */
    public static boolean isTelNum(String num) {
        if (TextUtils.isEmpty(num)) return false;
        Pattern p = Pattern.compile("(\\(\\d{3,4}\\)|\\d{3,4}-|\\s)?\\d{8}");
        return p.matcher(num).find();
    }
    /**
     * 判断字符串中是否有中文,有中文返回true
     */
    public static boolean isChinese(String string) {
        boolean flag = false;
        for (int i = 0, L = string.length(); i < L; i++) {
            char c = string.charAt(i);
            if ((c >= 0x4e00) && (c <= 0x9FA5)) {
                flag = true;
            } else {
                return false;
            }
        }
        return flag;
    }
    /**
     * 判断字符长度是否在范围里面。 当start end 为 -1 时,表示字符长度不考虑上线或下线
     *
     * @param str
     * @param start
     * @param end
     * @return
     */
    public static boolean isLengthInRange(String str, int start, int end) {
        boolean isInRange = true;
        int length = str.length();
        if (start != -1 && length < start) {
            isInRange = false;
        }
        if (end != -1 && end < length) {
            isInRange = false;
        }
        return isInRange;
    }
    /**
     * 字符串转换为long型
     */
    public static long toLong(String text, long defaultVal) {
        if (TextUtils.isDigitsOnly(text)) {
            try {
                return Long.parseLong(text);
            } catch (NumberFormatException e) {
            }
        }
        return defaultVal;
    }
    /**
     * 字符串转换为int
     */
    public static int toInt(String text, int defaultVal) {
        if (TextUtils.isDigitsOnly(text)) {
            try {
                return Integer.parseInt(text);
            } catch (NumberFormatException e) {
            }
        }
        return defaultVal;
    }
    public static String join(Iterable<?> iterable, String separator) {
        // handle null, zero and one elements before building a buffer
        if (iterable == null) {
            return null;
        }
        Iterator<?> iterator = iterable.iterator();
        if (!iterator.hasNext()) {
            return EMPTY;
        }
        Object first = iterator.next();
        if (!iterator.hasNext()) {
            return toString(first);
        }
        // two or more elements
        StringBuffer buf = new StringBuffer(256); // Java default is 16, probably too small
        if (first != null) {
            buf.append(first);
        }
        while (iterator.hasNext()) {
            if (separator != null) {
                buf.append(separator);
            }
            Object obj = iterator.next();
            if (obj != null) {
                buf.append(obj);
            }
        }
        return buf.toString();
    }
    public static String toString(Object obj) {
        return obj == null ? "" : obj.toString();
    }
    /**
     * 判断是否为字符串是否为空
     */
    public static boolean toBoolean(String property, boolean defaultVal) {
        return property == null ? defaultVal : Boolean.valueOf(property);
    }
    public static String format(String str, Object... obj) {
        try {
            return String.format(str, obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }
}
third-zxing/src/main/java/com/zxing/utils/Validator.java
New file
@@ -0,0 +1,202 @@
package com.zxing.utils;
import android.annotation.SuppressLint;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * 正则表达式
 *
 */
@SuppressLint("WrongConstant")
public class Validator {
    public static boolean password(String password) {
        return password.matches("[0-9a-zA-Z]{8,16}") && !password.matches("[0-9]+") && !password.matches("[a-zA-Z]+");
    }
    public static List<String> findMac(String src) {
        List<String> list = new ArrayList<String>();
        if (src == null || "".equals(src))
            return list;
        Pattern pattern = Pattern
                .compile("[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}:[0-9a-z]{2}");
        Matcher matcher = pattern.matcher(src);
        while (matcher.find()) {
            list.add(matcher.group(0));
        }
        return list;
    }
    public static List<String> findColor(String src) {
        List<String> list = new ArrayList<String>();
        if (src == null || src.equals(""))
            return list;
        Pattern pattern = Pattern
                .compile("#[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8}");
        Matcher matcher = pattern.matcher(src);
        while (matcher.find()) {
            list.add(matcher.group(0));
        }
        return list;
    }
    /**
     * 去除汉字,归正编码
     */
    public static String replaceHanzi(String input) {
        if (TextUtils.isEmpty(input)) {
            return "";
        }
        /**
         * 归正编码
         */
        byte[] bytes = input.getBytes();
        String info = "";
        for (int i = 0; i < bytes.length; i++) {
            if (bytes[i] < 0) {
                bytes[i] = 32;
            }
            info = info + new String(new byte[]{bytes[i]});
        }
        /**
         * 去除中文
         */
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(info);
        List<String> inputs = new ArrayList<>();
        if (m.find()) {
            for (int i = 0; i < info.length(); i++) {
                String ever = info.substring(i, i + 1);
                Matcher m1 = p.matcher(ever);
                if (m1.find()) {
                    ever = "";
                }
                inputs.add(ever);
            }
            String inputNew = "";
            for (int i = 0; i < inputs.size(); i++) {
                inputNew = inputNew + inputs.get(i);
            }
            return inputNew.trim();
        }
        return info.trim();
    }
    /**
     * 验证邮箱
     */
    public static boolean checkEmail(String email) {
        boolean flag;
        try {
            String check = "^([a-z0-9A-Z]+[-|_|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
            Pattern regex = Pattern.compile(check);
            Matcher matcher = regex.matcher(email);
            flag = matcher.matches();
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }
    /**
     * 获得汉语拼音首字母
     */
    public static String getAlpha(String str) {
        if (str == null) {
            return "#";
        }
        if (str.trim().length() == 0) {
            return "#";
        }
        char c = str.trim().substring(0, 1).charAt(0);
        // 正则表达式,判断首字母是否是英文字母
        Pattern pattern = Pattern.compile("^[A-Za-z]+$");
        if (pattern.matcher(c + "").matches()) {
            return (c + "").toUpperCase();
        } else {
            return "#";
        }
    }
    /**
     * 校验URL
     */
    public static boolean checkUrl(String url) {
        if (TextUtils.isEmpty(url)) return false;
        boolean flag;
        try {
            String check = "^((https|http|ftp|rtsp|mms|axd):\\/\\/)[^\\s]+";
            Pattern regex = Pattern.compile(check, Pattern.CASE_INSENSITIVE);
            Matcher matcher = regex.matcher(url.replaceAll(" ", ""));
            flag = matcher.matches();
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }
    /**
     * 校验图片URL
     */
    public static boolean checkImageUrl(String url) {
        if (TextUtils.isEmpty(url)) return false;
        boolean flag;
        try {
            String check = "^((https|http):\\/\\/)[^\\s]+.(png|jpg|gif|webp)";
            Pattern regex = Pattern.compile(check, Pattern.CASE_INSENSITIVE);
            Matcher matcher = regex.matcher(url);
            flag = matcher.matches();
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }
    /**
     * 校验正整数
     */
    public static boolean checkInt(String intContent) {
        if (TextUtils.isEmpty(intContent)) return false;
        boolean flag;
        try {
            String check = "^[1-9]\\d*$";
            Pattern regex = Pattern.compile(check, Pattern.CASE_INSENSITIVE);
            Matcher matcher = regex.matcher(intContent);
            flag = matcher.matches();
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }
    public static boolean checkColor(String color) {
        if (TextUtils.isEmpty(color))
            return false;
        boolean flag;
        try {
            String check = "^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$";
            Pattern regex = Pattern.compile(check, Pattern.CASE_INSENSITIVE);
            Matcher matcher = regex.matcher(color);
            flag = matcher.matches();
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }
}
third-zxing/src/main/java/com/zxing/utils/ZXingBitmapUtils.java
New file
@@ -0,0 +1,333 @@
package com.zxing.utils;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * Bitmap操作常用工具类
 */
public class ZXingBitmapUtils {
    private final static String TAG = ZXingBitmapUtils.class.getCanonicalName();
    public final static String JPG_SUFFIX = ".jpg";
    private final static String TIME_FORMAT = "yyyyMMddHHmmss";
    /**
     * 显示图片到相册
     *
     * @param context
     * @param photoFile 要保存的图片文件
     */
    public static void displayToGallery(Context context, File photoFile) {
        if (photoFile == null || !photoFile.exists()) {
            return;
        }
        String photoPath = photoFile.getAbsolutePath();
        String photoName = photoFile.getName();
        // 其次把文件插入到系统图库
        try {
            ContentResolver contentResolver = context.getContentResolver();
            MediaStore.Images.Media.insertImage(contentResolver, photoPath, photoName, null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 最后通知图库更新
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + photoPath)));
    }
    /**
     * 将Bitmap保存到指定目录下
     *
     * @param bitmap
     * @param folder
     * @return 保存成功,返回其对应的File,保存失败则返回null
     */
    public static File saveToFile(Bitmap bitmap, File folder) {
        String fileName = new SimpleDateFormat(TIME_FORMAT).format(new Date());//直接以当前时间戳作为文件名
        return saveToFile(bitmap, folder, fileName);
    }
    /**
     * 将Bitmap保存到指定目录下,并且指定好文件名
     *
     * @param bitmap
     * @param folder
     * @param fileName 指定的文件名包含后缀
     * @return 保存成功,返回其对应的File,保存失败则返回null
     */
    public static File saveToFile(Bitmap bitmap, File folder, String fileName) {
        if (bitmap != null) {
            if (!folder.exists()) {
                folder.mkdir();
            }
            File file = new File(folder, fileName + JPG_SUFFIX);
            if (file.exists()) {
                file.delete();
            }
            try {
                file.createNewFile();
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
                bos.flush();
                bos.close();
                return file;
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        } else {
            return null;
        }
    }
    /**
     * 获取图片的旋转角度
     *
     * @param path 图片绝对路径
     * @return 图片的旋转角度
     */
    public static int getBitmapDegree(String path) {
        int degree = 0;
        try {
            // 从指定路径下读取图片,并获取其EXIF信息
            ExifInterface exifInterface = new ExifInterface(path);
            // 获取图片的旋转信息
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }
    /**
     * 将图片按照指定的角度进行旋转
     *
     * @param bitmap 需要旋转的图片
     * @param degree 指定的旋转角度
     * @return 旋转后的图片
     */
    public static Bitmap rotateBitmapByDegree(Bitmap bitmap, int degree) {
        // 根据旋转角度,生成旋转矩阵
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        // 将原始图片按照旋转矩阵进行旋转,并得到新的图片
        Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
        }
        return newBitmap;
    }
    /**
     * 压缩Bitmap的大小
     *
     * @param imageFile     图片文件
     * @param requestWidth  压缩到想要的宽度
     * @param requestHeight 压缩到想要的高度
     * @return
     */
    public static Bitmap decodeBitmapFromFile(File imageFile, int requestWidth, int requestHeight) {
        if (imageFile != null) {
            return decodeBitmapFromFile(imageFile.getAbsolutePath(), requestWidth, requestHeight);
        } else {
            return null;
        }
    }
    /**
     * 压缩Bitmap的大小
     *
     * @param imagePath     图片文件路径
     * @param requestWidth  压缩到想要的宽度
     * @param requestHeight 压缩到想要的高度
     * @return
     */
    public static Bitmap decodeBitmapFromFile(String imagePath, int requestWidth, int requestHeight) {
        if (!TextUtils.isEmpty(imagePath)) {
            Log.i(TAG, "requestWidth: " + requestWidth);
            Log.i(TAG, "requestHeight: " + requestHeight);
            if (requestWidth <= 0 || requestHeight <= 0) {
                Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
                return bitmap;
            }
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;//不加载图片到内存,仅获得图片宽高
            BitmapFactory.decodeFile(imagePath, options);
            Log.i(TAG, "original height: " + options.outHeight);
            Log.i(TAG, "original width: " + options.outWidth);
            if (options.outHeight == -1 || options.outWidth == -1) {
                try {
                    ExifInterface exifInterface = new ExifInterface(imagePath);
                    int height = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_LENGTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的高度
                    int width = exifInterface.getAttributeInt(ExifInterface.TAG_IMAGE_WIDTH, ExifInterface.ORIENTATION_NORMAL);//获取图片的宽度
                    Log.i(TAG, "exif height: " + height);
                    Log.i(TAG, "exif width: " + width);
                    options.outWidth = width;
                    options.outHeight = height;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            options.inSampleSize = calculateInSampleSize(options, requestWidth, requestHeight); //计算获取新的采样率
            Log.i(TAG, "inSampleSize: " + options.inSampleSize);
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeFile(imagePath, options);
        } else {
            return null;
        }
    }
    /**
     * Decode and sample down a bitmap from resources to the requested width and height.
     *
     * @param res       The resources object containing the image data
     * @param resId     The resource id of the image data
     * @param reqWidth  The requested width of the resulting bitmap
     * @param reqHeight The requested height of the resulting bitmap
     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
     * that are equal to or greater than the requested width and height
     */
    public static Bitmap decodeBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
        // BEGIN_INCLUDE (read_bitmap_dimensions)
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);
        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        // END_INCLUDE (read_bitmap_dimensions)
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }
    /**
     * Decode and sample down a bitmap from a file input stream to the requested width and height.
     *
     * @param fileDescriptor The file descriptor to read from
     * @param reqWidth       The requested width of the resulting bitmap
     * @param reqHeight      The requested height of the resulting bitmap
     * @return A bitmap sampled down from the original with the same aspect ratio and dimensions
     * that are equal to or greater than the requested width and height
     */
    public static Bitmap decodeBitmapFromDescriptor(FileDescriptor fileDescriptor, int reqWidth, int reqHeight) {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options);
    }
    /**
     * Google官方代码,计算合适的采样率
     * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding
     * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates
     * the closest inSampleSize that is a power of 2 and will result in the final decoded bitmap
     * having a width and height equal to or larger than the requested width and height.
     *
     * @param options   An options object with out* params already populated (run through a decode*
     *                  method with inJustDecodeBounds==true
     * @param reqWidth  The requested width of the resulting bitmap
     * @param reqHeight The requested height of the resulting bitmap
     * @return The value to be used for inSampleSize
     */
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // BEGIN_INCLUDE (calculate_sample_size)
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;
            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
            // This offers some additional logic in case the image has a strange
            // aspect ratio. For example, a panorama may have a much larger
            // width than height. In these cases the total pixels might still
            // end up being too large to fit comfortably in memory, so we should
            // be more aggressive with sample down the image (=larger inSampleSize).
            long totalPixels = width * height / inSampleSize;
            // Anything more than 2x the requested pixels we'll sample down further
            final long totalReqPixelsCap = reqWidth * reqHeight * 2;
            while (totalPixels > totalReqPixelsCap) {
                inSampleSize *= 2;
                totalPixels /= 2;
            }
        }
        return inSampleSize;
        // END_INCLUDE (calculate_sample_size)
    }
    /**
     * drawable转bitmap
     */
    public static Bitmap drawableToBitmap(Drawable drawable) {
        int w = drawable.getIntrinsicWidth();
        int h = drawable.getIntrinsicHeight();
        Bitmap.Config config =
                drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
                        : Bitmap.Config.RGB_565;
        Bitmap bitmap = Bitmap.createBitmap(w, h, config);
        //注意,下面三行代码要用到,否在在View或者surfaceview里的canvas.drawBitmap会看不到图
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, w, h);
        drawable.draw(canvas);
        return bitmap;
    }
}
third-zxing/src/main/res/drawable-xxhdpi/ic_shadow.png
third-zxing/src/main/res/drawable-xxhdpi/scan_capture.9.png
third-zxing/src/main/res/drawable-xxhdpi/scan_line.png
third-zxing/src/main/res/drawable/back.png
third-zxing/src/main/res/drawable/fast_scan_light_close.png
third-zxing/src/main/res/drawable/fast_scan_light_open.png
third-zxing/src/main/res/drawable/transparent_divider.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <size android:height="13dp"/>
    <solid android:color="@color/transparent"/>
</shape>
third-zxing/src/main/res/layout/activity_capture.xml
New file
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/capture_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#636363">
    <RelativeLayout
        android:id="@+id/top_bar_view"
        android:layout_width="match_parent"
        android:layout_height="52dp"
        android:background="#245EC3"
        android:orientation="horizontal">
        <!--1.返回按钮 增大点击区域-->
        <LinearLayout
            android:id="@+id/top_back_btn"
            android:layout_width="56dp"
            android:layout_height="match_parent"
            android:gravity="center_vertical"
            android:orientation="horizontal"
            >
            <ImageView
                android:layout_width="24dp"
                android:layout_height="24dp"
                android:layout_gravity="center"
                android:layout_marginLeft="16dp"
                android:scaleType="centerInside"
                android:src="@drawable/back"
                />
        </LinearLayout>
        <!--2.标题文本-->
        <TextView
            android:id="@+id/top_title_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginLeft="60dp"
            android:layout_marginRight="60dp"
            android:fontFamily="sans-serif-medium"
            android:gravity="center"
            android:maxLines="1"
            android:text="快速扫码"
            android:textColor="#FFFFFFFF"
            android:textSize="18sp" />
        <!--3.更多按钮 默认隐藏-->
        <LinearLayout
            android:id="@+id/top_more_btn"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_alignParentEnd="true"
            android:gravity="center_vertical"
            android:orientation="horizontal">
            <ImageView
                android:id="@+id/top_more_iv"
                android:layout_width="28dp"
                android:layout_height="28dp"
                android:layout_marginStart="20dp"
                android:layout_marginEnd="20dp"
                android:adjustViewBounds="true"
                android:scaleType="centerInside"
                android:visibility="gone" />
        </LinearLayout>
    </RelativeLayout>
    <SurfaceView
        android:id="@+id/capture_preview"
        android:layout_width="367dp"
        android:layout_height="367dp"
        android:layout_centerInParent="true"
        />
    <RelativeLayout
        android:id="@+id/capture_crop_view"
        android:layout_width="367dp"
        android:layout_height="367dp"
        android:layout_centerInParent="true"
        android:background="@drawable/scan_capture">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="367dp"
            android:layout_marginTop="182dp">
            <ImageView
                android:id="@+id/capture_scan_line"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentTop="true"
                android:layout_marginTop="5dp"
                android:layout_marginBottom="5dp"
                android:src="@drawable/scan_line" />
        </RelativeLayout>
    </RelativeLayout>
    <ImageView
        android:id="@+id/light_iv"
        android:layout_width="127dp"
        android:layout_height="127dp"
        android:layout_alignParentBottom="true"
        android:layout_centerInParent="true"
        android:layout_marginBottom="13dp"
        android:background="@drawable/fast_scan_light_close" />
</RelativeLayout>
third-zxing/src/main/res/layout/toolbar.xml
New file
@@ -0,0 +1,34 @@
<?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="50dp"
    >
        <RelativeLayout
            android:id="@+id/rl_back"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginStart="32dp">
            <TextView
                android:id="@+id/tv_text_cancel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:text="@string/scan_cancel"
                android:textColor="#000000"
                android:textSize="36sp" />
        </RelativeLayout>
        <TextView
            android:id="@+id/tv_text_scan"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="@string/scan_title"
            android:textColor="#000000"
            android:textSize="36sp" />
</RelativeLayout>
third-zxing/src/main/res/raw/beep.ogg
Binary files differ
third-zxing/src/main/res/values/colors_ui.xml
New file
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--基础色-->
    <color name="c0">#F18D00</color>   <!--用于按钮、较大面积色块辅色 原C10-->
    <color name="c1">#F18D00</color>   <!--用于强调性文字/图片等非大面积色块色值-->
    <color name="c2">#2C2C2C</color>    <!--主标题/主文字色-->
    <!--主标题/主文字色-->
    <color name="c3">#C8D1E6</color>    <!--Toolbar文字/普通按钮BG色-->
    <!--点缀色-->
    <color name="c5">#888888</color>   <!--普通文案/引导/次要文字-->
    <color name="c6">#CCCCCC</color>   <!--置灰/输入提示-->
    <!--底色/分割-->
    <color name="c7">#F7F7F7</color>   <!--客户端底色/卡片描边-->
    <color name="c8">#F2F2F2</color>   <!--分割线底色-->
    <color name="c10">#FFFFFF</color>   <!--反白-->
    <!--带透明度的颜色-->
    <!--全局遮罩-->
    <color name="c14">#7FF18D00</color> <!--强调钮pressed-->
    <color name="c15">#7FF18D00</color> <!--强调钮disabled-->
    <!--普通钮pressed-->
    <!--普通钮disabled-->
    <!--成功失败提示-->
    <color name="c12">#EF6545</color>   <!--删除、警示色;添加设备超时红灯文案-->
    <color name="color_background">#ffffff</color>
    <color name="transparent">#00000000</color>
    <!--新UI规范颜色值统一命名-->
    <color name="color5">#424243</color>
    <color name="color9">#cccccc</color>
</resources>
third-zxing/src/main/res/values/ids.xml
New file
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="decode" type="id"/>
    <item name="decode_failed" type="id"/>
    <item name="decode_succeeded" type="id"/>
    <item name="quit" type="id"/>
    <item name="restart_preview" type="id"/>
    <item name="return_scan_result" type="id"/>
</resources>
third-zxing/src/main/res/values/strings.xml
New file
@@ -0,0 +1,13 @@
<resources>
    <string name="app_name">third_zxing2</string>
    <string name="scan_title">二维码扫描</string>
    <!--扫码-->
    <string name="zxing_scan_tips">将二维码放入框内,即可自动扫描</string>
    <string name="capture_no_camera">没有访问相机的权限,请打开访问权限再试</string>
    <string name="capture_no_result">没有扫描出结果</string>
    <string name="capture_no_network">当前网络不可用,请检查网络后再试</string>
    <string name="capture_no_result2">没有扫描出结果,可能不是有效的二维码</string>
    <string name="scan_cancel">取消</string>
</resources>
third-zxing/src/main/res/values/styles.xml
New file
@@ -0,0 +1,24 @@
<resources>
    <style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@color/color_background</item>
        <item name="android:listViewStyle">@style/List</item>
        <item name="android:windowAnimationStyle">@null</item>
        <item name="android:textViewStyle">@style/TextView</item>
        <item name="android:disabledAlpha">1</item>
        <item name="android:listDivider">@drawable/transparent_divider</item>
    </style>
    <style name="List" parent="@android:style/Widget.ListView">
        <item name="android:listSelector">@color/transparent</item>
        <item name="android:cacheColorHint">@color/transparent</item>
        <item name="android:divider">@null</item>
    </style>
    <style name="TextView" parent="@android:style/Widget.TextView">
        <item name="android:textColorHint">@color/color9</item>
        <item name="android:textColor">@color/color5</item>
        <item name="android:textSize">14sp</item>
    </style>
</resources>