Full Code of zwc456baby/vmqApk for AI

master 1d8158e49f75 cached
59 files
187.2 KB
46.0k tokens
236 symbols
1 requests
Download .txt
Showing preview only (214K chars total). Download the full file or copy to clipboard to get everything.
Repository: zwc456baby/vmqApk
Branch: master
Commit: 1d8158e49f75
Files: 59
Total size: 187.2 KB

Directory structure:
gitextract_efbl9myg/

├── .gitignore
├── LICENSE
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       ├── google/
│       │   │       │   └── zxing/
│       │   │       │       ├── activity/
│       │   │       │       │   └── CaptureActivity.java
│       │   │       │       ├── camera/
│       │   │       │       │   ├── AutoFocusCallback.java
│       │   │       │       │   ├── CameraConfigurationManager.java
│       │   │       │       │   ├── CameraManager.java
│       │   │       │       │   ├── FlashlightManager.java
│       │   │       │       │   ├── PlanarYUVLuminanceSource.java
│       │   │       │       │   └── PreviewCallback.java
│       │   │       │       ├── decoding/
│       │   │       │       │   ├── CaptureActivityHandler.java
│       │   │       │       │   ├── DecodeFormatManager.java
│       │   │       │       │   ├── DecodeHandler.java
│       │   │       │       │   ├── DecodeThread.java
│       │   │       │       │   ├── FinishListener.java
│       │   │       │       │   ├── InactivityTimer.java
│       │   │       │       │   ├── Intents.java
│       │   │       │       │   └── RGBLuminanceSource.java
│       │   │       │       ├── encoding/
│       │   │       │       │   └── EncodingHandler.java
│       │   │       │       └── view/
│       │   │       │           ├── ViewfinderResultPointCallback.java
│       │   │       │           └── ViewfinderView.java
│       │   │       └── vone/
│       │   │           └── vmq/
│       │   │               ├── App.java
│       │   │               ├── Constant.java
│       │   │               ├── ForegroundServer.java
│       │   │               ├── LockShowActivity.java
│       │   │               ├── MainActivity.java
│       │   │               ├── NeNotificationService2.java
│       │   │               ├── StartReceive.java
│       │   │               ├── Utils.java
│       │   │               └── util/
│       │   │                   ├── BitmapUtil.java
│       │   │                   ├── Constant.java
│       │   │                   ├── FileUtils.java
│       │   │                   └── UriUtil.java
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── activity_lock_show.xml
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_scanner.xml
│       │       │   ├── toolbar_main.xml
│       │       │   └── toolbar_scanner.xml
│       │       ├── menu/
│       │       │   └── scanner_menu.xml
│       │       ├── raw/
│       │       │   └── beep.ogg
│       │       ├── values/
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── ids.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       └── xml/
│       │           ├── network_security_config.xml
│       │           └── update_paths.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── vone/
│                       └── qrcode/
│                           └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
.idea
.DS_Store
/build
/captures
.externalNativeBuild

*.jks
/app/authkey.jks



================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2018 ahuyangdong

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



================================================
FILE: README.md
================================================

V免签  —— 个人开发者收款解决方案
===============

## Android 15 新限制

请注意,Android 15 新系统,对app权限进一步限制,需要打开usb调试模式,使用adb执行shell命令:

```
appops set com.vone.qrcode RECEIVE_SENSITIVE_NOTIFICATIONS allow
```

手动授予 `RECEIVE_SENSITIVE_NOTIFICATIONS`  权限,才能正常监听某些 支付宝 消息,否则会导致漏单等情况。这是Android15 新加入的限制,目前没有其他办法绕过

> 部分消息会被系统拦截,部分消息能够正常监听,这是新系统的默认行为,并非软件无法监听。手动授予权限后,才能监听到完整的通知消息
> Android 14 以及低版本没有这个限制

## 简介

此处为fork自原作者的修改版
主要修改增加几项功能:

1. 支持开机自启(国内定制系统需手动开启自启权限)
2. 支持post失败后再重试一次(这次重试是强制亮屏的)
3. ios设备可以找一台安卓设备-》绑定店员进行收款通知了

优化功能:

1. 优化了里面大量的 okhttp 的访问,做成了单例,防止某些情况下可能导致的内存溢出、错误崩溃等等
2. 增加了一次网络重试(没有做三次、四次是防止重复提交导致订单出问题),而且是唤起到前台的网络重试,(之所以唤起到前台,是测试过小米等机型,如果app长时间在后台(6小时以上),app会被限制网络,除非启动前台Service或者Activity

修改版特点:可以装在自己的日用安卓机器上,不用专门找一台机器亮屏挂机了。因为修改版支持错误重试,如果装在日用机器上推送失败,软件会强制打开一个前台Service以及一个前台Activity

前台页面的打开需要手动开启两项权限:后台弹出页面、锁屏显示

> 在使用过程中,可以将屏幕关闭,省电,然后在收到支付信息后,软件会自动的打开前台并推送支付信息。
> 软件里面的心跳本来想移除用来省电的,但基于可靠性,虽然心跳会略微增加耗电,但还是没有去除

---

**以下赞助链接采用此系统搭建,您可以随时赞助测试其稳定性:**

[赞助链接](https://card.zwc365.com/p/2eyzmzlwcdc076wm8zc2)

如果 APK 出现什么问题,不兼容你的手机或新版支付宝,可以从赞助链接与我反馈

如果你不想搭建或者不会搭建 V免签,可以用我搭建好的 [V免签系统](http://pay.zwc365.com/)

===============


V免签 是基于SpringBoot 2.1.1/ThinkPhP5.1 实现的一套免签支付程序,主要包含以下特色:

 + JAVA、PHP双服务端,总有一款适合你服务器
 + 超简单Api使用,提供统一Api实现收款回调
 + 免费、开源

> Java版服务端地址:【 https://github.com/szvone/Vmq 】

> PHP 版服务端地址:【 https://github.com/szvone/vmqphp 】

## 前言

[赞助链接](https://card.zwc365.com/p/2eyzmzlwcdc076wm8zc2)

## 安装

 + 下载服务端程序,可选PHP/Java版,按照说明安装
 + 下载编译好的Apk,安装后扫码/手动配置 即可使用


 > 升级说明:请您直接下载新版本覆盖旧版本即可!


## 说明
 + 请部署完成后访问后台,有详细的Api说明


## 注意

  + 本系统原理为监控收款后手机的通知栏推送消息,所以请保持微信/支付宝/V免签监控端后台正常运行,且添加到内存清理白名单!

  + v免签面向用户是个人开发者,如果您不懂如何开发网站,那么v免签不适合您的使用!

  + v免签的原理是监控手机收到收款后的通知栏推送信息,所以不适合于商用多用户的情况,如果您想用于商用,请二次开发!

  + v免签是免费开源产品,所有程序均开放源代码,所以不会有收费计划,因此作者不可能教会每个人部署安装,请参考文档多百度谷歌,v免签使用具有一定的技术门槛,请见谅!

  + v免签的监控端并不适配所有手机,遇到手机无法正常使用的时候,请您更换手机或使用模拟器挂机!

  + v免签拥有双语言服务端,当您使用php版本服务端遇到问题的时候,请您尝试使用java版本服务端,php版本服务端配置略复杂,需要配置伪静态规则,请知悉!

  + 正常的安装步骤简略如下
    + 下载服务端部署(GitHub中下载的为最新版)
    + 登录网站后台更改系统设置
    + 打开网站后台监控端设置
    + 下载监控端
    + 安装监控端后使用手动配置或扫码配置
    + 监控端中点击开启服务跳转到辅助功能中开启服务
    + 开启服务后返回v免签点击检测监听权限
    + 如果显示监听权限正常,至此安装完毕,如果只收到通知栏推送的测试通知,则系统不兼容无法正常监听
    + 如果显示监听权限正常,还是无法正常运行,那么请确定微信是否关注 “微信支付”这个公众号


  + v免签支持的通知有:
    + 支付宝个人收款的推送通知
    + 支付宝商家二维码的收款推送通知
    + 支付宝店员通绑定的店员账号收款的推送通知
    + 微信二维码收款推送通知
    + 微信店员收款推送通知
    + 微信收款商业版收款推送通知
    + 微信收款商业版店员到账收款通知

## 更新记录
 + v1.8.1(2019.12.20)
    + 修复上个版本无法正常回调问题

 + v1.8(2019.12.03)
    + 修复付款人昵称如果是纯数字,支付完后台订单金额会记录成昵称的数字的问题

 + v1.7(2019.05.17)
    + 删除辅助功能依赖,改为使用通知使用权进行监听,修复一大堆bug,建议更新到该版本

 + v1.6.2(2019.05.17)
    + 增加微信收款商业版到账支持

 + v1.6.1(2019.05.17)
    + 修复微信无法正常回调的问题

 + v1.6(2019.05.16)
    + 启用新方式监听到账通知,理论支持更多设备!

 + v1.5(2019.04.24)
    + 修复部分手机扫码配置失败的问题!

 + v1.4.1(2019.04.23)
    + 修复部分手机无法正确检测监听权限问题,点击监听权限按钮后,如果一切正常,状态栏会收到推送信息,并且会提示监听权限正常!

 + v1.4(2019.04.23)
    + 修复部分手机无法正确检测监听权限问题,点击监听权限按钮后,如果一切正常,状态栏会收到推送信息,并且会提示监听权限正常!

 + v1.3(2019.04.20)
    + 添加后台心跳线程熄屏运行权限,更加稳定啦(推荐更新到此版本)

 + v1.2(2019.04.19)
    + 整理代码,重新优化APP兼容性
    + 添加店员到账支持,添加后可以实现安卓备用机/模拟器 挂小号取收款通知,方便IOS用户,
       + 微信绑定店员方式=>微信->收付款->二维码收款->收款小账本->添加店员接收通知
       + 支付宝绑定店员方式=>我的->商家服务->店员通->立即添加

 + v1.1(2019.02.25)
   + 修复安卓7.0以上系统监控App闪退问题
   + 修复监控端检测服务状态无法正确检测是否正常问题
   + 添加商家码收款回调支持,商家码收款的也能正常回调啦

 + v1.0(2019.01.31)
   + 初版发布

## 版权信息

V免签遵循 MIT License 开源协议发布,并提供免费使用,请勿用于非法用途。


版权所有Copyright © 2019 by vone (http://szvone.cn)

All rights reserved。



================================================
FILE: app/.gitignore
================================================
/build


================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    // buildToolsVersion "26.0.0"
    defaultConfig {
        applicationId "com.vone.qrcode"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    signingConfigs {
        //加载资源
        Properties properties = new Properties()
        InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream();
        properties.load(inputStream)

        signConfig {
            storeFile file(properties.getProperty("STORE_FILE_NAME"))//签名文件路径,
            storePassword properties.getProperty("KEY_PASSWORD") //密码
            keyAlias properties.getProperty("STORE_ALIAS")
            keyPassword properties.getProperty("KEY_PASSWORD")  //密码
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.signConfig // 配置debug包的签名,接入微信分享必须验证签名
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.signConfig
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:26.+'
    // compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'com.google.zxing:core:3.3.0'
    compile 'com.squareup.okhttp3:okhttp:3.7.0'
    compile 'com.squareup.okio:okio:1.12.0'
    testCompile 'junit:junit:4.12'
}


================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\As\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


================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.vone.qrcode">

    <uses-permission android:name="android.permission.INTERNET" /> <!-- 网络权限 -->
    <uses-permission android:name="android.permission.VIBRATE" /> <!-- 震动权限 -->
    <uses-permission android:name="android.permission.CAMERA" /> <!-- 摄像头权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-feature android:name="android.hardware.camera.autofocus" /> <!-- 自动聚焦权限 -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <!--  新增权限  -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:name="com.vone.vmq.App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:networkSecurityConfig="@xml/network_security_config"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name="com.vone.vmq.MainActivity"
            android:excludeFromRecents="true">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="com.google.zxing.activity.CaptureActivity"
            android:excludeFromRecents="true" />

        <service
            android:name="com.vone.vmq.NeNotificationService2"
            android:label="@string/app_name"
            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
            <intent-filter>
                <action android:name="android.service.notification.NotificationListenerService" />
            </intent-filter>
        </service>

        <service android:name="com.vone.vmq.ForegroundServer" />

        <activity
            android:name="com.vone.vmq.LockShowActivity"
            android:excludeFromRecents="true"
            android:launchMode="singleInstance" />


        <receiver
            android:name="com.vone.vmq.StartReceive"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.provider.Telephony.SECRET_CODE" />

                <data
                    android:host="66469"
                    android:scheme="android_secret_code" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

================================================
FILE: app/src/main/java/com/google/zxing/activity/CaptureActivity.java
================================================
package com.google.zxing.activity;

import android.app.ProgressDialog;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.Toast;

import com.vone.qrcode.R;
import com.vone.vmq.util.BitmapUtil;
import com.vone.vmq.util.Constant;
import com.google.zxing.BarcodeFormat;
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.camera.CameraManager;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.decoding.CaptureActivityHandler;
import com.google.zxing.decoding.InactivityTimer;
import com.google.zxing.decoding.RGBLuminanceSource;
import com.google.zxing.qrcode.QRCodeReader;
import com.google.zxing.view.ViewfinderView;

import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;


/**
 * Initial the camera
 *
 * @author Ryan.Tang
 */
public class CaptureActivity extends AppCompatActivity implements Callback {

    private static final int REQUEST_CODE_SCAN_GALLERY = 100;

    private CaptureActivityHandler handler;
    private ViewfinderView viewfinderView;
    private ImageButton back;
    private ImageButton btnFlash;
    private Button btnAlbum; // 相册
    private boolean isFlashOn = false;
    private boolean hasSurface;
    private Vector<BarcodeFormat> decodeFormats;
    private String characterSet;
    private InactivityTimer inactivityTimer;
    private MediaPlayer mediaPlayer;
    private boolean playBeep;
    private static final float BEEP_VOLUME = 0.10f;
    private boolean vibrate;
    private ProgressDialog mProgress;
    private String photo_path;
    private Bitmap scanBitmap;
    //	private Button cancelScanButton;
    /**
     * Called when the activity is first created.
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scanner);
        //ViewUtil.addTopView(getApplicationContext(), this, R.string.scan_card);
        CameraManager.init(getApplication());
        viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_content);
        back = (ImageButton) findViewById(R.id.btn_back);
        back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });

        btnFlash = (ImageButton) findViewById(R.id.btn_flash);
        btnFlash.setOnClickListener(flashListener);

        btnAlbum = (Button) findViewById(R.id.btn_album);
        btnAlbum.setOnClickListener(albumOnClick);

//		cancelScanButton = (Button) this.findViewById(R.id.btn_cancel_scan);
        hasSurface = false;
        inactivityTimer = new InactivityTimer(this);

    }

    private View.OnClickListener albumOnClick = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //打开手机中的相册
            Intent innerIntent = new Intent(Intent.ACTION_GET_CONTENT); //"android.intent.action.GET_CONTENT"
            innerIntent.setType("image/*");
            startActivityForResult(innerIntent, REQUEST_CODE_SCAN_GALLERY);
        }
    };


    @Override
    protected void onActivityResult(final int requestCode, int resultCode, Intent data) {
        if (resultCode==RESULT_OK) {
            switch (requestCode) {
                case REQUEST_CODE_SCAN_GALLERY:
                    handleAlbumPic(data);
                    break;
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    /**
     * 处理选择的图片
     * @param data
     */
    private void handleAlbumPic(Intent data) {
        //获取选中图片的路径
        final Uri uri = data.getData();

        mProgress = new ProgressDialog(CaptureActivity.this);
        mProgress.setMessage("正在扫描...");
        mProgress.setCancelable(false);
        mProgress.show();

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Result result = scanningImage(uri);
                mProgress.dismiss();
                if (result != null) {
                    Intent resultIntent = new Intent();
                    Bundle bundle = new Bundle();
                    bundle.putString(Constant.INTENT_EXTRA_KEY_QR_SCAN ,result.getText());

                    resultIntent.putExtras(bundle);
                    CaptureActivity.this.setResult(RESULT_OK, resultIntent);
                    finish();
                } else {
                    Toast.makeText(CaptureActivity.this, "识别失败", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    /**
     * 扫描二维码图片的方法
     * @param uri
     * @return
     */
    public Result scanningImage(Uri uri) {
        if (uri == null) {
            return null;
        }
        Hashtable<DecodeHintType, String> hints = new Hashtable<>();
        hints.put(DecodeHintType.CHARACTER_SET, "UTF8"); //设置二维码内容的编码

        scanBitmap = BitmapUtil.decodeUri(this, uri, 500, 500);
        RGBLuminanceSource source = new RGBLuminanceSource(scanBitmap);
        BinaryBitmap bitmap1 = new BinaryBitmap(new HybridBinarizer(source));
        QRCodeReader reader = new QRCodeReader();
        try {
            return reader.decode(bitmap1, hints);
        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (ChecksumException e) {
            e.printStackTrace();
        } catch (FormatException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onResume() {
        super.onResume();
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.scanner_view);
        SurfaceHolder surfaceHolder = surfaceView.getHolder();
        if (hasSurface) {
            initCamera(surfaceHolder);
        } else {
            surfaceHolder.addCallback(this);
            surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
        decodeFormats = null;
        characterSet = null;

        playBeep = true;
        AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE);
        if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
            playBeep = false;
        }
        initBeepSound();
        vibrate = true;

        //quit the scan view
//		cancelScanButton.setOnClickListener(new OnClickListener() {
//
//			@Override
//			public void onClick(View v) {
//				CaptureActivity.this.finish();
//			}
//		});
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (handler != null) {
            handler.quitSynchronously();
            handler = null;
        }
        CameraManager.get().closeDriver();
    }

    @Override
    protected void onDestroy() {
        inactivityTimer.shutdown();
        super.onDestroy();
    }

    /**
     * Handler scan result
     *
     * @param result
     * @param barcode
     */
    public void handleDecode(Result result, Bitmap barcode) {
        inactivityTimer.onActivity();
        playBeepSoundAndVibrate();
        String resultString = result.getText();
        //FIXME
        if (TextUtils.isEmpty(resultString)) {
            Toast.makeText(CaptureActivity.this, "Scan failed!", Toast.LENGTH_SHORT).show();
        } else {
            Intent resultIntent = new Intent();
            Bundle bundle = new Bundle();
            bundle.putString(Constant.INTENT_EXTRA_KEY_QR_SCAN, resultString);
            System.out.println("sssssssssssssssss scan 0 = " + resultString);
            // 不能使用Intent传递大于40kb的bitmap,可以使用一个单例对象存储这个bitmap
//            bundle.putParcelable("bitmap", barcode);
//            Logger.d("saomiao",resultString);
            resultIntent.putExtras(bundle);
            this.setResult(RESULT_OK, resultIntent);
        }
        CaptureActivity.this.finish();
    }

    private void initCamera(SurfaceHolder surfaceHolder) {
        try {
            CameraManager.get().openDriver(surfaceHolder);
        } catch (IOException ioe) {
            return;
        } catch (RuntimeException e) {
            return;
        }
        if (handler == null) {
            handler = new CaptureActivityHandler(this, decodeFormats,
                    characterSet);
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (!hasSurface) {
            hasSurface = true;
            initCamera(holder);
        }

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        hasSurface = false;

    }

    public ViewfinderView getViewfinderView() {
        return viewfinderView;
    }

    public Handler getHandler() {
        return handler;
    }

    public void drawViewfinder() {
        viewfinderView.drawViewfinder();

    }

    private void initBeepSound() {
        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.
            setVolumeControlStream(AudioManager.STREAM_MUSIC);
            mediaPlayer = new MediaPlayer();
            mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mediaPlayer.setOnCompletionListener(beepListener);

            AssetFileDescriptor file = getResources().openRawResourceFd(
                    R.raw.beep);
            try {
                mediaPlayer.setDataSource(file.getFileDescriptor(),
                        file.getStartOffset(), file.getLength());
                file.close();
                mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
                mediaPlayer.prepare();
            } catch (IOException e) {
                mediaPlayer = null;
            }
        }
    }

    private static final long VIBRATE_DURATION = 200L;

    private void playBeepSoundAndVibrate() {
        if (playBeep && mediaPlayer != null) {
            mediaPlayer.start();
        }
        if (vibrate) {
            Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
            vibrator.vibrate(VIBRATE_DURATION);
        }
    }

    /**
     * When the beep has finished playing, rewind to queue up another one.
     */
    private final OnCompletionListener beepListener = new OnCompletionListener() {
        public void onCompletion(MediaPlayer mediaPlayer) {
            mediaPlayer.seekTo(0);
        }
    };

    /**
     *  闪光灯开关按钮
     */
    private View.OnClickListener flashListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            try {
                boolean isSuccess = CameraManager.get().setFlashLight(!isFlashOn);
                if(!isSuccess){
                    Toast.makeText(CaptureActivity.this, "暂时无法开启闪光灯", Toast.LENGTH_SHORT).show();
                    return;
                }
                if (isFlashOn) {
                    // 关闭闪光灯
                    btnFlash.setImageResource(R.drawable.flash_off);
                    isFlashOn = false;
                } else {
                    // 开启闪光灯
                    btnFlash.setImageResource(R.drawable.flash_on);
                    isFlashOn = true;
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    };
}

================================================
FILE: app/src/main/java/com/google/zxing/camera/AutoFocusCallback.java
================================================
/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.camera;

import android.hardware.Camera;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

final class AutoFocusCallback implements Camera.AutoFocusCallback {

  private static final String TAG = AutoFocusCallback.class.getSimpleName();

  private static final long AUTOFOCUS_INTERVAL_MS = 1500L;

  private Handler autoFocusHandler;
  private int autoFocusMessage;

  void setHandler(Handler autoFocusHandler, int autoFocusMessage) {
    this.autoFocusHandler = autoFocusHandler;
    this.autoFocusMessage = autoFocusMessage;
  }

  public void onAutoFocus(boolean success, Camera camera) {
    if (autoFocusHandler != null) {
      Message message = autoFocusHandler.obtainMessage(autoFocusMessage, success);
      autoFocusHandler.sendMessageDelayed(message, AUTOFOCUS_INTERVAL_MS);
      autoFocusHandler = null;
    } else {
      Log.d(TAG, "Got auto-focus callback, but no handler for it");
    }
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/camera/CameraConfigurationManager.java
================================================
/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.camera;

import android.content.Context;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;

import java.util.regex.Pattern;

final class CameraConfigurationManager {

  private static final String TAG = CameraConfigurationManager.class.getSimpleName();

  private static final int TEN_DESIRED_ZOOM = 27;
  private static final int DESIRED_SHARPNESS = 30;

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

  private final Context context;
  private Point screenResolution;
  private Point cameraResolution;
  private int previewFormat;
  private String previewFormatString;

  CameraConfigurationManager(Context context) {
    this.context = context;
  }

  /**
   * Reads, one time, values from the camera that are needed by the app.
   */
  void initFromCameraParameters(Camera camera) {
    Camera.Parameters parameters = camera.getParameters();
    previewFormat = parameters.getPreviewFormat();
    previewFormatString = parameters.get("preview-format");
    Log.d(TAG, "Default preview format: " + previewFormat + '/' + previewFormatString);
    WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    Display display = manager.getDefaultDisplay();
    screenResolution = new Point(display.getWidth(), display.getHeight());
    Log.d(TAG, "Screen resolution: " + screenResolution);

    //图片拉伸
    Point screenResolutionForCamera = new Point();
    screenResolutionForCamera.x = screenResolution.x;
    screenResolutionForCamera.y = screenResolution.y;
    // preview size is always something like 480*320, other 320*480
    if (screenResolution.x < screenResolution.y) {
      screenResolutionForCamera.x = screenResolution.y;
      screenResolutionForCamera.y = screenResolution.x;
    }

    cameraResolution = getCameraResolution(parameters, screenResolutionForCamera);
    Log.d(TAG, "Camera resolution: " + screenResolution);

  }

  /**
   * Sets the camera up to take preview images which are used for both preview and decoding.
   * We detect the preview format here so that buildLuminanceSource() can build an appropriate
   * LuminanceSource subclass. In the future we may want to force YUV420SP as it's the smallest,
   * and the planar Y can be used for barcode scanning without a copy in some cases.
   */
  void setDesiredCameraParameters(Camera camera) {
    Camera.Parameters parameters = camera.getParameters();
    Log.d(TAG, "Setting preview size: " + cameraResolution);
    parameters.setPreviewSize(cameraResolution.x, cameraResolution.y);
    setFlash(parameters);
    setZoom(parameters);
    //setSharpness(parameters);
    //modify here
    camera.setDisplayOrientation(90);
    camera.setParameters(parameters);
  }

  Point getCameraResolution() {
    return cameraResolution;
  }

  Point getScreenResolution() {
    return screenResolution;
  }

  int getPreviewFormat() {
    return previewFormat;
  }

  String getPreviewFormatString() {
    return previewFormatString;
  }

  private static Point getCameraResolution(Camera.Parameters parameters, Point screenResolution) {

    String previewSizeValueString = parameters.get("preview-size-values");
    // saw this on Xperia
    if (previewSizeValueString == null) {
      previewSizeValueString = parameters.get("preview-size-value");
    }

    Point cameraResolution = null;

    if (previewSizeValueString != null) {
      Log.d(TAG, "preview-size-values parameter: " + previewSizeValueString);
      cameraResolution = findBestPreviewSizeValue(previewSizeValueString, screenResolution);
    }

    if (cameraResolution == null) {
      // Ensure that the camera resolution is a multiple of 8, as the screen may not be.
      cameraResolution = new Point(
          (screenResolution.x >> 3) << 3,
          (screenResolution.y >> 3) << 3);
    }

    return cameraResolution;
  }

  private static Point findBestPreviewSizeValue(CharSequence previewSizeValueString, Point screenResolution) {
    int bestX = 0;
    int bestY = 0;
    int diff = Integer.MAX_VALUE;
    for (String previewSize : COMMA_PATTERN.split(previewSizeValueString)) {

      previewSize = previewSize.trim();
      int dimPosition = previewSize.indexOf('x');
      if (dimPosition < 0) {
        Log.w(TAG, "Bad preview-size: " + previewSize);
        continue;
      }

      int newX;
      int newY;
      try {
        newX = Integer.parseInt(previewSize.substring(0, dimPosition));
        newY = Integer.parseInt(previewSize.substring(dimPosition + 1));
      } catch (NumberFormatException nfe) {
        Log.w(TAG, "Bad preview-size: " + previewSize);
        continue;
      }

      int newDiff = Math.abs(newX - screenResolution.x) + Math.abs(newY - screenResolution.y);
      if (newDiff == 0) {
        bestX = newX;
        bestY = newY;
        break;
      } else if (newDiff < diff) {
        bestX = newX;
        bestY = newY;
        diff = newDiff;
      }

    }

    if (bestX > 0 && bestY > 0) {
      return new Point(bestX, bestY);
    }
    return null;
  }

  private static int findBestMotZoomValue(CharSequence stringValues, int tenDesiredZoom) {
    int tenBestValue = 0;
    for (String stringValue : COMMA_PATTERN.split(stringValues)) {
      stringValue = stringValue.trim();
      double value;
      try {
        value = Double.parseDouble(stringValue);
      } catch (NumberFormatException nfe) {
        return tenDesiredZoom;
      }
      int tenValue = (int) (10.0 * value);
      if (Math.abs(tenDesiredZoom - value) < Math.abs(tenDesiredZoom - tenBestValue)) {
        tenBestValue = tenValue;
      }
    }
    return tenBestValue;
  }

  private void setFlash(Camera.Parameters parameters) {
    // FIXME: This is a hack to turn the flash off on the Samsung Galaxy.
    // And this is a hack-hack to work around a different value on the Behold II
    // Restrict Behold II check to Cupcake, per Samsung's advice
    //if (Build.MODEL.contains("Behold II") &&
    //    CameraManager.SDK_INT == Build.VERSION_CODES.CUPCAKE) {
    if (Build.MODEL.contains("Behold II") && CameraManager.SDK_INT == 3) { // 3 = Cupcake
      parameters.set("flash-value", 1);
    } else {
      parameters.set("flash-value", 2);
    }
    // This is the standard setting to turn the flash off that all devices should honor.
    parameters.set("flash-mode", "off");
  }

  private void setZoom(Camera.Parameters parameters) {

    String zoomSupportedString = parameters.get("zoom-supported");
    if (zoomSupportedString != null && !Boolean.parseBoolean(zoomSupportedString)) {
      return;
    }

    int tenDesiredZoom = TEN_DESIRED_ZOOM;

    String maxZoomString = parameters.get("max-zoom");
    if (maxZoomString != null) {
      try {
        int tenMaxZoom = (int) (10.0 * Double.parseDouble(maxZoomString));
        if (tenDesiredZoom > tenMaxZoom) {
          tenDesiredZoom = tenMaxZoom;
        }
      } catch (NumberFormatException nfe) {
        Log.w(TAG, "Bad max-zoom: " + maxZoomString);
      }
    }

    String takingPictureZoomMaxString = parameters.get("taking-picture-zoom-max");
    if (takingPictureZoomMaxString != null) {
      try {
        int tenMaxZoom = Integer.parseInt(takingPictureZoomMaxString);
        if (tenDesiredZoom > tenMaxZoom) {
          tenDesiredZoom = tenMaxZoom;
        }
      } catch (NumberFormatException nfe) {
        Log.w(TAG, "Bad taking-picture-zoom-max: " + takingPictureZoomMaxString);
      }
    }

    String motZoomValuesString = parameters.get("mot-zoom-values");
    if (motZoomValuesString != null) {
      tenDesiredZoom = findBestMotZoomValue(motZoomValuesString, tenDesiredZoom);
    }

    String motZoomStepString = parameters.get("mot-zoom-step");
    if (motZoomStepString != null) {
      try {
        double motZoomStep = Double.parseDouble(motZoomStepString.trim());
        int tenZoomStep = (int) (10.0 * motZoomStep);
        if (tenZoomStep > 1) {
          tenDesiredZoom -= tenDesiredZoom % tenZoomStep;
        }
      } catch (NumberFormatException nfe) {
        // continue
      }
    }

    // Set zoom. This helps encourage the user to pull back.
    // Some devices like the Behold have a zoom parameter
    if (maxZoomString != null || motZoomValuesString != null) {
      parameters.set("zoom", String.valueOf(tenDesiredZoom / 10.0));
    }

    // Most devices, like the Hero, appear to expose this zoom parameter.
    // It takes on values like "27" which appears to mean 2.7x zoom
    if (takingPictureZoomMaxString != null) {
      parameters.set("taking-picture-zoom", tenDesiredZoom);
    }
  }

	public static int getDesiredSharpness() {
		return DESIRED_SHARPNESS;
	}

}


================================================
FILE: app/src/main/java/com/google/zxing/camera/CameraManager.java
================================================
/*
 * Copyright (C) 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.camera;

import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Build;
import android.os.Handler;
import android.view.SurfaceHolder;

import java.io.IOException;
import java.util.List;

/**
 * This object wraps the Camera service object and expects to be the only one talking to it. The
 * implementation encapsulates the steps needed to take preview-sized images, which are used for
 * both preview and decoding.
 */
public final class CameraManager {

    private static final String TAG = CameraManager.class.getSimpleName();

    private static final int MIN_FRAME_WIDTH = 240;
    private static final int MIN_FRAME_HEIGHT = 240;
    private static final int MAX_FRAME_WIDTH = 480;
    private static final int MAX_FRAME_HEIGHT = 360;

    private static CameraManager cameraManager;

    static final int SDK_INT; // Later we can use Build.VERSION.SDK_INT

    static {
        int sdkInt;
        try {
            sdkInt = Integer.parseInt(Build.VERSION.SDK);
        } catch (NumberFormatException nfe) {
            // Just to be safe
            sdkInt = 10000;
        }
        SDK_INT = sdkInt;
    }

    private final Context context;
    private final CameraConfigurationManager configManager;
    private Camera camera;
    private Rect framingRect;
    private Rect framingRectInPreview;
    private boolean initialized;
    private boolean previewing;
    private final boolean useOneShotPreviewCallback;
    /**
     * 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;
    /**
     * Autofocus callbacks arrive here, and are dispatched to the Handler which requested them.
     */
    private final AutoFocusCallback autoFocusCallback;

    /**
     * Initializes this static object with the Context of the calling Activity.
     *
     * @param context The Activity which wants to use the camera.
     */
    public static void init(Context context) {
        if (cameraManager == null) {
            cameraManager = new CameraManager(context);
        }
    }

    /**
     * Gets the CameraManager singleton instance.
     *
     * @return A reference to the CameraManager singleton.
     */
    public static CameraManager get() {
        return cameraManager;
    }

    private CameraManager(Context context) {

        this.context = context;
        this.configManager = new CameraConfigurationManager(context);

        // Camera.setOneShotPreviewCallback() has a race condition in Cupcake, so we use the older
        // Camera.setPreviewCallback() on 1.5 and earlier. For Donut and later, we need to use
        // the more efficient one shot callback, as the older one can swamp the system and cause it
        // to run out of memory. We can't use SDK_INT because it was introduced in the Donut SDK.
        //useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > Build.VERSION_CODES.CUPCAKE;
        useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > 3; // 3 = Cupcake

        previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback);
        autoFocusCallback = new AutoFocusCallback();
    }

    /**
     * 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 void openDriver(SurfaceHolder holder) throws IOException {
        if (camera == null) {
            camera = Camera.open();
            if (camera == null) {
                throw new IOException();
            }
            camera.setPreviewDisplay(holder);

            if (!initialized) {
                initialized = true;
                configManager.initFromCameraParameters(camera);
            }
            configManager.setDesiredCameraParameters(camera);

            //FIXME
            //     SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
            //�Ƿ�ʹ��ǰ��
//      if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) {
//        FlashlightManager.enableFlashlight();
//      }
            FlashlightManager.enableFlashlight();
        }
    }

    /**
     * Closes the camera driver if still in use.
     */
    public void closeDriver() {
        if (camera != null) {
            FlashlightManager.disableFlashlight();
            camera.release();
            camera = null;
        }
    }

    /**
     * Asks the camera hardware to begin drawing preview frames to the screen.
     */
    public void startPreview() {
        if (camera != null && !previewing) {
            camera.startPreview();
            previewing = true;
        }
    }

    /**
     * Tells the camera to stop drawing preview frames.
     */
    public void stopPreview() {
        if (camera != null && previewing) {
            if (!useOneShotPreviewCallback) {
                camera.setPreviewCallback(null);
            }
            camera.stopPreview();
            previewCallback.setHandler(null, 0);
            autoFocusCallback.setHandler(null, 0);
            previewing = false;
        }
    }

    /**
     * A single preview frame will be returned to the handler supplied. The data will arrive as byte[]
     * in the message.obj field, with width and height encoded as message.arg1 and message.arg2,
     * respectively.
     *
     * @param handler The handler to send the message to.
     * @param message The what field of the message to be sent.
     */
    public void requestPreviewFrame(Handler handler, int message) {
        if (camera != null && previewing) {
            previewCallback.setHandler(handler, message);
            if (useOneShotPreviewCallback) {
                camera.setOneShotPreviewCallback(previewCallback);
            } else {
                camera.setPreviewCallback(previewCallback);
            }
        }
    }

    /**
     * Asks the camera hardware to perform an autofocus.
     *
     * @param handler The Handler to notify when the autofocus completes.
     * @param message The message to deliver.
     */
    public void requestAutoFocus(Handler handler, int message) {
        if (camera != null && previewing) {
            autoFocusCallback.setHandler(handler, message);
            //Log.d(TAG, "Requesting auto-focus callback");
            camera.autoFocus(autoFocusCallback);
        }
    }

    /**
     * Calculates the framing rect which the UI should draw to show the user where to place the
     * barcode. This target helps with alignment as well as forces the user to hold the device
     * far enough away to ensure the image will be in focus.
     *
     * @return The rectangle to draw on screen in window coordinates.
     */
    public Rect getFramingRect() {
        Point screenResolution = configManager.getScreenResolution();
        if (screenResolution == null)
            return null;
        if (framingRect == null) {
            if (camera == null) {
                return null;
            }

            //修改之后
            int width = screenResolution.x * 7 / 10;
            int height = screenResolution.y * 7 / 10;

            if (height >= width) { //竖屏
                height = width;
            } else { //黑屏
                width = height;
            }

            int leftOffset = (screenResolution.x - width) / 2;
            int topOffset = (screenResolution.y - height) / 3;
            framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);

        }
        return framingRect;
    }
//  public Rect getFramingRect() {
//    Point screenResolution = configManager.getScreenResolution();
//    if (framingRect == null) {
//      if (camera == null) {
//        return null;
//      }
//      int width = screenResolution.x * 3 / 4;
//      if (width < MIN_FRAME_WIDTH) {
//        width = MIN_FRAME_WIDTH;
//      } else if (width > MAX_FRAME_WIDTH) {
//        width = MAX_FRAME_WIDTH;
//      }
//      int height = screenResolution.y * 3 / 4;
//      if (height < MIN_FRAME_HEIGHT) {
//        height = MIN_FRAME_HEIGHT;
//      } else if (height > MAX_FRAME_HEIGHT) {
//        height = MAX_FRAME_HEIGHT;
//      }
//      int leftOffset = (screenResolution.x - width) / 2;
//      int topOffset = (screenResolution.y - height) / 2;
//      framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
//      Log.d(TAG, "Calculated framing rect: " + framingRect);
//    }
//    return framingRect;
//  }

    /**
     * Like {@link #getFramingRect} but coordinates are in terms of the preview frame,
     * not UI / screen.
     */
    public Rect getFramingRectInPreview() {
        if (framingRectInPreview == null) {
            Rect rect = new Rect(getFramingRect());
            Point cameraResolution = configManager.getCameraResolution();
            Point screenResolution = configManager.getScreenResolution();
            //modify here
//      rect.left = rect.left * cameraResolution.x / screenResolution.x;
//      rect.right = rect.right * cameraResolution.x / screenResolution.x;
//      rect.top = rect.top * cameraResolution.y / screenResolution.y;
//      rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;
            rect.left = rect.left * cameraResolution.y / screenResolution.x;
            rect.right = rect.right * cameraResolution.y / screenResolution.x;
            rect.top = rect.top * cameraResolution.x / screenResolution.y;
            rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y;
            framingRectInPreview = rect;
        }
        return framingRectInPreview;
    }

    /**
     * Converts the result points from still resolution coordinates to screen coordinates.
     *
     * @param points The points returned by the Reader subclass through Result.getResultPoints().
     * @return An array of Points scaled to the size of the framing rect and offset appropriately
     *         so they can be drawn in screen coordinates.
     */
  /*
  public Point[] convertResultPoints(ResultPoint[] points) {
    Rect frame = getFramingRectInPreview();
    int count = points.length;
    Point[] output = new Point[count];
    for (int x = 0; x < count; x++) {
      output[x] = new Point();
      output[x].x = frame.left + (int) (points[x].getX() + 0.5f);
      output[x].y = frame.top + (int) (points[x].getY() + 0.5f);
    }
    return output;
  }
   */

    /**
     * A factory method to build the appropriate LuminanceSource object based on the format
     * of the preview buffers, as described by Camera.Parameters.
     *
     * @param data   A preview frame.
     * @param width  The width of the image.
     * @param height The height of the image.
     * @return A PlanarYUVLuminanceSource instance.
     */
    public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) {
        Rect rect = getFramingRectInPreview();
        int previewFormat = configManager.getPreviewFormat();
        String previewFormatString = configManager.getPreviewFormatString();
        switch (previewFormat) {
            // This is the standard Android format which all devices are REQUIRED to support.
            // In theory, it's the only one we should ever care about.
            case PixelFormat.YCbCr_420_SP:
                // This format has never been seen in the wild, but is compatible as we only care
                // about the Y channel, so allow it.
            case PixelFormat.YCbCr_422_SP:
                return new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height);
            default:
                // The Samsung Moment incorrectly uses this variant instead of the 'sp' version.
                // Fortunately, it too has all the Y data up front, so we can read it.
                if ("yuv420p".equals(previewFormatString)) {
                    return new PlanarYUVLuminanceSource(data, width, height, 0, 0, width, height);
                }
        }
        throw new IllegalArgumentException("Unsupported picture format: " +
                previewFormat + '/' + previewFormatString);
    }

    public Context getContext() {
        return context;
    }

    /**
     * 打开或关闭闪光灯
     * @param isOpen 是否开启闪光灯
     * @return boolean 操作成功/失败。
     */
    public boolean setFlashLight(boolean isOpen) {
        if (camera == null || !previewing) {
            return false;
        }
        Camera.Parameters parameters = camera.getParameters();
        if (parameters == null) {
            return false;
        }
        List<String> flashModes = parameters.getSupportedFlashModes();
        // 检查手机是否有闪光灯
        if (null == flashModes || 0 == flashModes.size()) {
            // 没有闪光灯则返回
            return false;
        }
        String flashMode = parameters.getFlashMode();
        if (isOpen) {
            if (Camera.Parameters.FLASH_MODE_TORCH.equals(flashMode)) {
                return true;
            }
            // 开启
            if (flashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                camera.setParameters(parameters);
                return true;
            } else {
                return false;
            }
        } else {
            if (Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)) {
                return true;
            }
            // 关闭
            if (flashModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {
                parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                camera.setParameters(parameters);
                return true;
            } else {
                return false;
            }
        }
    }
}


================================================
FILE: app/src/main/java/com/google/zxing/camera/FlashlightManager.java
================================================
/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.camera;

import android.os.IBinder;
import android.util.Log;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * This class is used to activate the weak light on some camera phones (not flash)
 * in order to illuminate surfaces for scanning. There is no official way to do this,
 * but, classes which allow access to this function still exist on some devices.
 * This therefore proceeds through a great deal of reflection.
 *
 * See <a href="http://almondmendoza.com/2009/01/05/changing-the-screen-brightness-programatically/">
 * http://almondmendoza.com/2009/01/05/changing-the-screen-brightness-programatically/</a> and
 * <a href="http://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java">
 * http://code.google.com/p/droidled/source/browse/trunk/src/com/droidled/demo/DroidLED.java</a>.
 * Thanks to Ryan Alford for pointing out the availability of this class.
 */
final class FlashlightManager {

  private static final String TAG = FlashlightManager.class.getSimpleName();

  private static final Object iHardwareService;
  private static final Method setFlashEnabledMethod;
  static {
    iHardwareService = getHardwareService();
    setFlashEnabledMethod = getSetFlashEnabledMethod(iHardwareService);
    if (iHardwareService == null) {
      Log.v(TAG, "This device does supports control of a flashlight");
    } else {
      Log.v(TAG, "This device does not support control of a flashlight");
    }
  }

  private FlashlightManager() {
  }

  /**
   * �����������ƿ���
   */
  //FIXME
  static void enableFlashlight() {
    setFlashlight(false);
  }

  static void disableFlashlight() {
    setFlashlight(false);
  }

  private static Object getHardwareService() {
    Class<?> serviceManagerClass = maybeForName("android.os.ServiceManager");
    if (serviceManagerClass == null) {
      return null;
    }

    Method getServiceMethod = maybeGetMethod(serviceManagerClass, "getService", String.class);
    if (getServiceMethod == null) {
      return null;
    }

    Object hardwareService = invoke(getServiceMethod, null, "hardware");
    if (hardwareService == null) {
      return null;
    }

    Class<?> iHardwareServiceStubClass = maybeForName("android.os.IHardwareService$Stub");
    if (iHardwareServiceStubClass == null) {
      return null;
    }

    Method asInterfaceMethod = maybeGetMethod(iHardwareServiceStubClass, "asInterface", IBinder.class);
    if (asInterfaceMethod == null) {
      return null;
    }

    return invoke(asInterfaceMethod, null, hardwareService);
  }

  private static Method getSetFlashEnabledMethod(Object iHardwareService) {
    if (iHardwareService == null) {
      return null;
    }
    Class<?> proxyClass = iHardwareService.getClass();
    return maybeGetMethod(proxyClass, "setFlashlightEnabled", boolean.class);
  }

  private static Class<?> maybeForName(String name) {
    try {
      return Class.forName(name);
    } catch (ClassNotFoundException cnfe) {
      // OK
      return null;
    } catch (RuntimeException re) {
      Log.w(TAG, "Unexpected error while finding class " + name, re);
      return null;
    }
  }

  private static Method maybeGetMethod(Class<?> clazz, String name, Class<?>... argClasses) {
    try {
      return clazz.getMethod(name, argClasses);
    } catch (NoSuchMethodException nsme) {
      // OK
      return null;
    } catch (RuntimeException re) {
      Log.w(TAG, "Unexpected error while finding method " + name, re);
      return null;
    }
  }

  private static Object invoke(Method method, Object instance, Object... args) {
    try {
      return method.invoke(instance, args);
    } catch (IllegalAccessException e) {
      Log.w(TAG, "Unexpected error while invoking " + method, e);
      return null;
    } catch (InvocationTargetException e) {
      Log.w(TAG, "Unexpected error while invoking " + method, e.getCause());
      return null;
    } catch (RuntimeException re) {
      Log.w(TAG, "Unexpected error while invoking " + method, re);
      return null;
    }
  }

  private static void setFlashlight(boolean active) {
    if (iHardwareService != null) {
      invoke(setFlashEnabledMethod, iHardwareService, active);
    }
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/camera/PlanarYUVLuminanceSource.java
================================================
/*
 * Copyright 2009 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.camera;

import android.graphics.Bitmap;

import com.google.zxing.LuminanceSource;

/**
 * This object extends LuminanceSource around an array of YUV data returned from the camera driver,
 * with the option to crop to a rectangle within the full data. This can be used to exclude
 * superfluous pixels around the perimeter and speed up decoding.
 *
 * It works for any pixel format where the Y channel is planar and appears first, including
 * YCbCr_420_SP and YCbCr_422_SP.
 *
 * @author dswitkin@google.com (Daniel Switkin)
 */
public final class PlanarYUVLuminanceSource extends LuminanceSource {
  private final byte[] yuvData;
  private final int dataWidth;
  private final int dataHeight;
  private final int left;
  private final int top;

  public PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dataHeight, int left, int top,
      int width, int height) {
    super(width, height);

    if (left + width > dataWidth || top + height > dataHeight) {
      throw new IllegalArgumentException("Crop rectangle does not fit within image data.");
    }

    this.yuvData = yuvData;
    this.dataWidth = dataWidth;
    this.dataHeight = dataHeight;
    this.left = left;
    this.top = top;
  }

  @Override
  public byte[] getRow(int y, byte[] row) {
    if (y < 0 || y >= getHeight()) {
      throw new IllegalArgumentException("Requested row is outside the image: " + y);
    }
    int width = getWidth();
    if (row == null || row.length < width) {
      row = new byte[width];
    }
    int offset = (y + top) * dataWidth + left;
    System.arraycopy(yuvData, offset, row, 0, width);
    return row;
  }

  @Override
  public byte[] getMatrix() {
    int width = getWidth();
    int height = getHeight();

    // If the caller asks for the entire underlying image, save the copy and give them the
    // original data. The docs specifically warn that result.length must be ignored.
    if (width == dataWidth && height == dataHeight) {
      return yuvData;
    }

    int area = width * height;
    byte[] matrix = new byte[area];
    int inputOffset = top * dataWidth + left;

    // If the width matches the full width of the underlying data, perform a single copy.
    if (width == dataWidth) {
      System.arraycopy(yuvData, inputOffset, matrix, 0, area);
      return matrix;
    }

    // Otherwise copy one cropped row at a time.
    byte[] yuv = yuvData;
    for (int y = 0; y < height; y++) {
      int outputOffset = y * width;
      System.arraycopy(yuv, inputOffset, matrix, outputOffset, width);
      inputOffset += dataWidth;
    }
    return matrix;
  }

  @Override
  public boolean isCropSupported() {
    return true;
  }

  public int getDataWidth() {
    return dataWidth;
  }

  public int getDataHeight() {
    return dataHeight;
  }

  public Bitmap renderCroppedGreyscaleBitmap() {
    int width = getWidth();
    int height = getHeight();
    int[] pixels = new int[width * height];
    byte[] yuv = yuvData;
    int inputOffset = top * dataWidth + left;

    for (int y = 0; y < height; y++) {
      int outputOffset = y * width;
      for (int x = 0; x < width; x++) {
        int grey = yuv[inputOffset + x] & 0xff;
        pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101);
      }
      inputOffset += dataWidth;
    }

    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
    return bitmap;
  }
}


================================================
FILE: app/src/main/java/com/google/zxing/camera/PreviewCallback.java
================================================
/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.camera;

import android.graphics.Point;
import android.hardware.Camera;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

final class PreviewCallback implements Camera.PreviewCallback {

  private static final String TAG = PreviewCallback.class.getSimpleName();

  private final CameraConfigurationManager configManager;
  private final boolean useOneShotPreviewCallback;
  private Handler previewHandler;
  private int previewMessage;

  PreviewCallback(CameraConfigurationManager configManager, boolean useOneShotPreviewCallback) {
    this.configManager = configManager;
    this.useOneShotPreviewCallback = useOneShotPreviewCallback;
  }

  void setHandler(Handler previewHandler, int previewMessage) {
    this.previewHandler = previewHandler;
    this.previewMessage = previewMessage;
  }

  public void onPreviewFrame(byte[] data, Camera camera) {
    Point cameraResolution = configManager.getCameraResolution();
    if (!useOneShotPreviewCallback) {
      camera.setPreviewCallback(null);
    }
    if (previewHandler != null) {
      Message message = previewHandler.obtainMessage(previewMessage, cameraResolution.x,
          cameraResolution.y, data);
      message.sendToTarget();
      previewHandler = null;
    } else {
      Log.d(TAG, "Got preview callback, but no handler for it");
    }
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/decoding/CaptureActivityHandler.java
================================================
/*
 * Copyright (C) 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.decoding;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.vone.qrcode.R;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result;
import com.google.zxing.activity.CaptureActivity;
import com.google.zxing.camera.CameraManager;
import com.google.zxing.view.ViewfinderResultPointCallback;

import java.util.Vector;


/**
 * This class handles all the messaging which comprises the state machine for capture.
 */
public final class CaptureActivityHandler extends Handler {

  private static final String TAG = CaptureActivityHandler.class.getSimpleName();

  private final CaptureActivity activity;
  private final DecodeThread decodeThread;
  private State state;

  private enum State {
    PREVIEW,
    SUCCESS,
    DONE
  }

  public CaptureActivityHandler(CaptureActivity activity, Vector<BarcodeFormat> decodeFormats,
                                String characterSet) {
    this.activity = activity;
    decodeThread = new DecodeThread(activity, decodeFormats, characterSet,
        new ViewfinderResultPointCallback(activity.getViewfinderView()));
    decodeThread.start();
    state = State.SUCCESS;
    // Start ourselves capturing previews and decoding.
    CameraManager.get().startPreview();
    restartPreviewAndDecode();
  }

  @Override
  public void handleMessage(Message message) {
    switch (message.what) {
      case R.id.auto_focus:
        //Log.d(TAG, "Got auto-focus message");
        // When one auto focus pass finishes, start another. This is the closest thing to
        // continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
        if (state == State.PREVIEW) {
          CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
        }
        break;
      case R.id.restart_preview:
        Log.d(TAG, "Got restart preview message");
        restartPreviewAndDecode();
        break;
      case R.id.decode_succeeded:
        Log.d(TAG, "Got decode succeeded message");
        state = State.SUCCESS;
        Bundle bundle = message.getData();
        
        /***********************************************************************/
        Bitmap barcode = bundle == null ? null :
            (Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);//���ñ����߳�
        
        activity.handleDecode((Result) message.obj, barcode);//���ؽ��
        /***********************************************************************/
        break;
      case R.id.decode_failed:
        // We're decoding as fast as possible, so when one decode fails, start another.
        state = State.PREVIEW;
        CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
        break;
      case R.id.return_scan_result:
        Log.d(TAG, "Got return scan result message");
        activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
        activity.finish();
        break;
      case R.id.launch_product_query:
        Log.d(TAG, "Got product query message");
        String url = (String) message.obj;
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
        activity.startActivity(intent);
        break;
    }
  }

  public void quitSynchronously() {
    state = State.DONE;
    CameraManager.get().stopPreview();
    Message quit = Message.obtain(decodeThread.getHandler(), R.id.quit);
    quit.sendToTarget();
    try {
      decodeThread.join();
    } catch (InterruptedException e) {
      // continue
    }

    // Be absolutely sure we don't send any queued up messages
    removeMessages(R.id.decode_succeeded);
    removeMessages(R.id.decode_failed);
  }

  private void restartPreviewAndDecode() {
    if (state == State.SUCCESS) {
      state = State.PREVIEW;
      CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
      CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
      activity.drawViewfinder();
    }
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/decoding/DecodeFormatManager.java
================================================
/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.decoding;

import android.content.Intent;
import android.net.Uri;

import com.google.zxing.BarcodeFormat;

import java.util.Arrays;
import java.util.List;
import java.util.Vector;
import java.util.regex.Pattern;

final class DecodeFormatManager {

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

  static final Vector<BarcodeFormat> PRODUCT_FORMATS;
  static final Vector<BarcodeFormat> ONE_D_FORMATS;
  static final Vector<BarcodeFormat> QR_CODE_FORMATS;
  static final Vector<BarcodeFormat> DATA_MATRIX_FORMATS;
  static {
    PRODUCT_FORMATS = new Vector<BarcodeFormat>(5);
    PRODUCT_FORMATS.add(BarcodeFormat.UPC_A);
    PRODUCT_FORMATS.add(BarcodeFormat.UPC_E);
    PRODUCT_FORMATS.add(BarcodeFormat.EAN_13);
    PRODUCT_FORMATS.add(BarcodeFormat.EAN_8);
    ONE_D_FORMATS = new Vector<BarcodeFormat>(PRODUCT_FORMATS.size() + 4);
    ONE_D_FORMATS.addAll(PRODUCT_FORMATS);
    ONE_D_FORMATS.add(BarcodeFormat.CODE_39);
    ONE_D_FORMATS.add(BarcodeFormat.CODE_93);
    ONE_D_FORMATS.add(BarcodeFormat.CODE_128);
    ONE_D_FORMATS.add(BarcodeFormat.ITF);
    QR_CODE_FORMATS = new Vector<BarcodeFormat>(1);
    QR_CODE_FORMATS.add(BarcodeFormat.QR_CODE);
    DATA_MATRIX_FORMATS = new Vector<BarcodeFormat>(1);
    DATA_MATRIX_FORMATS.add(BarcodeFormat.DATA_MATRIX);
  }

  private DecodeFormatManager() {}

  static Vector<BarcodeFormat> parseDecodeFormats(Intent intent) {
    List<String> scanFormats = null;
    String scanFormatsString = intent.getStringExtra(Intents.Scan.SCAN_FORMATS);
    if (scanFormatsString != null) {
      scanFormats = Arrays.asList(COMMA_PATTERN.split(scanFormatsString));
    }
    return parseDecodeFormats(scanFormats, intent.getStringExtra(Intents.Scan.MODE));
  }

  static Vector<BarcodeFormat> parseDecodeFormats(Uri inputUri) {
    List<String> formats = inputUri.getQueryParameters(Intents.Scan.SCAN_FORMATS);
    if (formats != null && formats.size() == 1 && formats.get(0) != null){
      formats = Arrays.asList(COMMA_PATTERN.split(formats.get(0)));
    }
    return parseDecodeFormats(formats, inputUri.getQueryParameter(Intents.Scan.MODE));
  }

  private static Vector<BarcodeFormat> parseDecodeFormats(Iterable<String> scanFormats,
                                                          String decodeMode) {
    if (scanFormats != null) {
      Vector<BarcodeFormat> formats = new Vector<BarcodeFormat>();
      try {
        for (String format : scanFormats) {
          formats.add(BarcodeFormat.valueOf(format));
        }
        return formats;
      } catch (IllegalArgumentException iae) {
        // ignore it then
      }
    }
    if (decodeMode != null) {
      if (Intents.Scan.PRODUCT_MODE.equals(decodeMode)) {
        return PRODUCT_FORMATS;
      }
      if (Intents.Scan.QR_CODE_MODE.equals(decodeMode)) {
        return QR_CODE_FORMATS;
      }
      if (Intents.Scan.DATA_MATRIX_MODE.equals(decodeMode)) {
        return DATA_MATRIX_FORMATS;
      }
      if (Intents.Scan.ONE_D_MODE.equals(decodeMode)) {
        return ONE_D_FORMATS;
      }
    }
    return null;
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/decoding/DecodeHandler.java
================================================
/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.decoding;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.vone.qrcode.R;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.activity.CaptureActivity;
import com.google.zxing.camera.CameraManager;
import com.google.zxing.camera.PlanarYUVLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

import java.util.Hashtable;


final class DecodeHandler extends Handler {

  private static final String TAG = DecodeHandler.class.getSimpleName();

  private final CaptureActivity activity;
  private final MultiFormatReader multiFormatReader;

  DecodeHandler(CaptureActivity activity, Hashtable<DecodeHintType, Object> hints) {
    multiFormatReader = new MultiFormatReader();
    multiFormatReader.setHints(hints);
    this.activity = activity;
  }

  @Override
  public void handleMessage(Message message) {
    switch (message.what) {
      case R.id.decode:
        //Log.d(TAG, "Got decode message");
        decode((byte[]) message.obj, message.arg1, message.arg2);
        break;
      case R.id.quit:
        Looper.myLooper().quit();
        break;
    }
  }

  /**
   * Decode the data within the viewfinder rectangle, and time how long it took. For efficiency,
   * reuse the same reader objects from one decode to the next.
   *
   * @param data   The YUV preview frame.
   * @param width  The width of the preview frame.
   * @param height The height of the preview frame.
   */
  private void decode(byte[] data, int width, int height) {
    long start = System.currentTimeMillis();
    Result rawResult = null;
    
    //modify here
    byte[] rotatedData = new byte[data.length];
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++)
            rotatedData[x * height + height - y - 1] = data[x + y * width];
    }
    int tmp = width; // Here we are swapping, that's the difference to #11
    width = height;
    height = tmp;
    
    PlanarYUVLuminanceSource source = CameraManager.get().buildLuminanceSource(rotatedData, width, height);
    BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
    try {
      rawResult = multiFormatReader.decodeWithState(bitmap);
    } catch (ReaderException re) {
      // continue
    } finally {
      multiFormatReader.reset();
    }

    if (rawResult != null) {
      long end = System.currentTimeMillis();
      Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n" + rawResult.toString());
      Message message = Message.obtain(activity.getHandler(), R.id.decode_succeeded, rawResult);
      Bundle bundle = new Bundle();
      bundle.putParcelable(DecodeThread.BARCODE_BITMAP, source.renderCroppedGreyscaleBitmap());
      message.setData(bundle);
      //Log.d(TAG, "Sending decode succeeded message...");
      message.sendToTarget();
    } else {
      Message message = Message.obtain(activity.getHandler(), R.id.decode_failed);
      message.sendToTarget();
    }
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/decoding/DecodeThread.java
================================================
/*
 * Copyright (C) 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.decoding;

import android.os.Handler;
import android.os.Looper;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.ResultPointCallback;
import com.google.zxing.activity.CaptureActivity;

import java.util.Hashtable;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;

/**
 * This thread does all the heavy lifting of decoding the images.
 * �����߳�
 */
final class DecodeThread extends Thread {

  public static final String BARCODE_BITMAP = "barcode_bitmap";
  private final CaptureActivity activity;
  private final Hashtable<DecodeHintType, Object> hints;
  private Handler handler;
  private final CountDownLatch handlerInitLatch;

  DecodeThread(CaptureActivity activity,
               Vector<BarcodeFormat> decodeFormats,
               String characterSet,
               ResultPointCallback resultPointCallback) {

    this.activity = activity;
    handlerInitLatch = new CountDownLatch(1);

    hints = new Hashtable<DecodeHintType, Object>(3);

    if (decodeFormats == null || decodeFormats.isEmpty()) {
    	 decodeFormats = new Vector<BarcodeFormat>();
    	 decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
    	 decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
    	 decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
    }
    
    hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);

    if (characterSet != null) {
      hints.put(DecodeHintType.CHARACTER_SET, characterSet);
    }

    hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, resultPointCallback);
  }

  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();
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/decoding/FinishListener.java
================================================
/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.decoding;

import android.app.Activity;
import android.content.DialogInterface;

/**
 * Simple listener used to exit the app in a few cases.
 *
 */
public final class FinishListener
    implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener, Runnable {

  private final Activity activityToFinish;

  public FinishListener(Activity activityToFinish) {
    this.activityToFinish = activityToFinish;
  }

  public void onCancel(DialogInterface dialogInterface) {
    run();
  }

  public void onClick(DialogInterface dialogInterface, int i) {
    run();
  }

  public void run() {
    activityToFinish.finish();
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/decoding/InactivityTimer.java
================================================
/*
 * Copyright (C) 2010 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.decoding;

import android.app.Activity;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * Finishes an activity after a period of inactivity.
 */
public final class InactivityTimer {

  private static final int INACTIVITY_DELAY_SECONDS = 5 * 60;

  private final ScheduledExecutorService inactivityTimer =
      Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory());
  private final Activity activity;
  private ScheduledFuture<?> inactivityFuture = null;

  public InactivityTimer(Activity activity) {
    this.activity = activity;
    onActivity();
  }

  public void onActivity() {
    cancel();
    inactivityFuture = inactivityTimer.schedule(new FinishListener(activity),
                                                INACTIVITY_DELAY_SECONDS,
                                                TimeUnit.SECONDS);
  }

  private void cancel() {
    if (inactivityFuture != null) {
      inactivityFuture.cancel(true);
      inactivityFuture = null;
    }
  }

  public void shutdown() {
    cancel();
    inactivityTimer.shutdown();
  }

  private static final class DaemonThreadFactory implements ThreadFactory {
    public Thread newThread(Runnable runnable) {
      Thread thread = new Thread(runnable);
      thread.setDaemon(true);
      return thread;
    }
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/decoding/Intents.java
================================================
/*
 * Copyright (C) 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.decoding;

/**
 * This class provides the constants to use when sending an Intent to Barcode Scanner.
 * These strings are effectively API and cannot be changed.
 */
public final class Intents {
  private Intents() {
  }

  public static final class Scan {
    /**
     * Send this intent to open the Barcodes app in scanning mode, find a barcode, and return
     * the results.
     */
    public static final String ACTION = "com.google.zxing.client.android.SCAN";

    /**
     * By default, sending Scan.ACTION will decode all barcodes that we understand. However it
     * may be useful to limit scanning to certain formats. Use Intent.putExtra(MODE, value) with
     * one of the values below ({@link #PRODUCT_MODE}, {@link #ONE_D_MODE}, {@link #QR_CODE_MODE}).
     * Optional.
     *
     * Setting this is effectively shorthnad for setting explicit formats with {@link #SCAN_FORMATS}.
     * It is overridden by that setting.
     */
    public static final String MODE = "SCAN_MODE";

    /**
     * Comma-separated list of formats to scan for. The values must match the names of
     * {@link com.google.zxing.BarcodeFormat}s, such as {@link com.google.zxing.BarcodeFormat#EAN_13}.
     * Example: "EAN_13,EAN_8,QR_CODE"
     *
     * This overrides {@link #MODE}.
     */
    public static final String SCAN_FORMATS = "SCAN_FORMATS";

    /**
     * @see com.google.zxing.DecodeHintType#CHARACTER_SET
     */
    public static final String CHARACTER_SET = "CHARACTER_SET";

    /**
     * Decode only UPC and EAN barcodes. This is the right choice for shopping apps which get
     * prices, reviews, etc. for products.
     */
    public static final String PRODUCT_MODE = "PRODUCT_MODE";

    /**
     * Decode only 1D barcodes (currently UPC, EAN, Code 39, and Code 128).
     */
    public static final String ONE_D_MODE = "ONE_D_MODE";

    /**
     * Decode only QR codes.
     */
    public static final String QR_CODE_MODE = "QR_CODE_MODE";

    /**
     * Decode only Data Matrix codes.
     */
    public static final String DATA_MATRIX_MODE = "DATA_MATRIX_MODE";

    /**
     * If a barcode is found, Barcodes returns RESULT_OK to onActivityResult() of the app which
     * requested the scan via startSubActivity(). The barcodes contents can be retrieved with
     * intent.getStringExtra(RESULT). If the user presses Back, the result code will be
     * RESULT_CANCELED.
     */
    public static final String RESULT = "SCAN_RESULT";

    /**
     * Call intent.getStringExtra(RESULT_FORMAT) to determine which barcode format was found.
     * See Contents.Format for possible values.
     */
    public static final String RESULT_FORMAT = "SCAN_RESULT_FORMAT";

    /**
     * Setting this to false will not save scanned codes in the history.
     */
    public static final String SAVE_HISTORY = "SAVE_HISTORY";

    private Scan() {
    }
  }

  public static final class Encode {
    /**
     * Send this intent to encode a piece of data as a QR code and display it full screen, so
     * that another person can scan the barcode from your screen.
     */
    public static final String ACTION = "com.google.zxing.client.android.ENCODE";

    /**
     * The data to encode. Use Intent.putExtra(DATA, data) where data is either a String or a
     * Bundle, depending on the type and format specified. Non-QR Code formats should
     * just use a String here. For QR Code, see Contents for details.
     */
    public static final String DATA = "ENCODE_DATA";

    /**
     * The type of data being supplied if the format is QR Code. Use
     * Intent.putExtra(TYPE, type) with one of Contents.Type.
     */
    public static final String TYPE = "ENCODE_TYPE";
    
    /**
     * The barcode format to be displayed. If this isn't specified or is blank, 
     * it defaults to QR Code. Use Intent.putExtra(FORMAT, format), where
     * format is one of Contents.Format. 
     */
    public static final String FORMAT = "ENCODE_FORMAT";

    private Encode() {
    }
  }

  public static final class SearchBookContents {
    /**
     * Use Google Book Search to search the contents of the book provided.
     */
    public static final String ACTION = "com.google.zxing.client.android.SEARCH_BOOK_CONTENTS";

    /**
     * The book to search, identified by ISBN number.
     */
    public static final String ISBN = "ISBN";

    /**
     * An optional field which is the text to search for.
     */
    public static final String QUERY = "QUERY";

    private SearchBookContents() {
    }
  }

  public static final class WifiConnect {
	    /**
	     * Internal intent used to trigger connection to a wi-fi network.
	     */
	    public static final String ACTION = "com.google.zxing.client.android.WIFI_CONNECT";

	    /**
	     * The network to connect to, all the configuration provided here.
	     */
	    public static final String SSID = "SSID";

	    /**
	     * The network to connect to, all the configuration provided here.
	     */
	    public static final String TYPE = "TYPE";

	    /**
	     * The network to connect to, all the configuration provided here.
	     */
	    public static final String PASSWORD = "PASSWORD";

	    private WifiConnect() {
	    }
	  }


  public static final class Share {
    /**
     * Give the user a choice of items to encode as a barcode, then render it as a QR Code and
     * display onscreen for a friend to scan with their phone.
     */
    public static final String ACTION = "com.google.zxing.client.android.SHARE";

    private Share() {
    }
  }
}


================================================
FILE: app/src/main/java/com/google/zxing/decoding/RGBLuminanceSource.java
================================================
/*
 * Copyright 2009 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.decoding;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import com.google.zxing.LuminanceSource;

import java.io.FileNotFoundException;

/**
 * This class is used to help decode images from files which arrive as RGB data
 * from Android bitmaps. It does not support cropping or rotation.
 * 
 */
public final 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;
	}

	// Since this class does not support cropping, the underlying byte array
	// already contains
	// exactly what the caller is asking for, so give it to them without a copy.
	@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;
	}

}


================================================
FILE: app/src/main/java/com/google/zxing/encoding/EncodingHandler.java
================================================
package com.google.zxing.encoding;

import android.graphics.Bitmap;
import android.graphics.Canvas;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * @author Ryan Tang
 *
 */
public final class EncodingHandler {
	private static final int BLACK = 0xff000000;
	
	public static Bitmap createQRCode(String str, int widthAndHeight) throws WriterException {
		Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 
		BitMatrix matrix = new MultiFormatWriter().encode(str,
				BarcodeFormat.QR_CODE, widthAndHeight, widthAndHeight);
		int width = matrix.getWidth();
		int height = matrix.getHeight();
		int[] pixels = new int[width * height];
		
		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				if (matrix.get(x, y)) {
					pixels[y * width + x] = BLACK;
				}
			}
		}
		Bitmap bitmap = Bitmap.createBitmap(width, height,
				Bitmap.Config.ARGB_8888);
		bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
		return bitmap;
	}
	
	/**
	 * 创建二维码
	 *
	 * @param content   content
	 * @param widthPix  widthPix
	 * @param heightPix heightPix
	 * @param logoBm    logoBm
	 * @return 二维码
	 */
	public static Bitmap createQRCode(String content, int widthPix, int heightPix, Bitmap logoBm) {
		try {
			if (content == null || "".equals(content)) {
				return null;
			}
			// 配置参数
			Map<EncodeHintType, Object> hints = new HashMap<>();
			hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
			// 容错级别
			hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
			// 图像数据转换,使用了矩阵转换
			BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, widthPix,
					heightPix, hints);
			int[] pixels = new int[widthPix * heightPix];
			// 下面这里按照二维码的算法,逐个生成二维码的图片,
			// 两个for循环是图片横列扫描的结果
			for (int y = 0; y < heightPix; y++) {
				for (int x = 0; x < widthPix; x++) {
					if (bitMatrix.get(x, y)) {
						pixels[y * widthPix + x] = 0xff000000;
					} else {
						pixels[y * widthPix + x] = 0xffffffff;
					}
				}
			}
			// 生成二维码图片的格式,使用ARGB_8888
			Bitmap bitmap = Bitmap.createBitmap(widthPix, heightPix, Bitmap.Config.ARGB_8888);
			bitmap.setPixels(pixels, 0, widthPix, 0, 0, widthPix, heightPix);
			if (logoBm != null) {
				bitmap = addLogo(bitmap, logoBm);
			}
			//必须使用compress方法将bitmap保存到文件中再进行读取。直接返回的bitmap是没有任何压缩的,内存消耗巨大!
			return bitmap;
		} catch (WriterException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 在二维码中间添加Logo图案
	 */
	private static Bitmap addLogo(Bitmap src, Bitmap logo) {
		if (src == null) {
			return null;
		}
		if (logo == null) {
			return src;
		}
		//获取图片的宽高
		int srcWidth = src.getWidth();
		int srcHeight = src.getHeight();
		int logoWidth = logo.getWidth();
		int logoHeight = logo.getHeight();
		if (srcWidth == 0 || srcHeight == 0) {
			return null;
		}
		if (logoWidth == 0 || logoHeight == 0) {
			return src;
		}
		//logo大小为二维码整体大小的1/5
		float scaleFactor = srcWidth * 1.0f / 5 / logoWidth;
		Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
		try {
			Canvas canvas = new Canvas(bitmap);
			canvas.drawBitmap(src, 0, 0, null);
			canvas.scale(scaleFactor, scaleFactor, srcWidth / 2, srcHeight / 2);
			canvas.drawBitmap(logo, (srcWidth - logoWidth) / 2, (srcHeight - logoHeight) / 2, null);
			canvas.save();
			canvas.restore();
		} catch (Exception e) {
			bitmap = null;
			e.getStackTrace();
		}
		return bitmap;
	}
}


================================================
FILE: app/src/main/java/com/google/zxing/view/ViewfinderResultPointCallback.java
================================================
/*
 * Copyright (C) 2009 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.view;

import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;

public final class ViewfinderResultPointCallback implements ResultPointCallback {
  private final ViewfinderView viewfinderView;

  public ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
    this.viewfinderView = viewfinderView;
  }

  public void foundPossibleResultPoint(ResultPoint point) {
    viewfinderView.addPossibleResultPoint(point);
  }

}


================================================
FILE: app/src/main/java/com/google/zxing/view/ViewfinderView.java
================================================
/*
 * Copyright (C) 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.zxing.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.view.View;

import com.vone.qrcode.R;
import com.google.zxing.ResultPoint;
import com.google.zxing.camera.CameraManager;

import java.util.Collection;
import java.util.HashSet;


/**
 * This view is overlaid on top of the camera preview. It adds the viewfinder rectangle and partial
 * transparency outside it, as well as the laser scanner animation and result points.
 * @author dswitkin@google.com (Daniel Switkin)
 */
public final class ViewfinderView extends View {

  private static final int[]  SCANNER_ALPHA                 =   {0, 64, 128, 192, 255, 192, 128, 64};
  private static final long   ANIMATION_DELAY               =   10L;
  private static final int    OPAQUE                        =   0xFF;
  private static final int    CORNER_RECT_WIDTH             =   8;  //扫描区边角的宽
  private static final int    CORNER_RECT_HEIGHT            =   40; //扫描区边角的高
  private static final int    SCANNER_LINE_MOVE_DISTANCE    =   5;  //扫描线移动距离
  private static final int    SCANNER_LINE_HEIGHT           =   10;  //扫描线宽度

  private final Paint paint;
  private Bitmap resultBitmap;
  //模糊区域颜色
  private final int maskColor;
  private final int resultColor;
  //扫描区域边框颜色
  private final int frameColor;
  //扫描线颜色
  private final int laserColor;
  //四角颜色
  private final int cornerColor;
  //扫描点的颜色
  private final int resultPointColor;
  private int scannerAlpha;
  //扫描区域提示文本
  private final String labelText;
  //扫描区域提示文本颜色
  private final int labelTextColor;
  private final float labelTextSize;

  public static int scannerStart = 0;
  public static int scannerEnd = 0;

  private Collection<ResultPoint> possibleResultPoints;
  private Collection<ResultPoint> lastPossibleResultPoints;

  // This constructor is used when the class is built from an XML resource.
  public ViewfinderView(Context context, AttributeSet attrs) {
    super(context, attrs);

    //初始化自定义属性信息
    TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ViewfinderView);
    laserColor = array.getColor(R.styleable.ViewfinderView_laser_color, 0x00FF00);
    cornerColor = array.getColor(R.styleable.ViewfinderView_corner_color, 0x00FF00);
    frameColor = array.getColor(R.styleable.ViewfinderView_frame_color, 0xFFFFFF);
    resultPointColor = array.getColor(R.styleable.ViewfinderView_result_point_color, 0xC0FFFF00);
    maskColor = array.getColor(R.styleable.ViewfinderView_mask_color, 0x60000000);
    resultColor = array.getColor(R.styleable.ViewfinderView_result_color, 0xB0000000);
    labelTextColor = array.getColor(R.styleable.ViewfinderView_label_text_color, 0x90FFFFFF);
    labelText = array.getString(R.styleable.ViewfinderView_label_text);
    labelTextSize = array.getFloat(R.styleable.ViewfinderView_label_text_size, 36f);

    // Initialize these once for performance rather than calling them every time in onDraw().
    paint = new Paint();
    paint.setAntiAlias(true);
    scannerAlpha = 0;
    possibleResultPoints = new HashSet<ResultPoint>(5);


  }

  @Override
  public void onDraw(Canvas canvas) {
    Rect frame = CameraManager.get().getFramingRect();
    if (frame == null) {
      return;
    }
    if(scannerStart == 0 || scannerEnd == 0) {
      scannerStart = frame.top;
      scannerEnd = frame.bottom;
    }

    int width = canvas.getWidth();
    int height = canvas.getHeight();
    // Draw the exterior (i.e. outside the framing rect) darkened
    drawExterior(canvas, frame, width, height);


    if (resultBitmap != null) {
      // Draw the opaque result bitmap over the scanning rectangle
      paint.setAlpha(OPAQUE);
      canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint);
    } else {
      // Draw a two pixel solid black border inside the framing rect
      drawFrame(canvas, frame);
      // 绘制边角
      drawCorner(canvas, frame);
      //绘制提示信息
      drawTextInfo(canvas, frame);
      // Draw a red "laser scanner" line through the middle to show decoding is active
      drawLaserScanner(canvas, frame);

      Collection<ResultPoint> currentPossible = possibleResultPoints;
      Collection<ResultPoint> currentLast = lastPossibleResultPoints;
      if (currentPossible.isEmpty()) {
        lastPossibleResultPoints = null;
      } else {
        possibleResultPoints = new HashSet<ResultPoint>(5);
        lastPossibleResultPoints = currentPossible;
        paint.setAlpha(OPAQUE);
        paint.setColor(resultPointColor);
        for (ResultPoint point : currentPossible) {
          canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 6.0f, paint);
        }
      }
      if (currentLast != null) {
        paint.setAlpha(OPAQUE / 2);
        paint.setColor(resultPointColor);
        for (ResultPoint point : currentLast) {
          canvas.drawCircle(frame.left + point.getX(), frame.top + point.getY(), 3.0f, paint);
        }
      }

      // Request another update at the animation interval, but only repaint the laser line,
      // not the entire viewfinder mask.
      //指定重绘区域,该方法会在子线程中执行
      postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom);
    }
  }

  //绘制文本
  private void drawTextInfo(Canvas canvas, Rect frame) {
    paint.setColor(labelTextColor);
    paint.setTextSize(labelTextSize);
    paint.setTextAlign(Paint.Align.CENTER);
    canvas.drawText(labelText, frame.left + frame.width() / 2, frame.bottom + CORNER_RECT_HEIGHT * 1.5f, paint);
  }


  //绘制边角
  private void drawCorner(Canvas canvas, Rect frame) {
    paint.setColor(cornerColor);
    //左上
    canvas.drawRect(frame.left, frame.top, frame.left + CORNER_RECT_WIDTH, frame.top + CORNER_RECT_HEIGHT, paint);
    canvas.drawRect(frame.left, frame.top, frame.left + CORNER_RECT_HEIGHT, frame.top + CORNER_RECT_WIDTH, paint);
    //右上
    canvas.drawRect(frame.right - CORNER_RECT_WIDTH, frame.top, frame.right, frame.top + CORNER_RECT_HEIGHT, paint);
    canvas.drawRect(frame.right - CORNER_RECT_HEIGHT, frame.top, frame.right, frame.top + CORNER_RECT_WIDTH, paint);
    //左下
    canvas.drawRect(frame.left, frame.bottom - CORNER_RECT_WIDTH, frame.left + CORNER_RECT_HEIGHT, frame.bottom, paint);
    canvas.drawRect(frame.left, frame.bottom - CORNER_RECT_HEIGHT, frame.left + CORNER_RECT_WIDTH, frame.bottom, paint);
    //右下
    canvas.drawRect(frame.right - CORNER_RECT_WIDTH, frame.bottom - CORNER_RECT_HEIGHT, frame.right, frame.bottom, paint);
    canvas.drawRect(frame.right - CORNER_RECT_HEIGHT, frame.bottom - CORNER_RECT_WIDTH, frame.right, frame.bottom, paint);
  }

  //绘制扫描线
  private void drawLaserScanner(Canvas canvas, Rect frame) {
    paint.setColor(laserColor);
    //扫描线闪烁效果
//    paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
//    scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
//    int middle = frame.height() / 2 + frame.top;
//    canvas.drawRect(frame.left + 2, middle - 1, frame.right - 1, middle + 2, paint);
    //线性渐变
    LinearGradient linearGradient = new LinearGradient(
            frame.left, scannerStart,
            frame.left, scannerStart + SCANNER_LINE_HEIGHT,
            shadeColor(laserColor),
            laserColor,
            Shader.TileMode.MIRROR);

    RadialGradient radialGradient = new RadialGradient(
            (float)(frame.left + frame.width() / 2),
            (float)(scannerStart + SCANNER_LINE_HEIGHT / 2),
              360f,
            laserColor,
            shadeColor(laserColor),
            Shader.TileMode.MIRROR);

    SweepGradient sweepGradient = new SweepGradient(
            (float)(frame.left + frame.width() / 2),
            (float)(scannerStart + SCANNER_LINE_HEIGHT),
            shadeColor(laserColor),
            laserColor);

    ComposeShader composeShader = new ComposeShader(radialGradient, linearGradient, PorterDuff.Mode.ADD);

    paint.setShader(radialGradient);
    if(scannerStart <= scannerEnd) {
      //矩形
//      canvas.drawRect(frame.left, scannerStart, frame.right, scannerStart + SCANNER_LINE_HEIGHT, paint);
      //椭圆
      RectF rectF = new RectF(frame.left + 2 * SCANNER_LINE_HEIGHT, scannerStart, frame.right - 2 * SCANNER_LINE_HEIGHT, scannerStart + SCANNER_LINE_HEIGHT);
      canvas.drawOval(rectF, paint);
      scannerStart += SCANNER_LINE_MOVE_DISTANCE;
    } else {
      scannerStart = frame.top;
    }
    paint.setShader(null);
  }

  //处理颜色模糊
  public int shadeColor(int color) {
    String hax = Integer.toHexString(color);
    String result = "20"+hax.substring(2);
    return Integer.valueOf(result, 16);
  }

  // 绘制扫描区边框 Draw a two pixel solid black border inside the framing rect
  private void drawFrame(Canvas canvas, Rect frame) {
    paint.setColor(frameColor);
    canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
    canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
    canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
    canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);
  }

  // 绘制模糊区域 Draw the exterior (i.e. outside the framing rect) darkened
  private void drawExterior(Canvas canvas, Rect frame, int width, int height) {
    paint.setColor(resultBitmap != null ? resultColor : maskColor);
    canvas.drawRect(0, 0, width, frame.top, paint);
    canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
    canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
    canvas.drawRect(0, frame.bottom + 1, width, height, paint);
  }

  public void drawViewfinder() {
    resultBitmap = null;
    invalidate();
  }

  /**
   * Draw a bitmap with the result points highlighted instead of the live scanning display.
   *
   * @param barcode An image of the decoded barcode.
   */
  public void drawResultBitmap(Bitmap barcode) {
    resultBitmap = barcode;
    invalidate();
  }

  public void addPossibleResultPoint(ResultPoint point) {
    possibleResultPoints.add(point);
  }

}


================================================
FILE: app/src/main/java/com/vone/vmq/App.java
================================================
package com.vone.vmq;

import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.os.Process;
import android.util.Log;

public class App extends Application {

    @SuppressLint("StaticFieldLeak")
    private static Context mContext;

    public static Context getContext() {
        return mContext;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable throwable) {
                Utils.putStr(App.this, "exception:" + Log.getStackTraceString(throwable));
                Process.killProcess(Process.myPid());
            }
        });
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        mContext = base;
    }
}


================================================
FILE: app/src/main/java/com/vone/vmq/Constant.java
================================================
package com.vone.vmq;

/**
 * Created by user68 on 2018/7/30.
 */

@SuppressWarnings({"unused", "WeakerAccess"})
public class Constant {

    public final static String GET_MESSAGE_KEY = "get_message_key";

    public final static String FINISH_LOCK_SHOW_ACTIVITY = "finish_lock_show_activity";
    public final static String UPDATA_MESSAGE_DATA_ACTION = "updata_message_data_action";
    public final static String FINISH_FOREGROUND_SERVICE = "finish_foreground_service";

}


================================================
FILE: app/src/main/java/com/vone/vmq/ForegroundServer.java
================================================
package com.vone.vmq;

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;
import android.util.Log;

import com.vone.qrcode.R;

import org.json.JSONObject;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;

@SuppressWarnings("FieldCanBeLocal")
public class ForegroundServer extends Service {
    public static final String GET_NOTIFY_TITLE = "get_notify_title";
    public static final String GET_NOTIFY_TEXT = "get_notify_text";
    //这里传 json 过来
    public static final String GET_NOTIFY_EXTRA = "get_notify_extra";

    private final int FOREGROUND_ID = 1;

    private final String channel_name = "ForegoundServer";
    private final String CHANNEL_ID = "service";

    private final Handler handler = new Handler(Looper.getMainLooper());

    private final long MIN_SHOW_TIME = 2000;
    private final long MAX_SHOW_TIME = 20000;

    private long enterTime;

    @Override
    public void onCreate() {
        super.onCreate();
        enterTime = SystemClock.elapsedRealtime();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            setForegroundService();
        }
        registerFinishBroad();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        handler.removeCallbacks(stopServerRunnable);
        handler.postDelayed(stopServerRunnable, MAX_SHOW_TIME);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            updateNotify(intent);
        }
        startForegroundActivity(intent);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        unregisterFinishBroad();
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        Log.i("ForegoundServer", "stop notification");
        if (notificationManager != null) {
            notificationManager.cancel(FOREGROUND_ID);
        }
        handler.removeCallbacks(stopServerRunnable);
        super.onDestroy();
    }

    private void startForegroundActivity(Intent intent) {
        if (intent == null) {
            return;
        }
        String extraStr = intent.getStringExtra(GET_NOTIFY_EXTRA);
        if (TextUtils.isEmpty(extraStr)) {
            return;
        }
        try {
            JSONObject jsonObject = new JSONObject(extraStr);
            final String url = jsonObject.optString("url");
            if (url == null) {
                return;
            }
            if (jsonObject.optBoolean("show", true)) {
                startLockActivity(this.getString(R.string.app_is_post));
            }
            tryPushByUrl(url, jsonObject.optInt("try_count", 1));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void tryPushByUrl(final String url, final int count) {
        if (count <= 0) {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    NeNotificationService2.exitForeground(App.getContext());
                }
            });
            return;
        }
        // 进行一个短暂的延迟再通知过去
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Request request = new Request.Builder().url(url).method("GET", null).build();
                Call call = Utils.getOkHttpClient().newCall(request);
                call.enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        Log.d("ForegroundServer", "onResponse  push: 请求失败");
                        tryPushByUrl(url, count - 1);
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        try {
                            Log.d("ForegroundServer", "onResponse  push: " + response.body().string());
                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {
                            if (!response.isSuccessful()) {
                                tryPushByUrl(url, count - 1);
                            } else {
                                handler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        NeNotificationService2.exitForeground(App.getContext());
                                    }
                                });
                            }
                        }
                    }
                });
            }
        }, MIN_SHOW_TIME);
    }

    /**
     * 通过通知启动服务
     */
    @TargetApi(Build.VERSION_CODES.O)
    private void setForegroundService() {
        Utils.createNotificationChannel(this, CHANNEL_ID, channel_name
                , NotificationManager.IMPORTANCE_DEFAULT);
        Notification notification = getNotifycation(null);

        startForeground(FOREGROUND_ID, notification);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void updateNotify(Intent intent) {
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        if (notificationManager != null) {
            Notification notification = getNotifycation(intent);

            notificationManager.notify(FOREGROUND_ID, notification);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private Notification getNotifycation(Intent intent) {
        String title = intent == null ? getString(R.string.app_name) :
                TextUtils.isEmpty(intent.getStringExtra(GET_NOTIFY_TITLE)) ? getString(R.string.app_name)
                        : intent.getStringExtra(GET_NOTIFY_TITLE);
        String text = intent == null ? getString(R.string.click_close_notify) :
                TextUtils.isEmpty(intent.getStringExtra(GET_NOTIFY_TEXT)) ? getString(R.string.click_close_notify)
                        : intent.getStringExtra(GET_NOTIFY_TEXT);
        Notification.Builder notificationBuilder = new Notification.Builder(this)
                .setContentTitle(title)//设置通知标题
                .setContentText(text)//设置通知内容
                .setPriority(Notification.PRIORITY_MIN)
                .setCategory(Notification.CATEGORY_SERVICE)
                .setOngoing(true)
                .setWhen(System.currentTimeMillis())
                .setShowWhen(true)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setAutoCancel(true);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            notificationBuilder.setChannelId(CHANNEL_ID);
        }

        Notification notification = notificationBuilder.build();

        Intent notificationIntent = new Intent(getApplicationContext(), StartReceive.class);
        notificationIntent.setAction(StartReceive.TRY_CLOSE_ACTIVITY_ACTION);
        notification.contentIntent = PendingIntent.getBroadcast(getApplicationContext(),
                0, notificationIntent, 0);
        return notification;
    }

    private void registerFinishBroad() {
        registerReceiver(finishServiceBroadcast,
                new IntentFilter(Constant.FINISH_FOREGROUND_SERVICE));
    }

    private void unregisterFinishBroad() {
        try {
            this.unregisterReceiver(finishServiceBroadcast);
        } catch (Exception ignore) {
        }
    }

    private final Runnable stopServerRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                finishLockActivity();
                Intent intent1 = new Intent(App.getContext(), ForegroundServer.class);
                stopService(intent1);
            } catch (Exception ignore) {
            }
        }
    };

    private final BroadcastReceiver finishServiceBroadcast = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (Constant.FINISH_FOREGROUND_SERVICE.equals(intent.getAction())) {
                long temp = SystemClock.elapsedRealtime() - enterTime;
                handler.removeCallbacks(stopServerRunnable);
                if (temp > MIN_SHOW_TIME) {
                    handler.post(stopServerRunnable);
                } else {
                    handler.postDelayed(stopServerRunnable, MIN_SHOW_TIME - temp);
                }
            }
        }
    };

    private void startLockActivity(String msg) {
        Intent intent = new Intent(this, LockShowActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra(Constant.GET_MESSAGE_KEY, msg);
        startActivity(intent);
    }

    private void finishLockActivity() {
        Intent sendIntent = new Intent();
        sendIntent.setAction(Constant.FINISH_LOCK_SHOW_ACTIVITY);
        sendBroadcast(sendIntent);
    }

    private void updataMessageData(String msg) {
        Intent sendIntent = new Intent();
        sendIntent.setAction(Constant.UPDATA_MESSAGE_DATA_ACTION);
        sendIntent.putExtra(Constant.GET_MESSAGE_KEY, msg);
        sendBroadcast(sendIntent);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}


================================================
FILE: app/src/main/java/com/vone/vmq/LockShowActivity.java
================================================
package com.vone.vmq;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.view.WindowManager;
import android.widget.TextView;

import com.vone.qrcode.R;

public class LockShowActivity extends Activity {
    private TextView showTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_lock_show);
        registerBroadCast();
        InitView();
        InitData();
    }

    private void registerBroadCast() {
        IntentFilter filter = new IntentFilter(Constant.FINISH_LOCK_SHOW_ACTIVITY);
        registerReceiver(finishActivityBroadcast, filter);
    }

    private void unregisterBroadCast() {
        unregisterReceiver(finishActivityBroadcast);
    }

    private void InitView() {
        showTv = findViewById(R.id.showTv);
    }

    private void InitData() {
        resetData(getIntent());
    }

    /**
     * 显示通知类型:
     * -1 :检测到对应的配置通知
     * 0 : 远程的重要通知
     * 1 : 通知栏通知
     */
    private void resetData(Intent intent) {
        String showTvText = intent.getStringExtra(Constant.GET_MESSAGE_KEY);
        showTv.setText(showTvText);
    }


    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        resetData(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterBroadCast();
    }

    private final BroadcastReceiver finishActivityBroadcast = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (Constant.FINISH_LOCK_SHOW_ACTIVITY.equals(intent.getAction())) {
                if (!isFinishing()) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        finishAndRemoveTask();
                    }
                }
            } else if (Constant.UPDATA_MESSAGE_DATA_ACTION.equals(intent.getAction())) {
                resetData(intent);
            }
        }
    };
}


================================================
FILE: app/src/main/java/com/vone/vmq/MainActivity.java
================================================
package com.vone.vmq;

import android.Manifest;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.google.zxing.activity.CaptureActivity;
import com.vone.qrcode.R;
import com.vone.vmq.util.Constant;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {

    private final Handler handler = new Handler(Looper.getMainLooper());
    private TextView txthost;
    private TextView txtkey;

    private boolean isOk = false;
    private static String TAG = "MainActivity";

    private static String host;
    private static String key;
    int id = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        txthost = (TextView) findViewById(R.id.txt_host);
        txtkey = (TextView) findViewById(R.id.txt_key);

        //检测通知使用权是否启用
        if (!isNotificationListenersEnabled()) {
            //跳转到通知使用权页面
            gotoNotificationAccessSetting();
        } else if (!Utils.checkBatteryWhiteList(this)) {
            Utils.gotoBatterySetting(this);
        }
        //重启监听服务
        if (!NeNotificationService2.isRunning) {
            toggleNotificationListenerService(this);
        }
        //读入保存的配置数据并显示
        SharedPreferences read = getSharedPreferences("vone", MODE_PRIVATE);
        host = read.getString("host", "");
        key = read.getString("key", "");

        if (host != null && key != null && host != "" && key != "") {
            txthost.setText(" 通知地址:" + host);
            txtkey.setText(" 通讯密钥:" + key);
            isOk = true;
        }
        Toast.makeText(MainActivity.this, "v免签开源免费免签系统 v1.8.1", Toast.LENGTH_SHORT).show();
    }

    //扫码配置
    public void startQrCode(View v) {
        // 申请相机权限
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            // 申请权限
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, Constant.REQ_PERM_CAMERA);
            return;
        }
        // 申请文件读写权限(部分朋友遇到相册选图需要读写权限的情况,这里一并写一下)
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            // 申请权限
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, Constant.REQ_PERM_EXTERNAL_STORAGE);
            return;
        }
        // 二维码扫码
        Intent intent = new Intent(MainActivity.this, CaptureActivity.class);
        startActivityForResult(intent, Constant.REQ_QR_CODE);
    }

    //手动配置
    public void doInput(View v) {
        final EditText inputServer = new EditText(this);
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("请输入配置数据").setView(inputServer)
                .setNegativeButton("取消", null);
        builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {

            public void onClick(DialogInterface dialog, int which) {
                String scanResult = inputServer.getText().toString();

                String[] tmp = scanResult.split("/");
                if (tmp.length != 2) {
                    Toast.makeText(MainActivity.this, "数据错误,请您输入网站上显示的配置数据!", Toast.LENGTH_SHORT).show();
                    return;
                }

                String t = String.valueOf(new Date().getTime());
                String sign = md5(t + tmp[1]);

                Request request = new Request.Builder().url("http://" + tmp[0] + "/appHeart?t=" + t + "&sign=" + sign).method("GET", null).build();
                Call call = Utils.getOkHttpClient().newCall(request);
                call.enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {

                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        try {
                            Log.d(TAG, "onResponse: " + response.body().string());
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        isOk = true;
                    }
                });
                if (tmp[0].indexOf("localhost") >= 0) {
                    Toast.makeText(MainActivity.this, "配置信息错误,本机调试请访问 本机局域网IP:8080(如192.168.1.101:8080) 获取配置信息进行配置!", Toast.LENGTH_LONG).show();

                    return;
                }
                //将扫描出的信息显示出来
                txthost.setText(" 通知地址:" + tmp[0]);
                txtkey.setText(" 通讯密钥:" + tmp[1]);
                host = tmp[0];
                key = tmp[1];

                SharedPreferences.Editor editor = getSharedPreferences("vone", MODE_PRIVATE).edit();
                editor.putString("host", host);
                editor.putString("key", key);
                editor.commit();

            }
        });
        builder.show();

    }

    //检测心跳
    public void doStart(View view) {
        if (!isOk) {
            Toast.makeText(MainActivity.this, "请您先配置!", Toast.LENGTH_SHORT).show();
            return;
        }

        String t = String.valueOf(new Date().getTime());
        String sign = md5(t + key);

        Request request = new Request.Builder().url("http://" + host + "/appHeart?t=" + t + "&sign=" + sign).method("GET", null).build();
        Call call = Utils.getOkHttpClient().newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, "心跳状态错误,请检查配置是否正确!", Toast.LENGTH_SHORT).show();
                    }
                });
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            // 为什么每一个response都 try catch了,因为response.body有可能为空
                            Toast.makeText(MainActivity.this, "心跳返回:" + response.body().string(), Toast.LENGTH_LONG).show();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        });
    }

    //检测监听
    public void checkPush(View v) {
        Notification mNotification;
        NotificationManager mNotificationManager;
        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel("1",
                    "Channel1", NotificationManager.IMPORTANCE_DEFAULT);
            channel.enableLights(true);
            channel.setLightColor(Color.GREEN);
            channel.setShowBadge(true);
            mNotificationManager.createNotificationChannel(channel);

            Notification.Builder builder = new Notification.Builder(this, "1");

            mNotification = builder
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setTicker("这是一条测试推送信息,如果程序正常,则会提示监听权限正常")
                    .setContentTitle("V免签测试推送")
                    .setContentText("这是一条测试推送信息,如果程序正常,则会提示监听权限正常")
                    .build();
        } else {
            mNotification = new Notification.Builder(MainActivity.this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setTicker("这是一条测试推送信息,如果程序正常,则会提示监听权限正常")
                    .setContentTitle("V免签测试推送")
                    .setContentText("这是一条测试推送信息,如果程序正常,则会提示监听权限正常")
                    .build();
        }
        //Toast.makeText(MainActivity.this, "已推送信息,如果权限,那么将会有下一条提示!", Toast.LENGTH_SHORT).show();

        mNotificationManager.notify(id++, mNotification);
    }

    //各种权限的判断
    private void toggleNotificationListenerService(Context context) {
        PackageManager pm = context.getPackageManager();
        pm.setComponentEnabledSetting(new ComponentName(context, NeNotificationService2.class),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);

        pm.setComponentEnabledSetting(new ComponentName(context, NeNotificationService2.class),
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

        // 不要每次打开都显示
        // Toast.makeText(MainActivity.this, "监听服务启动中...", Toast.LENGTH_SHORT).show();
    }

    public boolean isNotificationListenersEnabled() {
        String pkgName = getPackageName();
        final String flat = Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners");
        if (!TextUtils.isEmpty(flat)) {
            final String[] names = flat.split(":");
            for (int i = 0; i < names.length; i++) {
                final ComponentName cn = ComponentName.unflattenFromString(names[i]);
                if (cn != null) {
                    if (TextUtils.equals(pkgName, cn.getPackageName())) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    protected boolean gotoNotificationAccessSetting() {
        try {
            Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            return true;
        } catch (ActivityNotFoundException e) {//普通情况下找不到的时候需要再特殊处理找一次
            try {
                Intent intent = new Intent();
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                ComponentName cn = new ComponentName("com.android.settings", "com.android.settings.Settings$NotificationAccessSettingsActivity");
                intent.setComponent(cn);
                intent.putExtra(":settings:show_fragment", "NotificationAccessSettings");
                startActivity(intent);
                return true;
            } catch (Exception e1) {
                e1.printStackTrace();
            }
            Toast.makeText(this, "对不起,您的手机暂不支持", Toast.LENGTH_SHORT).show();
            e.printStackTrace();
            return false;
        }
    }

    public static String md5(String string) {
        if (TextUtils.isEmpty(string)) {
            return "";
        }
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
            byte[] bytes = md5.digest(string.getBytes());
            StringBuilder result = new StringBuilder();
            for (byte b : bytes) {
                String temp = Integer.toHexString(b & 0xff);
                if (temp.length() == 1) {
                    temp = "0" + temp;
                }
                result.append(temp);
            }
            return result.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //扫描结果回调
        if (requestCode == Constant.REQ_QR_CODE && resultCode == RESULT_OK) {
            Bundle bundle = data.getExtras();
            String scanResult = bundle.getString(Constant.INTENT_EXTRA_KEY_QR_SCAN);

            String[] tmp = scanResult.split("/");
            if (tmp.length != 2) {
                Toast.makeText(MainActivity.this, "二维码错误,请您扫描网站上显示的二维码!", Toast.LENGTH_SHORT).show();
                return;
            }

            String t = String.valueOf(new Date().getTime());
            String sign = md5(t + tmp[1]);

            Request request = new Request.Builder().url("http://" + tmp[0] + "/appHeart?t=" + t + "&sign=" + sign).method("GET", null).build();
            Call call = Utils.getOkHttpClient().newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {

                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    try {
                        Log.d(TAG, "onResponse: " + response.body().string());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    isOk = true;
                }
            });

            //将扫描出的信息显示出来
            txthost.setText(" 通知地址:" + tmp[0]);
            txtkey.setText(" 通讯密钥:" + tmp[1]);
            host = tmp[0];
            key = tmp[1];

            SharedPreferences.Editor editor = getSharedPreferences("vone", MODE_PRIVATE).edit();
            editor.putString("host", host);
            editor.putString("key", key);
            editor.commit();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case Constant.REQ_PERM_CAMERA:
                // 摄像头权限申请
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // 获得授权
                    startQrCode(null);
                } else {
                    // 被禁止授权
                    Toast.makeText(MainActivity.this, "请至权限中心打开本应用的相机访问权限", Toast.LENGTH_LONG).show();
                }
                break;
            case Constant.REQ_PERM_EXTERNAL_STORAGE:
                // 文件读写权限申请
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // 获得授权
                    startQrCode(null);
                } else {
                    // 被禁止授权
                    Toast.makeText(MainActivity.this, "请至权限中心打开本应用的文件读写权限", Toast.LENGTH_LONG).show();
                }
                break;
        }
    }
}


================================================
FILE: app/src/main/java/com/vone/vmq/NeNotificationService2.java
================================================
package com.vone.vmq;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.vone.qrcode.R;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;

public class NeNotificationService2 extends NotificationListenerService {
    private static String TAG = "NeNotificationService2";
    private final Handler handler = new Handler(Looper.getMainLooper());
    private String host = "";
    private String key = "";
    private Thread newThread = null;
    private PowerManager.WakeLock mWakeLock = null;
    public static boolean isRunning;

    //申请设备电源锁
    @SuppressLint("InvalidWakeLockTag")
    public void acquireWakeLock(final Context context) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (null == mWakeLock) {
                    PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
                    if (pm != null) {
                        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "WakeLock");
                    }
                }
                if (null != mWakeLock) {
                    mWakeLock.acquire(5000);
                }
            }
        });

    }

    //释放设备电源锁
    public void releaseWakeLock() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (null != mWakeLock) {
                    mWakeLock.release();
                    mWakeLock = null;
                }
            }
        });
    }

    //心跳进程
    public void initAppHeart() {
        Log.d(TAG, "开始启动心跳线程");
        newThread = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "心跳线程启动!");
                while (isRunning && newThread == Thread.currentThread()) {
                    SharedPreferences read = getSharedPreferences("vone", MODE_PRIVATE);
                    host = read.getString("host", "");
                    key = read.getString("key", "");

                    //这里写入子线程需要做的工作
                    String t = String.valueOf(new Date().getTime());
                    String sign = md5(t + key);

                    final String url = "http://" + host + "/appHeart?t=" + t + "&sign=" + sign;
                    Request request = new Request.Builder().url(url).method("GET", null).build();
                    Call call = Utils.getOkHttpClient().newCall(request);
                    call.enqueue(new Callback() {
                        @Override
                        public void onFailure(Call call, IOException e) {
                            // final String error = e.getMessage();
                            // Toast.makeText(getApplicationContext(), "心跳状态错误,请检查配置是否正确!" + error, Toast.LENGTH_LONG).show();
                            foregroundHeart(url);
                        }

                        //请求成功执行的方法
                        @Override
                        public void onResponse(Call call, Response response) throws IOException {
                            try {
                                Log.d(TAG, "onResponse heard: " + response.body().string());
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            if (!response.isSuccessful()) {
                                foregroundHeart(url);
                            }
                        }
                    });
                    try {
                        Thread.sleep(30 * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        newThread.start(); //启动线程
    }


    //当收到一条消息的时候回调,sbn是收到的消息
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        Log.d(TAG, "接受到通知消息");
        writeNotifyToFile(sbn);
        // 微信支付部分通知,会调用两次,导致统计不准确
        if ((sbn.getNotification().flags & Notification.FLAG_GROUP_SUMMARY) != 0) {
            Log.d(TAG, "群组摘要通知,忽略");
            return;
        }
        SharedPreferences read = getSharedPreferences("vone", MODE_PRIVATE);
        host = read.getString("host", "");
        key = read.getString("key", "");

        Notification notification = sbn.getNotification();
        String pkg = sbn.getPackageName();
        if (notification != null) {
            Bundle extras = notification.extras;
            if (extras != null) {
                CharSequence _title = extras.getCharSequence(NotificationCompat.EXTRA_TITLE, "");
                CharSequence _content = extras.getCharSequence(NotificationCompat.EXTRA_TEXT, "");
                Log.d(TAG, "**********************");
                Log.d(TAG, "包名:" + pkg);
                Log.d(TAG, "标题:" + _title);
                Log.d(TAG, "内容:" + _content);
                Log.d(TAG, "**********************");
                // to string (企业微信之类的 getString 会出错,换getCharSequence)
                String title = _title.toString();
                String content = _content.toString();
                if ("com.eg.android.AlipayGphone".equals(pkg)) {
                    if (!content.equals("")) {
                        if (content.contains("通过扫码向你付款") || content.contains("成功收款")
                                || title.contains("通过扫码向你付款") || title.contains("成功收款")
                                || content.contains("店员通") || title.contains("店员通")) {
                            String money;
                            // 新版支付宝,会显示积分情况下。先匹配标题上的金额
                            if (content.contains("商家积分")) {
                                money = getMoney(title);
                                if (money == null) {
                                    money = getMoney(content);
                                }
                            } else {
                                money = getMoney2(title);
                                if (money == null) {  // 继续使用匹配 xxx元的方式
                                    money = getMoney2(content);
                                }
                                if (money == null) {  // 使用数字匹配的方式
                                    money = getMoney(content);
                                }
                                if (money == null) {
                                    money = getMoney(title);
                                }
                            }
                            if (money != null) {
                                Log.d(TAG, "onAccessibilityEvent: 匹配成功: 支付宝 到账 " + money);
                                try{
                                    appPush(2, Double.parseDouble(money));
                                } catch (Exception e) {
                                    Log.d(TAG, "app push 错误!!!");
                                }
                            } else {
                                handler.post(new Runnable() {
                                    public void run() {
                                        Toast.makeText(getApplicationContext(), "监听到支付宝消息但未匹配到金额!", Toast.LENGTH_SHORT).show();
                                    }
                                });
                            }
                        }
                    }
                } else if ("com.tencent.mm".equals(pkg)
                        || "com.tencent.wework".equals(pkg)) {
                    if (!content.equals("")) {
                        // 微信 最新版 8.0.50 开始,对收款通知栏格式做了修改
                        if (title.equals("微信") || title.equals("微信支付") || title.equals("微信收款助手") || title.equals("微信收款商业版")
                                || content.contains("微信支付")
                                || content.contains("微信收款助手")
                                || content.contains("微信收款商业版")
                                || (title.equals("对外收款") || title.equals("企业微信")) &&
                                (content.contains("成功收款") || content.contains("收款通知"))) {
                            String money = getMoney2(content);
                            if (money == null) {  // 继续使用匹配 xxx元的方式
                                money = getMoney2(title);
                            }
                            if (money == null) {  // 使用旧版的匹配方式,可能识别错误,不够精准
                                money = getMoney(content);
                            }
                            if (money != null) {
                                Log.d(TAG, "onAccessibilityEvent: 匹配成功: 微信到账 " + money);
                                try {
                                    appPush(1, Double.parseDouble(money));
                                } catch (Exception e) {
                                    Log.d(TAG, "app push 错误!!!");
                                }
                            } else {
                                handler.post(new Runnable() {
                                    public void run() {
                                        Toast.makeText(getApplicationContext(), "监听到微信消息但未匹配到金额!", Toast.LENGTH_SHORT).show();
                                    }
                                });
                            }

                        }
                    }
                } else if ("com.vone.qrcode".equals(pkg)) {
                    if (content.equals("这是一条测试推送信息,如果程序正常,则会提示监听权限正常")) {
                        handler.post(new Runnable() {
                            public void run() {
                                Toast.makeText(getApplicationContext(), "监听正常,如无法正常回调请联系作者反馈!", Toast.LENGTH_SHORT).show();
                            }
                        });
                    }
                }
            }
        }
    }

    //当移除一条消息的时候回调,sbn是被移除的消息
    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {

    }

    //当连接成功时调用,一般在开启监听后会回调一次该方法
    @Override
    public void onListenerConnected() {
        isRunning = true;
        //开启心跳线程
        initAppHeart();

        handler.post(new Runnable() {
            public void run() {
                Toast.makeText(getApplicationContext(), "监听服务开启成功!", Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public void onListenerDisconnected() {
        super.onListenerDisconnected();
        isRunning = false;
        if (newThread != null) {
            newThread.interrupt();
        }
        newThread = null;
    }

    private void writeNotifyToFile(StatusBarNotification sbn) {
        if (!sbn.isClearable()) {
            return;
        }
        Log.i(TAG, "write notify message to file");
        //            具有写入权限,否则不写入
        CharSequence notificationTitle = null;
        CharSequence notificationText = null;
        CharSequence subText = null;

        Bundle extras = sbn.getNotification().extras;
        if (extras != null) {
            notificationTitle = extras.getCharSequence(Notification.EXTRA_TITLE);
            notificationText = extras.getCharSequence(Notification.EXTRA_TEXT);
            subText = extras.getCharSequence(Notification.EXTRA_SUB_TEXT);
        }
        String packageName = sbn.getPackageName();
        String time = Utils.formatTime(Calendar.getInstance().getTime());

        String writText = "\n" + "[" + time + "]" + "[" + packageName + "]" + "\n" +
                "[" + notificationTitle + "]" + "\n" + "[" + notificationText + "]" + "\n" +
                "[" + subText + "]" + "\n";

        // 使用 post 异步的写入
        Utils.putStr(this, writText);
    }

    /**
     * 通知服务器收款到账
     */
    public void appPush(int type, double price) {
        acquireWakeLock(this);
        SharedPreferences read = getSharedPreferences("vone", MODE_PRIVATE);
        host = read.getString("host", "");
        key = read.getString("key", "");

        Log.d(TAG, "onResponse  push: 开始:" + type + "  " + price);

        String t = String.valueOf(new Date().getTime());
        String sign = md5(type + "" + price + t + key);
        final String url = "http://" + host + "/appPush?t=" + t + "&type=" + type + "&price=" + price + "&sign=" + sign;
        Log.d(TAG, "onResponse  push: 开始:" + url);
        Request request = new Request.Builder().url(url).method("GET", null).build();
        Call call = Utils.getOkHttpClient().newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d(TAG, "onResponse  push: 请求失败");
                foregroundPost(url + "&force_push=true");
                releaseWakeLock();
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    Log.d(TAG, "onResponse  push: " + response.body().string());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 如果返回状态不是成功的。同样要回调
                if (!response.isSuccessful()) {
                    foregroundPost(url + "&force_push=true");
                }
                releaseWakeLock();
            }
        });
    }

    private void foregroundHeart(String url) {
        final Context context = NeNotificationService2.this;
        if (isRunning) {
            final JSONObject extraJson = new JSONObject();
            try {
                extraJson.put("url", url);
                extraJson.put("show", false);
            } catch (JSONException jsonException) {
                jsonException.printStackTrace();
            }
            handler.post(new Runnable() {
                @Override
                public void run() {
                    enterForeground(context,
                            context.getString(R.string.app_name),
                            context.getString(R.string.app_is_heart), extraJson.toString());
                }
            });
        }
    }

    /**
     * 当通知失败的时候,前台强制通知
     */
    private void foregroundPost(String url) {
        final Context context = NeNotificationService2.this;
        if (isRunning) {
            final JSONObject extraJson = new JSONObject();
            try {
                extraJson.put("url", url);
                extraJson.put("try_count", 5);
            } catch (JSONException jsonException) {
                jsonException.printStackTrace();
            }
            handler.post(new Runnable() {
                @Override
                public void run() {
                    enterForeground(context,
                            context.getString(R.string.app_name),
                            context.getString(R.string.app_is_post), extraJson.toString());
                }
            });
        }
    }

    /**
     * 如果出现无法通知的情况,进入前台,然后主动打开通知
     */
    public static void enterForeground(Context context, String title, String text, String extra) {
        if (context == null) return;
        Log.i(TAG, "enter fore ground");
        Intent intent = new Intent(context, ForegroundServer.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra(ForegroundServer.GET_NOTIFY_TITLE, title == null ? "" : title);
        intent.putExtra(ForegroundServer.GET_NOTIFY_TEXT, text == null ? "" : text);
        intent.putExtra(ForegroundServer.GET_NOTIFY_EXTRA, extra == null ? "" : extra);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(intent);
        } else {
            context.startService(intent);
        }
    }

    public static void exitForeground(Context context) {
        if (context == null) return;
        Log.i(TAG, "exitForeground");

        Intent intent1 = new Intent();
        intent1.setAction(Constant.FINISH_FOREGROUND_SERVICE);
        context.sendBroadcast(intent1);
    }

    /**
     * 匹配支付宝的收款 元
     * 为了兼容旧版,新版增加这个匹配
     */
    public static String getMoney2(String content) {
        Pattern compile = Pattern.compile("(\\d+\\.\\d+)元|(\\d+)元");
        Matcher matcher = compile.matcher(content);
        if (matcher.find()) {
            String price = matcher.group();
            return price.substring(0, price.lastIndexOf("元"));
        } else {
            return null;
        }
    }

    public static String getMoney(String content) {
        List<String> ss = new ArrayList<>();
        for (String sss : content.replaceAll(",", "")
                .replaceAll("[^0-9.]", ",").split(",")) {
            if (sss.length() > 0)
                ss.add(sss);
        }
        if (ss.size() < 1) {
            return null;
        } else {
            return ss.get(ss.size() - 1);
        }
    }

    public static String md5(String string) {
        if (TextUtils.isEmpty(string)) {
            return "";
        }
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
            byte[] bytes = md5.digest(string.getBytes());
            StringBuilder result = new StringBuilder();
            for (byte b : bytes) {
                String temp = Integer.toHexString(b & 0xff);
                if (temp.length() == 1) {
                    temp = "0" + temp;
                }
                result.append(temp);
            }
            return result.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

}


================================================
FILE: app/src/main/java/com/vone/vmq/StartReceive.java
================================================
package com.vone.vmq;

import static android.content.Context.POWER_SERVICE;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.util.Log;

import com.vone.qrcode.R;

/**
 * Created by user68 on 2018/7/30.
 * <p>
 * 接收另一个app的广播启动本地服务
 */

public class StartReceive extends BroadcastReceiver {
    public static final String START_SETTING_ACTIVITY_ACTION = "android.provider.Telephony.SECRET_CODE";
    public static final String TRY_CLOSE_ACTIVITY_ACTION = "try_close_activity_action";

    static boolean isBootCompleted = false; // 标志是否已经开机发送过通知

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("StartReceive", "start");
        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
            if (!checkBatteryWhiteList(context)) {
                isBootCompleted = true;
                Utils.sendBatteryNotify(context);
            }
            NeNotificationService2.enterForeground(context,
                    context.getString(R.string.app_name),
                    context.getString(R.string.app_is_start), "");
        }
        if (START_SETTING_ACTIVITY_ACTION.equals(intent.getAction())) {
            Log.d("StartReceive", "start");
            Intent startActivityIntent = new Intent(context, MainActivity.class);
            startActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(startActivityIntent);
        }
    }

    static boolean checkBatteryWhiteList(Context context) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
            if (powerManager == null) return true;
            return powerManager.isIgnoringBatteryOptimizations(context.getPackageName());
        }
        return true;
    }
}


================================================
FILE: app/src/main/java/com/vone/vmq/Utils.java
================================================
package com.vone.vmq;

import static android.content.Context.NOTIFICATION_SERVICE;
import static android.content.Context.POWER_SERVICE;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.PowerManager;
import android.provider.Settings;

import com.vone.qrcode.R;
import com.vone.vmq.util.FileUtils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;

class Utils {
    public final static String GET_MESSAGE_KEY = "get_message_key";
    public static final String GET_SHOW_ACTIVITY_TYPE = "get_show_activity_type";

    private final static String dayType = "yyyy-MM-dd HH:mm:ss";
    private final static String hourType = "HH:mm:ss";
    private static int notifyDay = -1;
    private static OkHttpClient okHttpClient;

    public static OkHttpClient getOkHttpClient() {
        if (okHttpClient == null) {
            synchronized (Utils.class) {
                if (okHttpClient == null) {
                    okHttpClient = new OkHttpClient.Builder()
                            .connectTimeout(10, TimeUnit.SECONDS)
                            .readTimeout(10, TimeUnit.SECONDS)
                            .writeTimeout(10, TimeUnit.SECONDS)
                            .connectionPool(new ConnectionPool(0, 5, TimeUnit.SECONDS))
                            .build();
                }
            }
        }
        return okHttpClient;
    }

    static void putStr(Context context, String value) {
        if (context == null) {
            return;
        }
        File notifycationFilePath = context.getExternalFilesDir("log");
        if (notifycationFilePath == null || !canWrite(notifycationFilePath)) return;

        String notifycationFileName = "notifycation_file.txt";
        File file = new File(notifycationFilePath, notifycationFileName);
        // 为了防止文件无限增大,只保留当天的数据
        if (Calendar.getInstance().get(Calendar.DAY_OF_MONTH) != notifyDay) {
            if (file.exists() && file.canWrite()) {
                // 设置最大容量 1M 大小
                if (file.length() > 1024 * 1024) {
                    FileUtils fileUtils = new FileUtils();
                    if (fileUtils.deleteFileSafely(file)) {
                        try {
                            //noinspection ResultOfMethodCallIgnored
                            file.createNewFile();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            notifyDay = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
        }

        BufferedWriter out = null;
        try {
            out = new BufferedWriter(new FileWriter(file, true), 1024);
            out.write(value);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static boolean canWrite(File notifycationFilePath) {
        return notifycationFilePath.canWrite();
    }


    static boolean checkBatteryWhiteList(Context context) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
            if (powerManager == null) return true;
            return powerManager.isIgnoringBatteryOptimizations(context.getPackageName());
        }
        return true;
    }

    static void gotoBatterySetting(Context context) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            @SuppressLint("BatteryLife")
            Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
            intent.setData(Uri.parse("package:" + context.getPackageName()));
            context.startActivity(intent);
        }
    }

    static String formatTime(Date time) {
        DateFormat dataFormat = new SimpleDateFormat(dayType, Locale.getDefault());
        return dataFormat.format(time);
    }

    static String formatTimeSimple(Date time) {
        DateFormat dataFormat = new SimpleDateFormat(hourType, Locale.getDefault());
        return dataFormat.format(time);
    }

    static void createNotificationChannel(Context context, String channelId, CharSequence channelName, int importance) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);

            channel.enableLights(true);
            channel.setShowBadge(true);
            channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
            NotificationManager notificationManager = (NotificationManager) context
                    .getSystemService(NOTIFICATION_SERVICE);

            if (notificationManager != null) {
                notificationManager.createNotificationChannel(channel);
            }
        }
    }

    static void sendNotifyMessage(Context context, String title, String text, int type) {
        if (type == 1) {
            String channelId = "MessageNotify";
            int channelLevel = -1;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                channelLevel = NotificationManager.IMPORTANCE_HIGH;
            }
            int id = (channelId + System.currentTimeMillis()).hashCode();
            String showTvText = String.format("%s\n%s", title, text);
            Intent intent = new Intent(context, MainActivity.class);
            intent.putExtra(GET_MESSAGE_KEY, showTvText);
            intent.putExtra(GET_SHOW_ACTIVITY_TYPE, type);

            sendNotify(context, channelId, "remote message notify",
                    channelLevel, Notification.PRIORITY_HIGH, id,
                    title, text, intent);
        }
    }

    static void sendBatteryNotify(Context context) {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            String channelId = "BatteryNotify";
            int channelLevel = -1;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                channelLevel = NotificationManager.IMPORTANCE_MAX;
            }
            @SuppressLint("BatteryLife")
            Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.setData(Uri.parse("package:" + context.getPackageName()));
            int id = (channelId + System.currentTimeMillis()).hashCode();
            sendNotify(context, channelId, "battery white list notify",
                    channelLevel, Notification.PRIORITY_MAX, id,
                    context.getString(R.string.app_name), context.getString(R.string.click_add_to_battery_white_list),
                    intent);
        }
    }

    private static void sendNotify(Context context, String channelId, String channelName,
                                   int channelLevel, int priority, int id,
                                   String title, String text, Intent intent) {
        NotificationManager manager = (NotificationManager) context.
                getSystemService(NOTIFICATION_SERVICE);
        if (manager == null) return;
        Notification.Builder notificationBuild;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            if (channelLevel < 0) {
                channelLevel = NotificationManager.IMPORTANCE_HIGH;
            }
            Utils.createNotificationChannel(context, channelId
                    , channelName
                    , channelLevel);
            notificationBuild = new Notification.Builder(context, channelId);
        } else {
            notificationBuild = new Notification.Builder(context);
        }
        notificationBuild.setContentTitle(title)
                .setContentText(text)
                .setStyle(new Notification.BigTextStyle()
                        .setBigContentTitle(title)
                        .bigText(text))
                .setWhen(System.currentTimeMillis())
                .setShowWhen(true)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setPriority(priority)
                .setAutoCancel(true);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, id
                , intent, PendingIntent.FLAG_CANCEL_CURRENT);
        notificationBuild.setContentIntent(pendingIntent);
        // 正式发出通知
        manager.notify(id, notificationBuild.build());
    }
}


================================================
FILE: app/src/main/java/com/vone/vmq/util/BitmapUtil.java
================================================
package com.vone.vmq.util;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;

/**
 * Bitmap util.
 * <p>从Uri直接读取图片流,避免路径转换的适配问题</p>
 */
public class BitmapUtil {
    /**
     * 读取一个缩放后的图片,限定图片大小,避免OOM
     *
     * @param uri       图片uri,支持“file://”、“content://”
     * @param maxWidth  最大允许宽度
     * @param maxHeight 最大允许高度
     * @return 返回一个缩放后的Bitmap,失败则返回null
     */
    public static Bitmap decodeUri(Context context, Uri uri, int maxWidth, int maxHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true; //只读取图片尺寸
        readBitmapScale(context, uri, options);

        //计算实际缩放比例
        int scale = 1;
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            if ((options.outWidth / scale > maxWidth &&
                    options.outWidth / scale > maxWidth * 1.4) ||
                    (options.outHeight / scale > maxHeight &&
                            options.outHeight / scale > maxHeight * 1.4)) {
                scale++;
            } else {
                break;
            }
        }

        options.inSampleSize = scale;
        options.inJustDecodeBounds = false;//读取图片内容
        options.inPreferredConfig = Bitmap.Config.RGB_565; //根据情况进行修改
        Bitmap bitmap = null;
        try {
            bitmap = readBitmapData(context, uri, options);
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    private static void readBitmapScale(Context context, Uri uri, BitmapFactory.Options options) {
        if (uri == null) {
            return;
        }
        String scheme = uri.getScheme();
        if (ContentResolver.SCHEME_CONTENT.equals(scheme) ||
                ContentResolver.SCHEME_FILE.equals(scheme)) {
            InputStream stream = null;
            try {
                stream = context.getContentResolver().openInputStream(uri);
                BitmapFactory.decodeStream(stream, null, options);
            } catch (Exception e) {
                Log.w("readBitmapScale", "Unable to open content: " + uri, e);
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        Log.e("readBitmapScale", "Unable to close content: " + uri, e);
                    }
                }
            }
        } else if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
            Log.e("readBitmapScale", "Unable to close content: " + uri);
        } else {
            Log.e("readBitmapScale", "Unable to close content: " + uri);
        }
    }

    private static Bitmap readBitmapData(Context context, Uri uri, BitmapFactory.Options options) {
        if (uri == null) {
            return null;
        }
        Bitmap bitmap = null;
        String scheme = uri.getScheme();
        if (ContentResolver.SCHEME_CONTENT.equals(scheme) ||
                ContentResolver.SCHEME_FILE.equals(scheme)) {
            InputStream stream = null;
            try {
                stream = context.getContentResolver().openInputStream(uri);
                bitmap = BitmapFactory.decodeStream(stream, null, options);
            } catch (Exception e) {
                Log.e("readBitmapData", "Unable to open content: " + uri, e);
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (IOException e) {
                        Log.e("readBitmapData", "Unable to close content: " + uri, e);
                    }
                }
            }
        } else if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
            Log.e("readBitmapData", "Unable to close content: " + uri);
        } else {
            Log.e("readBitmapData", "Unable to close content: " + uri);
        }
        return bitmap;
    }
}

================================================
FILE: app/src/main/java/com/vone/vmq/util/Constant.java
================================================
package com.vone.vmq.util;

/**
 * 常量
 */
public class Constant {
    // request参数
    public static final int REQ_QR_CODE = 11002; // // 打开扫描界面请求码
    public static final int REQ_PERM_CAMERA = 11003; // 打开摄像头
    public static final int REQ_PERM_EXTERNAL_STORAGE = 11004; // 读写文件

    public static final String INTENT_EXTRA_KEY_QR_SCAN = "qr_scan_result";
}


================================================
FILE: app/src/main/java/com/vone/vmq/util/FileUtils.java
================================================
package com.vone.vmq.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

@SuppressWarnings("ALL")
public class FileUtils {

    public String readFileToString(String filePath) {
        File file = new File(filePath);
        if (!file.exists())
            return null;
        BufferedReader in = null;
        try {
            in = new BufferedReader(new FileReader(file));
            StringBuilder readStringBuilder = new StringBuilder();
            String currentLine;
            while ((currentLine = in.readLine()) != null) {
                readStringBuilder.append(currentLine);
            }
            return readStringBuilder.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public boolean putStringToFile(String path, String text) {
        File file = new File(path);
        if (file.exists() && (!deleteFileSafely(file)))
            return false;
        BufferedWriter out = null;
        try {
            out = new BufferedWriter(new FileWriter(file), 2048);
            out.write(text);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            if (out != null) {
                try {
                    out.flush();
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * @param file 要删除的文件
     */
    public boolean deleteFileSafely(File file) {
        if (file != null && file.exists()) {
            File tmp = getTmpFile(file, System.currentTimeMillis(), -1);
            if (file.renameTo(tmp)) { // 将源文件重命名
                return tmp.delete(); // 删除重命名后的文件
            } else {
                return file.delete();
            }
        }
        return false;
    }

    private File getTmpFile(File file, long time, int index) {
        File tmp;
        if (index == -1) {
            tmp = new File(file.getParent() + File.separator + time);
        } else {
            tmp = new File(file.getParent() + File.separator + time + "(" + index + ")");
        }
        if (!tmp.exists()) {
            return tmp;
        } else {
            return getTmpFile(file, time, index >= 1000 ? index : ++index);
        }
    }
}


================================================
FILE: app/src/main/java/com/vone/vmq/util/UriUtil.java
================================================
package com.vone.vmq.util;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.DocumentsContract;
import android.provider.MediaStore;

/**
 * Uri路径工具
 *
 * @Deprecated 该方法存在终端适配问题,较为麻烦,已经弃用,新方法为BitmapUtil
 * @see BitmapUtil
 */
@Deprecated
public class UriUtil {
    /**
     * 根据图片的Uri获取图片的绝对路径(适配多种API)
     *
     * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
     */
    public static String getRealPathFromUri(Context context, Uri uri) {
        int sdkVersion = Build.VERSION.SDK_INT;
        if (sdkVersion < 11) return getRealPathFromUri_BelowApi11(context, uri);
        if (sdkVersion < 19) return getRealPathFromUri_Api11To18(context, uri);
        else return getRealPathFromUri_AboveApi19(context, uri);
    }

    /**
     * 适配api19以上,根据uri获取图片的绝对路径
     */
    @TargetApi(Build.VERSION_CODES.KITKAT)
    private static String getRealPathFromUri_AboveApi19(Context context, Uri uri) {
        String filePath = null;
        String wholeID = DocumentsContract.getDocumentId(uri);

        // 使用':'分割
        String[] ids = wholeID.split(":");
        String id = null;
        if (ids == null) {
            return null;
        }
        if (ids.length > 1) {
            id = ids[1];
        } else {
            id = ids[0];
        }

        String[] projection = {MediaStore.Images.Media.DATA};
        String selection = MediaStore.Images.Media._ID + "=?";
        String[] selectionArgs = {id};

        Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,//
                projection, selection, selectionArgs, null);
        int columnIndex = cursor.getColumnIndex(projection[0]);
        if (cursor.moveToFirst()) filePath = cursor.getString(columnIndex);
        cursor.close();
        return filePath;
    }

    /**
     * 适配api11-api18,根据uri获取图片的绝对路径
     */
    private static String getRealPathFromUri_Api11To18(Context context, Uri uri) {
        String filePath = null;
        String[] projection = {MediaStore.Images.Media.DATA};
        CursorLoader loader = new CursorLoader(context, uri, projection, null, null, null);
        Cursor cursor = loader.loadInBackground();

        if (cursor != null) {
            cursor.moveToFirst();
            filePath = cursor.getString(cursor.getColumnIndex(projection[0]));
            cursor.close();
        }
        return filePath;
    }

    /**
     * 适配api11以下(不包括api11),根据uri获取图片的绝对路径
     */
    private static String getRealPathFromUri_BelowApi11(Context context, Uri uri) {
        String filePath = null;
        String[] projection = {MediaStore.Images.Media.DATA};
        Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
        if (cursor != null) {
            cursor.moveToFirst();
            filePath = cursor.getString(cursor.getColumnIndex(projection[0]));
            cursor.close();
        }
        return filePath;
    }
}


================================================
FILE: app/src/main/res/layout/activity_lock_show.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000"
    android:keepScreenOn="true"
    tools:context="com.vone.vmq.LockShowActivity">

    <TextView
        android:id="@+id/showTv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:layout_marginStart="40dp"
        android:layout_marginTop="20dp"
        android:layout_marginEnd="40dp"
        android:layout_marginBottom="20dp"
        android:background="#00000000"
        android:gravity="center"
        android:text="@string/is_post_server_tip"
        android:textColor="#FFF"
        android:textSize="16sp" />

</RelativeLayout>

================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.vone.vmq.MainActivity"

    >

    <include layout="@layout/toolbar_main" />

    <TextView
        android:paddingTop="20dp"
        android:paddingBottom="10dp"

        android:id="@+id/txt_host"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"

        android:baselineAligned="false"
        android:text=" 通知地址:请扫码配置" />

    <TextView
        android:paddingBottom="20dp"
        android:id="@+id/txt_key"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text=" 通讯密钥:请扫码配置" />


    <Button
        android:id="@+id/btn_qrcode"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:onClick="startQrCode"
        android:text="扫码配置" />
    <Button
        android:id="@+id/btn_input"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:onClick="doInput"
        android:text="手动配置" />
    <Button
        android:id="@+id/btn_start"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:onClick="doStart"
        android:text="检测心跳" />
    <Button
        android:id="@+id/btn_checkpush"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:onClick="checkPush"
        android:text="检测监听" />

</LinearLayout>


================================================
FILE: app/src/main/res/layout/activity_scanner.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <include layout="@layout/toolbar_scanner" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <SurfaceView
            android:id="@+id/scanner_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center" />

        <com.google.zxing.view.ViewfinderView
            android:id="@+id/viewfinder_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:corner_color="@color/corner_color"
            app:frame_color="@color/viewfinder_frame"
            app:label_text="请扫描网站上的二维码"
            app:label_text_color="@color/colorAccent"
            app:laser_color="@color/laser_color"
            app:mask_color="@color/viewfinder_mask"
            app:result_color="@color/result_view"
            app:result_point_color="@color/result_point_color" />

        <ImageButton
            android:id="@+id/btn_flash"
            android:layout_width="40dip"
            android:layout_height="40dip"
            android:padding="6dip"
            android:layout_gravity="bottom|center_horizontal"
            android:layout_marginBottom="30dip"
            android:background="?attr/selectableItemBackground"
            android:scaleType="centerInside"
            android:src="@drawable/flash_off" />
    </FrameLayout>

</LinearLayout>

================================================
FILE: app/src/main/res/layout/toolbar_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:contentInsetStart="0dip">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical">

        <TextView
            android:id="@+id/txt_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="V免签"
            android:textColor="@android:color/white"
            android:textSize="18sp" />

    </RelativeLayout>
</android.support.v7.widget.Toolbar>


================================================
FILE: app/src/main/res/layout/toolbar_scanner.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorPrimary"
    app:contentInsetStart="0dip">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical">

        <ImageButton
            android:id="@+id/btn_back"
            android:layout_width="40dip"
            android:layout_height="40dip"
            android:layout_centerVertical="true"
            android:background="?attr/selectableItemBackground"
            android:padding="10dip"
            android:scaleType="centerCrop"
            android:src="@drawable/btn_back" />

        <TextView
            android:id="@+id/txt_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="扫描二维码"
            android:textColor="@android:color/white"
            android:textSize="18sp" />

        <Button
            android:id="@+id/btn_album"
            android:layout_width="40dip"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="10dip"
            android:background="?attr/selectableItemBackground"
            android:text="相册"
            android:textColor="@android:color/white" />
    </RelativeLayout>
</android.support.v7.widget.Toolbar>


================================================
FILE: app/src/main/res/menu/scanner_menu.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/scan_local"
        android:title="从相册选取二维码"/>
</menu>

================================================
FILE: app/src/main/res/values/attrs.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!--corner_color 边角颜色,
        scanner_color 扫描线颜色
        possible_result_color 扫描点颜色
        frame_color 扫描框边线颜色
        mask_color 模糊区域颜色
        label_text  框上方提示
    -->
    <declare-styleable name="ViewfinderView">
        <attr name="corner_color" format="color"/>
        <attr name="laser_color" format="color"/>
        <attr name="frame_color" format="color" />
        <attr name="mask_color" format="color" />
        <attr name="result_point_color" format="color"/>
        <attr name="result_color" format="color" />
        <attr name="label_text_color" format="color"/>
        <attr name="label_text" format="string"/>
        <attr name="label_text_size" format="float"/>
    </declare-styleable>

</resources>


================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <!-- QRCode scanner color begin -->
    <color name="viewfinder_mask">#60000000</color>
    <color name="result_view">#B0000000</color>
    <color name="viewfinder_frame">#90FFFFFF</color>
    <color name="result_point_color">#C0FFFF00</color>
    <color name="laser_color">#0F0</color>
    <color name="corner_color">#00FF00</color>
    <!-- QRCode scanner color end -->
</resources>


================================================
FILE: app/src/main/res/values/ids.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!--
 Copyright (C) 2008 ZXing authors

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 -->
<resources>
  <!-- Messages IDs -->
  <item type="id" name="auto_focus"/>
  <item type="id" name="decode"/>
  <item type="id" name="decode_failed"/>
  <item type="id" name="decode_succeeded"/>
  <item type="id" name="encode_failed"/>
  <item type="id" name="encode_succeeded"/>
  <item type="id" name="launch_product_query"/>
  <item type="id" name="quit"/>
  <item type="id" name="restart_preview"/>
  <item type="id" name="return_scan_result"/>
  <item type="id" name="search_book_contents_failed"/>
  <item type="id" name="search_book_contents_succeeded"/>
</resources>


================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">V免签监控端</string>

    <string name="click_add_to_battery_white_list">点击加入电池优化白名单</string>

    <string name="app_is_start">应用正在启动中,请稍后</string>
    <string name="app_is_heart">应用正在连接服务器</string>
    <string name="app_is_post">应用正在通知服务器发单</string>
    <string name="click_close_notify">点击关闭通知</string>
    <string name="is_post_server_tip">当前收到一笔转账信息, 正在通知到服务端</string>
</resources>


================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>


================================================
FILE: app/src/main/res/xml/network_security_config.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

================================================
FILE: app/src/main/res/xml/update_paths.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external_files_path"
        path="apk/" />
    <external-path name="beta_external_files_path" path="Android/data/"/>
</paths>

================================================
FILE: app/src/test/java/com/vone/qrcode/ExampleUnitTest.java
================================================
package com.vone.qrcode;

import org.junit.Test;

import static org.junit.Assert.*;

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        assertEquals(4, 2 + 2);
    }
}

================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
        google()

    }
    dependencies {
        // classpath 'com.android.tools.build:gradle:2.3.2'
        classpath 'com.android.tools.build:gradle:4.1.1'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        google()

    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}



================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true



================================================
FILE: gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
esac

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
    JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"



================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windowz variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
r
Download .txt
gitextract_efbl9myg/

├── .gitignore
├── LICENSE
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       ├── google/
│       │   │       │   └── zxing/
│       │   │       │       ├── activity/
│       │   │       │       │   └── CaptureActivity.java
│       │   │       │       ├── camera/
│       │   │       │       │   ├── AutoFocusCallback.java
│       │   │       │       │   ├── CameraConfigurationManager.java
│       │   │       │       │   ├── CameraManager.java
│       │   │       │       │   ├── FlashlightManager.java
│       │   │       │       │   ├── PlanarYUVLuminanceSource.java
│       │   │       │       │   └── PreviewCallback.java
│       │   │       │       ├── decoding/
│       │   │       │       │   ├── CaptureActivityHandler.java
│       │   │       │       │   ├── DecodeFormatManager.java
│       │   │       │       │   ├── DecodeHandler.java
│       │   │       │       │   ├── DecodeThread.java
│       │   │       │       │   ├── FinishListener.java
│       │   │       │       │   ├── InactivityTimer.java
│       │   │       │       │   ├── Intents.java
│       │   │       │       │   └── RGBLuminanceSource.java
│       │   │       │       ├── encoding/
│       │   │       │       │   └── EncodingHandler.java
│       │   │       │       └── view/
│       │   │       │           ├── ViewfinderResultPointCallback.java
│       │   │       │           └── ViewfinderView.java
│       │   │       └── vone/
│       │   │           └── vmq/
│       │   │               ├── App.java
│       │   │               ├── Constant.java
│       │   │               ├── ForegroundServer.java
│       │   │               ├── LockShowActivity.java
│       │   │               ├── MainActivity.java
│       │   │               ├── NeNotificationService2.java
│       │   │               ├── StartReceive.java
│       │   │               ├── Utils.java
│       │   │               └── util/
│       │   │                   ├── BitmapUtil.java
│       │   │                   ├── Constant.java
│       │   │                   ├── FileUtils.java
│       │   │                   └── UriUtil.java
│       │   └── res/
│       │       ├── layout/
│       │       │   ├── activity_lock_show.xml
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_scanner.xml
│       │       │   ├── toolbar_main.xml
│       │       │   └── toolbar_scanner.xml
│       │       ├── menu/
│       │       │   └── scanner_menu.xml
│       │       ├── raw/
│       │       │   └── beep.ogg
│       │       ├── values/
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── ids.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       └── xml/
│       │           ├── network_security_config.xml
│       │           └── update_paths.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── vone/
│                       └── qrcode/
│                           └── ExampleUnitTest.java
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
Download .txt
SYMBOL INDEX (236 symbols across 31 files)

FILE: app/src/main/java/com/google/zxing/activity/CaptureActivity.java
  class CaptureActivity (line 52) | public class CaptureActivity extends AppCompatActivity implements Callba...
    method onCreate (line 77) | @Override
    method onClick (line 105) | @Override
    method onActivityResult (line 115) | @Override
    method handleAlbumPic (line 131) | private void handleAlbumPic(Intent data) {
    method scanningImage (line 165) | public Result scanningImage(Uri uri) {
    method onResume (line 188) | @Override
    method onPause (line 220) | @Override
    method onDestroy (line 230) | @Override
    method handleDecode (line 242) | public void handleDecode(Result result, Bitmap barcode) {
    method initCamera (line 263) | private void initCamera(SurfaceHolder surfaceHolder) {
    method surfaceChanged (line 277) | @Override
    method surfaceCreated (line 283) | @Override
    method surfaceDestroyed (line 292) | @Override
    method getViewfinderView (line 298) | public ViewfinderView getViewfinderView() {
    method getHandler (line 302) | public Handler getHandler() {
    method drawViewfinder (line 306) | public void drawViewfinder() {
    method initBeepSound (line 311) | private void initBeepSound() {
    method playBeepSoundAndVibrate (line 337) | private void playBeepSoundAndVibrate() {
    method onCompletion (line 351) | public void onCompletion(MediaPlayer mediaPlayer) {
    method onClick (line 360) | @Override

FILE: app/src/main/java/com/google/zxing/camera/AutoFocusCallback.java
  class AutoFocusCallback (line 24) | final class AutoFocusCallback implements Camera.AutoFocusCallback {
    method setHandler (line 33) | void setHandler(Handler autoFocusHandler, int autoFocusMessage) {
    method onAutoFocus (line 38) | public void onAutoFocus(boolean success, Camera camera) {

FILE: app/src/main/java/com/google/zxing/camera/CameraConfigurationManager.java
  class CameraConfigurationManager (line 29) | final class CameraConfigurationManager {
    method CameraConfigurationManager (line 44) | CameraConfigurationManager(Context context) {
    method initFromCameraParameters (line 51) | void initFromCameraParameters(Camera camera) {
    method setDesiredCameraParameters (line 82) | void setDesiredCameraParameters(Camera camera) {
    method getCameraResolution (line 94) | Point getCameraResolution() {
    method getScreenResolution (line 98) | Point getScreenResolution() {
    method getPreviewFormat (line 102) | int getPreviewFormat() {
    method getPreviewFormatString (line 106) | String getPreviewFormatString() {
    method getCameraResolution (line 110) | private static Point getCameraResolution(Camera.Parameters parameters,...
    method findBestPreviewSizeValue (line 135) | private static Point findBestPreviewSizeValue(CharSequence previewSize...
    method findBestMotZoomValue (line 177) | private static int findBestMotZoomValue(CharSequence stringValues, int...
    method setFlash (line 195) | private void setFlash(Camera.Parameters parameters) {
    method setZoom (line 210) | private void setZoom(Camera.Parameters parameters) {
    method getDesiredSharpness (line 274) | public static int getDesiredSharpness() {

FILE: app/src/main/java/com/google/zxing/camera/CameraManager.java
  class CameraManager (line 36) | public final class CameraManager {
    method init (line 83) | public static void init(Context context) {
    method get (line 94) | public static CameraManager get() {
    method CameraManager (line 98) | private CameraManager(Context context) {
    method openDriver (line 120) | public void openDriver(SurfaceHolder holder) throws IOException {
    method closeDriver (line 147) | public void closeDriver() {
    method startPreview (line 158) | public void startPreview() {
    method stopPreview (line 168) | public void stopPreview() {
    method requestPreviewFrame (line 188) | public void requestPreviewFrame(Handler handler, int message) {
    method requestAutoFocus (line 205) | public void requestAutoFocus(Handler handler, int message) {
    method getFramingRect (line 220) | public Rect getFramingRect() {
    method getFramingRectInPreview (line 276) | public Rect getFramingRectInPreview() {
    method buildLuminanceSource (line 325) | public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int ...
    method getContext (line 348) | public Context getContext() {
    method setFlashLight (line 357) | public boolean setFlashLight(boolean isOpen) {

FILE: app/src/main/java/com/google/zxing/camera/FlashlightManager.java
  class FlashlightManager (line 37) | final class FlashlightManager {
    method FlashlightManager (line 53) | private FlashlightManager() {
    method enableFlashlight (line 60) | static void enableFlashlight() {
    method disableFlashlight (line 64) | static void disableFlashlight() {
    method getHardwareService (line 68) | private static Object getHardwareService() {
    method getSetFlashEnabledMethod (line 97) | private static Method getSetFlashEnabledMethod(Object iHardwareService) {
    method maybeForName (line 105) | private static Class<?> maybeForName(String name) {
    method maybeGetMethod (line 117) | private static Method maybeGetMethod(Class<?> clazz, String name, Clas...
    method invoke (line 129) | private static Object invoke(Method method, Object instance, Object......
    method setFlashlight (line 144) | private static void setFlashlight(boolean active) {

FILE: app/src/main/java/com/google/zxing/camera/PlanarYUVLuminanceSource.java
  class PlanarYUVLuminanceSource (line 33) | public final class PlanarYUVLuminanceSource extends LuminanceSource {
    method PlanarYUVLuminanceSource (line 40) | public PlanarYUVLuminanceSource(byte[] yuvData, int dataWidth, int dat...
    method getRow (line 55) | @Override
    method getMatrix (line 69) | @Override
    method isCropSupported (line 100) | @Override
    method getDataWidth (line 105) | public int getDataWidth() {
    method getDataHeight (line 109) | public int getDataHeight() {
    method renderCroppedGreyscaleBitmap (line 113) | public Bitmap renderCroppedGreyscaleBitmap() {

FILE: app/src/main/java/com/google/zxing/camera/PreviewCallback.java
  class PreviewCallback (line 25) | final class PreviewCallback implements Camera.PreviewCallback {
    method PreviewCallback (line 34) | PreviewCallback(CameraConfigurationManager configManager, boolean useO...
    method setHandler (line 39) | void setHandler(Handler previewHandler, int previewMessage) {
    method onPreviewFrame (line 44) | public void onPreviewFrame(byte[] data, Camera camera) {

FILE: app/src/main/java/com/google/zxing/decoding/CaptureActivityHandler.java
  class CaptureActivityHandler (line 41) | public final class CaptureActivityHandler extends Handler {
    type State (line 49) | private enum State {
    method CaptureActivityHandler (line 55) | public CaptureActivityHandler(CaptureActivity activity, Vector<Barcode...
    method handleMessage (line 67) | @Override
    method quitSynchronously (line 114) | public void quitSynchronously() {
    method restartPreviewAndDecode (line 130) | private void restartPreviewAndDecode() {

FILE: app/src/main/java/com/google/zxing/decoding/DecodeFormatManager.java
  class DecodeFormatManager (line 29) | final class DecodeFormatManager {
    method DecodeFormatManager (line 55) | private DecodeFormatManager() {}
    method parseDecodeFormats (line 57) | static Vector<BarcodeFormat> parseDecodeFormats(Intent intent) {
    method parseDecodeFormats (line 66) | static Vector<BarcodeFormat> parseDecodeFormats(Uri inputUri) {
    method parseDecodeFormats (line 74) | private static Vector<BarcodeFormat> parseDecodeFormats(Iterable<Strin...

FILE: app/src/main/java/com/google/zxing/decoding/DecodeHandler.java
  class DecodeHandler (line 39) | final class DecodeHandler extends Handler {
    method DecodeHandler (line 46) | DecodeHandler(CaptureActivity activity, Hashtable<DecodeHintType, Obje...
    method handleMessage (line 52) | @Override
    method decode (line 73) | private void decode(byte[] data, int width, int height) {

FILE: app/src/main/java/com/google/zxing/decoding/DecodeThread.java
  class DecodeThread (line 35) | final class DecodeThread extends Thread {
    method DecodeThread (line 43) | DecodeThread(CaptureActivity activity,
    method getHandler (line 69) | Handler getHandler() {
    method run (line 78) | @Override

FILE: app/src/main/java/com/google/zxing/decoding/FinishListener.java
  class FinishListener (line 26) | public final class FinishListener
    method FinishListener (line 31) | public FinishListener(Activity activityToFinish) {
    method onCancel (line 35) | public void onCancel(DialogInterface dialogInterface) {
    method onClick (line 39) | public void onClick(DialogInterface dialogInterface, int i) {
    method run (line 43) | public void run() {

FILE: app/src/main/java/com/google/zxing/decoding/InactivityTimer.java
  class InactivityTimer (line 30) | public final class InactivityTimer {
    method InactivityTimer (line 39) | public InactivityTimer(Activity activity) {
    method onActivity (line 44) | public void onActivity() {
    method cancel (line 51) | private void cancel() {
    method shutdown (line 58) | public void shutdown() {
    class DaemonThreadFactory (line 63) | private static final class DaemonThreadFactory implements ThreadFactory {
      method newThread (line 64) | public Thread newThread(Runnable runnable) {

FILE: app/src/main/java/com/google/zxing/decoding/Intents.java
  class Intents (line 23) | public final class Intents {
    method Intents (line 24) | private Intents() {
    class Scan (line 27) | public static final class Scan {
      method Scan (line 99) | private Scan() {
    class Encode (line 103) | public static final class Encode {
      method Encode (line 130) | private Encode() {
    class SearchBookContents (line 134) | public static final class SearchBookContents {
      method SearchBookContents (line 150) | private SearchBookContents() {
    class WifiConnect (line 154) | public static final class WifiConnect {
      method WifiConnect (line 175) | private WifiConnect() {
    class Share (line 180) | public static final class Share {
      method Share (line 187) | private Share() {

FILE: app/src/main/java/com/google/zxing/decoding/RGBLuminanceSource.java
  class RGBLuminanceSource (line 31) | public final class RGBLuminanceSource extends LuminanceSource {
    method RGBLuminanceSource (line 35) | public RGBLuminanceSource(String path) throws FileNotFoundException {
    method RGBLuminanceSource (line 39) | public RGBLuminanceSource(Bitmap bitmap) {
    method getRow (line 74) | @Override
    method getMatrix (line 91) | @Override
    method loadBitmap (line 96) | private static Bitmap loadBitmap(String path) throws FileNotFoundExcep...

FILE: app/src/main/java/com/google/zxing/encoding/EncodingHandler.java
  class EncodingHandler (line 22) | public final class EncodingHandler {
    method createQRCode (line 25) | public static Bitmap createQRCode(String str, int widthAndHeight) thro...
    method createQRCode (line 56) | public static Bitmap createQRCode(String content, int widthPix, int he...
    method addLogo (line 98) | private static Bitmap addLogo(Bitmap src, Bitmap logo) {

FILE: app/src/main/java/com/google/zxing/view/ViewfinderResultPointCallback.java
  class ViewfinderResultPointCallback (line 22) | public final class ViewfinderResultPointCallback implements ResultPointC...
    method ViewfinderResultPointCallback (line 25) | public ViewfinderResultPointCallback(ViewfinderView viewfinderView) {
    method foundPossibleResultPoint (line 29) | public void foundPossibleResultPoint(ResultPoint point) {

FILE: app/src/main/java/com/google/zxing/view/ViewfinderView.java
  class ViewfinderView (line 48) | public final class ViewfinderView extends View {
    method ViewfinderView (line 85) | public ViewfinderView(Context context, AttributeSet attrs) {
    method onDraw (line 109) | @Override
    method drawTextInfo (line 169) | private void drawTextInfo(Canvas canvas, Rect frame) {
    method drawCorner (line 178) | private void drawCorner(Canvas canvas, Rect frame) {
    method drawLaserScanner (line 195) | private void drawLaserScanner(Canvas canvas, Rect frame) {
    method shadeColor (line 241) | public int shadeColor(int color) {
    method drawFrame (line 248) | private void drawFrame(Canvas canvas, Rect frame) {
    method drawExterior (line 257) | private void drawExterior(Canvas canvas, Rect frame, int width, int he...
    method drawViewfinder (line 265) | public void drawViewfinder() {
    method drawResultBitmap (line 275) | public void drawResultBitmap(Bitmap barcode) {
    method addPossibleResultPoint (line 280) | public void addPossibleResultPoint(ResultPoint point) {

FILE: app/src/main/java/com/vone/vmq/App.java
  class App (line 9) | public class App extends Application {
    method getContext (line 14) | public static Context getContext() {
    method onCreate (line 18) | @Override
    method attachBaseContext (line 30) | @Override

FILE: app/src/main/java/com/vone/vmq/Constant.java
  class Constant (line 7) | @SuppressWarnings({"unused", "WeakerAccess"})

FILE: app/src/main/java/com/vone/vmq/ForegroundServer.java
  class ForegroundServer (line 32) | @SuppressWarnings("FieldCanBeLocal")
    method onCreate (line 51) | @Override
    method onStartCommand (line 61) | @Override
    method onDestroy (line 72) | @Override
    method startForegroundActivity (line 84) | private void startForegroundActivity(Intent intent) {
    method tryPushByUrl (line 107) | private void tryPushByUrl(final String url, final int count) {
    method setForegroundService (line 157) | @TargetApi(Build.VERSION_CODES.O)
    method updateNotify (line 166) | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    method getNotifycation (line 176) | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    method registerFinishBroad (line 208) | private void registerFinishBroad() {
    method unregisterFinishBroad (line 213) | private void unregisterFinishBroad() {
    method run (line 221) | @Override
    method onReceive (line 234) | @Override
    method startLockActivity (line 248) | private void startLockActivity(String msg) {
    method finishLockActivity (line 255) | private void finishLockActivity() {
    method updataMessageData (line 261) | private void updataMessageData(String msg) {
    method onBind (line 268) | @Override

FILE: app/src/main/java/com/vone/vmq/LockShowActivity.java
  class LockShowActivity (line 15) | public class LockShowActivity extends Activity {
    method onCreate (line 18) | @Override
    method registerBroadCast (line 30) | private void registerBroadCast() {
    method unregisterBroadCast (line 35) | private void unregisterBroadCast() {
    method InitView (line 39) | private void InitView() {
    method InitData (line 43) | private void InitData() {
    method resetData (line 53) | private void resetData(Intent intent) {
    method onNewIntent (line 59) | @Override
    method onDestroy (line 65) | @Override
    method onReceive (line 73) | @Override

FILE: app/src/main/java/com/vone/vmq/MainActivity.java
  class MainActivity (line 45) | public class MainActivity extends AppCompatActivity {
    method onCreate (line 58) | @Override
    method startQrCode (line 91) | public void startQrCode(View v) {
    method doInput (line 110) | public void doInput(View v) {
    method doStart (line 170) | public void doStart(View view) {
    method checkPush (line 210) | public void checkPush(View v) {
    method toggleNotificationListenerService (line 245) | private void toggleNotificationListenerService(Context context) {
    method isNotificationListenersEnabled (line 257) | public boolean isNotificationListenersEnabled() {
    method gotoNotificationAccessSetting (line 274) | protected boolean gotoNotificationAccessSetting() {
    method md5 (line 298) | public static String md5(String string) {
    method onActivityResult (line 321) | @Override
    method onRequestPermissionsResult (line 370) | @Override

FILE: app/src/main/java/com/vone/vmq/NeNotificationService2.java
  class NeNotificationService2 (line 40) | public class NeNotificationService2 extends NotificationListenerService {
    method acquireWakeLock (line 50) | @SuppressLint("InvalidWakeLockTag")
    method releaseWakeLock (line 70) | public void releaseWakeLock() {
    method initAppHeart (line 83) | public void initAppHeart() {
    method onNotificationPosted (line 135) | @Override
    method onNotificationRemoved (line 251) | @Override
    method onListenerConnected (line 257) | @Override
    method onListenerDisconnected (line 270) | @Override
    method writeNotifyToFile (line 280) | private void writeNotifyToFile(StatusBarNotification sbn) {
    method appPush (line 310) | public void appPush(int type, double price) {
    method foregroundHeart (line 348) | private void foregroundHeart(String url) {
    method foregroundPost (line 372) | private void foregroundPost(String url) {
    method enterForeground (line 396) | public static void enterForeground(Context context, String title, Stri...
    method exitForeground (line 411) | public static void exitForeground(Context context) {
    method getMoney2 (line 424) | public static String getMoney2(String content) {
    method getMoney (line 435) | public static String getMoney(String content) {
    method md5 (line 449) | public static String md5(String string) {

FILE: app/src/main/java/com/vone/vmq/StartReceive.java
  class StartReceive (line 19) | public class StartReceive extends BroadcastReceiver {
    method onReceive (line 25) | @Override
    method checkBatteryWhiteList (line 45) | static boolean checkBatteryWhiteList(Context context) {

FILE: app/src/main/java/com/vone/vmq/Utils.java
  class Utils (line 34) | class Utils {
    method getOkHttpClient (line 43) | public static OkHttpClient getOkHttpClient() {
    method putStr (line 59) | static void putStr(Context context, String value) {
    method canWrite (line 105) | private static boolean canWrite(File notifycationFilePath) {
    method checkBatteryWhiteList (line 110) | static boolean checkBatteryWhiteList(Context context) {
    method gotoBatterySetting (line 119) | static void gotoBatterySetting(Context context) {
    method formatTime (line 128) | static String formatTime(Date time) {
    method formatTimeSimple (line 133) | static String formatTimeSimple(Date time) {
    method createNotificationChannel (line 138) | static void createNotificationChannel(Context context, String channelI...
    method sendNotifyMessage (line 154) | static void sendNotifyMessage(Context context, String title, String te...
    method sendBatteryNotify (line 173) | static void sendBatteryNotify(Context context) {
    method sendNotify (line 192) | private static void sendNotify(Context context, String channelId, Stri...

FILE: app/src/main/java/com/vone/vmq/util/BitmapUtil.java
  class BitmapUtil (line 17) | public class BitmapUtil {
    method decodeUri (line 26) | public static Bitmap decodeUri(Context context, Uri uri, int maxWidth,...
    method readBitmapScale (line 56) | private static void readBitmapScale(Context context, Uri uri, BitmapFa...
    method readBitmapData (line 85) | private static Bitmap readBitmapData(Context context, Uri uri, BitmapF...

FILE: app/src/main/java/com/vone/vmq/util/Constant.java
  class Constant (line 6) | public class Constant {

FILE: app/src/main/java/com/vone/vmq/util/FileUtils.java
  class FileUtils (line 11) | @SuppressWarnings("ALL")
    method readFileToString (line 14) | public String readFileToString(String filePath) {
    method putStringToFile (line 41) | public boolean putStringToFile(String path, String text) {
    method deleteFileSafely (line 68) | public boolean deleteFileSafely(File file) {
    method getTmpFile (line 80) | private File getTmpFile(File file, long time, int index) {

FILE: app/src/main/java/com/vone/vmq/util/UriUtil.java
  class UriUtil (line 18) | @Deprecated
    method getRealPathFromUri (line 25) | public static String getRealPathFromUri(Context context, Uri uri) {
    method getRealPathFromUri_AboveApi19 (line 35) | @TargetApi(Build.VERSION_CODES.KITKAT)
    method getRealPathFromUri_Api11To18 (line 67) | private static String getRealPathFromUri_Api11To18(Context context, Ur...
    method getRealPathFromUri_BelowApi11 (line 84) | private static String getRealPathFromUri_BelowApi11(Context context, U...

FILE: app/src/test/java/com/vone/qrcode/ExampleUnitTest.java
  class ExampleUnitTest (line 12) | public class ExampleUnitTest {
    method addition_isCorrect (line 13) | @Test
Condensed preview — 59 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (212K chars).
[
  {
    "path": ".gitignore",
    "chars": 111,
    "preview": "*.iml\n.gradle\n/local.properties\n.idea\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n\n*.jks\n/app/authkey.jks\n\n"
  },
  {
    "path": "LICENSE",
    "chars": 1069,
    "preview": "MIT License\n\nCopyright (c) 2018 ahuyangdong\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "README.md",
    "chars": 3422,
    "preview": "\nV免签  —— 个人开发者收款解决方案\n===============\n\n## Android 15 新限制\n\n请注意,Android 15 新系统,对app权限进一步限制,需要打开usb调试模式,使用adb执行shell命令:\n\n```"
  },
  {
    "path": "app/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "chars": 1766,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 28\n    // buildToolsVersion \"26.0.0\"\n    defaul"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 911,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 3165,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "app/src/main/java/com/google/zxing/activity/CaptureActivity.java",
    "chars": 12145,
    "preview": "package com.google.zxing.activity;\n\nimport android.app.ProgressDialog;\nimport android.content.Intent;\nimport android.con"
  },
  {
    "path": "app/src/main/java/com/google/zxing/camera/AutoFocusCallback.java",
    "chars": 1569,
    "preview": "/*\n * Copyright (C) 2010 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/camera/CameraConfigurationManager.java",
    "chars": 9385,
    "preview": "/*\n * Copyright (C) 2010 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/camera/CameraManager.java",
    "chars": 14637,
    "preview": "/*\n * Copyright (C) 2008 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/camera/FlashlightManager.java",
    "chars": 4854,
    "preview": "/*\n * Copyright (C) 2010 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/camera/PlanarYUVLuminanceSource.java",
    "chars": 4074,
    "preview": "/*\n * Copyright 2009 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not "
  },
  {
    "path": "app/src/main/java/com/google/zxing/camera/PreviewCallback.java",
    "chars": 1972,
    "preview": "/*\n * Copyright (C) 2010 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/decoding/CaptureActivityHandler.java",
    "chars": 4784,
    "preview": "/*\n * Copyright (C) 2008 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/decoding/DecodeFormatManager.java",
    "chars": 3700,
    "preview": "/*\n * Copyright (C) 2010 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/decoding/DecodeHandler.java",
    "chars": 3782,
    "preview": "/*\n * Copyright (C) 2010 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/decoding/DecodeThread.java",
    "chars": 2544,
    "preview": "/*\n * Copyright (C) 2008 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/decoding/FinishListener.java",
    "chars": 1266,
    "preview": "/*\n * Copyright (C) 2010 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/decoding/InactivityTimer.java",
    "chars": 2096,
    "preview": "/*\n * Copyright (C) 2010 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/decoding/Intents.java",
    "chars": 6161,
    "preview": "/*\n * Copyright (C) 2008 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/decoding/RGBLuminanceSource.java",
    "chars": 2985,
    "preview": "/*\n * Copyright 2009 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not "
  },
  {
    "path": "app/src/main/java/com/google/zxing/encoding/EncodingHandler.java",
    "chars": 3806,
    "preview": "package com.google.zxing.encoding;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\n\nimport com.google.z"
  },
  {
    "path": "app/src/main/java/com/google/zxing/view/ViewfinderResultPointCallback.java",
    "chars": 1084,
    "preview": "/*\n * Copyright (C) 2009 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/google/zxing/view/ViewfinderView.java",
    "chars": 11044,
    "preview": "/*\n * Copyright (C) 2008 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may "
  },
  {
    "path": "app/src/main/java/com/vone/vmq/App.java",
    "chars": 946,
    "preview": "package com.vone.vmq;\n\nimport android.annotation.SuppressLint;\nimport android.app.Application;\nimport android.content.Co"
  },
  {
    "path": "app/src/main/java/com/vone/vmq/Constant.java",
    "chars": 476,
    "preview": "package com.vone.vmq;\n\n/**\n * Created by user68 on 2018/7/30.\n */\n\n@SuppressWarnings({\"unused\", \"WeakerAccess\"})\npublic "
  },
  {
    "path": "app/src/main/java/com/vone/vmq/ForegroundServer.java",
    "chars": 9844,
    "preview": "package com.vone.vmq;\n\nimport android.annotation.TargetApi;\nimport android.app.Notification;\nimport android.app.Notifica"
  },
  {
    "path": "app/src/main/java/com/vone/vmq/LockShowActivity.java",
    "chars": 2447,
    "preview": "package com.vone.vmq;\n\nimport android.app.Activity;\nimport android.content.BroadcastReceiver;\nimport android.content.Con"
  },
  {
    "path": "app/src/main/java/com/vone/vmq/MainActivity.java",
    "chars": 15385,
    "preview": "package com.vone.vmq;\n\nimport android.Manifest;\nimport android.app.AlertDialog;\nimport android.app.Notification;\nimport "
  },
  {
    "path": "app/src/main/java/com/vone/vmq/NeNotificationService2.java",
    "chars": 18309,
    "preview": "package com.vone.vmq;\n\nimport android.annotation.SuppressLint;\nimport android.app.Notification;\nimport android.content.C"
  },
  {
    "path": "app/src/main/java/com/vone/vmq/StartReceive.java",
    "chars": 1948,
    "preview": "package com.vone.vmq;\n\nimport static android.content.Context.POWER_SERVICE;\n\nimport android.content.BroadcastReceiver;\ni"
  },
  {
    "path": "app/src/main/java/com/vone/vmq/Utils.java",
    "chars": 9257,
    "preview": "package com.vone.vmq;\n\nimport static android.content.Context.NOTIFICATION_SERVICE;\nimport static android.content.Context"
  },
  {
    "path": "app/src/main/java/com/vone/vmq/util/BitmapUtil.java",
    "chars": 4135,
    "preview": "package com.vone.vmq.util;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.graph"
  },
  {
    "path": "app/src/main/java/com/vone/vmq/util/Constant.java",
    "chars": 360,
    "preview": "package com.vone.vmq.util;\n\n/**\n * 常量\n */\npublic class Constant {\n    // request参数\n    public static final int REQ_QR_CO"
  },
  {
    "path": "app/src/main/java/com/vone/vmq/util/FileUtils.java",
    "chars": 2698,
    "preview": "package com.vone.vmq.util;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.File;\n\nimport j"
  },
  {
    "path": "app/src/main/java/com/vone/vmq/util/UriUtil.java",
    "chars": 3074,
    "preview": "package com.vone.vmq.util;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.content."
  },
  {
    "path": "app/src/main/res/layout/activity_lock_show.xml",
    "chars": 917,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xm"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "chars": 1974,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "app/src/main/res/layout/activity_scanner.xml",
    "chars": 1744,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmln"
  },
  {
    "path": "app/src/main/res/layout/toolbar_main.xml",
    "chars": 926,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.Toolbar xmlns:android=\"http://schemas.android.com/apk/"
  },
  {
    "path": "app/src/main/res/layout/toolbar_scanner.xml",
    "chars": 1755,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<android.support.v7.widget.Toolbar xmlns:android=\"http://schemas.android.com/apk/"
  },
  {
    "path": "app/src/main/res/menu/scanner_menu.xml",
    "chars": 194,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n     "
  },
  {
    "path": "app/src/main/res/values/attrs.xml",
    "chars": 786,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n\n    <!--corner_color 边角颜色,\n        scanner_color 扫描线颜色\n        possi"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "chars": 585,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"color"
  },
  {
    "path": "app/src/main/res/values/ids.xml",
    "chars": 1191,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n Copyright (C) 2008 ZXing authors\n\n Licensed under the Apache License, Versi"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "chars": 421,
    "preview": "<resources>\n    <string name=\"app_name\">V免签监控端</string>\n\n    <string name=\"click_add_to_battery_white_list\">点击加入电池优化白名单<"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "chars": 381,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">"
  },
  {
    "path": "app/src/main/res/xml/network_security_config.xml",
    "chars": 144,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<network-security-config>\n    <base-config cleartextTrafficPermitted=\"true\" />\n</"
  },
  {
    "path": "app/src/main/res/xml/update_paths.xml",
    "chars": 206,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths>\n    <external-path\n        name=\"external_files_path\"\n        path=\"apk/\""
  },
  {
    "path": "app/src/test/java/com/vone/qrcode/ExampleUnitTest.java",
    "chars": 393,
    "preview": "package com.vone.qrcode;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, whi"
  },
  {
    "path": "build.gradle",
    "chars": 595,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    r"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 200,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "gradle.properties",
    "chars": 731,
    "preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
  },
  {
    "path": "gradlew",
    "chars": 4972,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2315,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "settings.gradle",
    "chars": 16,
    "preview": "include ':app'\n\n"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the zwc456baby/vmqApk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 59 files (187.2 KB), approximately 46.0k tokens, and a symbol index with 236 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!