Skip to content

Commit

Permalink
优化二维码扫码
Browse files Browse the repository at this point in the history
  • Loading branch information
goweii committed Mar 6, 2020
1 parent 2a32d9d commit 82daa74
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 166 deletions.
3 changes: 2 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,6 @@ dependencies {
implementation rootProject.ext.dependencies.crashActivity
implementation rootProject.ext.dependencies.heartView
implementation rootProject.ext.dependencies.tbs
implementation 'com.king.zxing:zxing-lite:1.1.6'
implementation 'com.github.goweii.BGAQRCode-Android:zxing:v1.3.8'

}
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
android:name="android.permission.READ_LOGS"
tools:ignore="ProtectedPermissions" />

<!-- 二维码扫码震动 -->
<uses-permission android:name="android.permission.VIBRATE" />

<application
android:name=".common.WanApp"
android:allowBackup="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,32 @@ import android.animation.Animator
import android.animation.ObjectAnimator
import android.content.Context
import android.content.Intent
import android.view.MotionEvent
import android.os.Vibrator
import android.view.View
import android.view.animation.DecelerateInterpolator
import com.google.zxing.BarcodeFormat
import com.king.zxing.CaptureHelper
import com.king.zxing.OnCaptureCallback
import cn.bingoogolapple.qrcode.core.QRCodeView
import cn.bingoogolapple.qrcode.zxing.QRCodeDecoder
import kotlinx.android.synthetic.main.activity_scan.*
import per.goweii.anypermission.RequestListener
import per.goweii.anypermission.RuntimeRequester
import per.goweii.basic.core.base.BaseActivity
import per.goweii.basic.core.permission.PermissionUtils
import per.goweii.basic.utils.LogUtils
import per.goweii.basic.utils.ext.gone
import per.goweii.basic.utils.ext.invisible
import per.goweii.basic.utils.ext.visible
import per.goweii.wanandroid.R
import per.goweii.wanandroid.module.main.presenter.ScanPresenter
import per.goweii.wanandroid.module.main.view.ScanView
import per.goweii.wanandroid.utils.PictureSelectorUtils
import per.goweii.wanandroid.utils.UrlOpenUtils


/**
* @author CuiZhen
* @date 2020/2/26
*/
class ScanActivity : BaseActivity<ScanPresenter>(), ScanView, OnCaptureCallback {
class ScanActivity : BaseActivity<ScanPresenter>(), ScanView, QRCodeView.Delegate {

companion object {
private const val REQ_CODE_CAMERA = 1
Expand All @@ -42,9 +43,9 @@ class ScanActivity : BaseActivity<ScanPresenter>(), ScanView, OnCaptureCallback
}
}

private lateinit var mCaptureHelper: CaptureHelper
private var mRuntimeRequester: RuntimeRequester? = null
private var hasPermission = false
private var shouldPause = false
private var tvTipAnim: Animator? = null

override fun swipeBackOnlyEdge(): Boolean = true
Expand All @@ -60,28 +61,24 @@ class ScanActivity : BaseActivity<ScanPresenter>(), ScanView, OnCaptureCallback
}
tvTip.visibility = View.INVISIBLE
ivTorch.visibility = View.INVISIBLE
mCaptureHelper = CaptureHelper(this, surfaceView, viewfinderView, ivTorch)
.setOnCaptureCallback(this)
.continuousScan(false)
.vibrate(true)
.playBeep(true)
.fullScreenScan(true)
.supportAutoZoom(false)
.supportZoom(true)
.decodeFormats(arrayListOf(BarcodeFormat.QR_CODE))
mCaptureHelper.onCreate()
qrCodeView.setDelegate(this)
qrCodeView.stopSpotAndHiddenRect()
}

private fun requestPermission() {
mRuntimeRequester = PermissionUtils.request(object : RequestListener {
override fun onSuccess() {
hasPermission = true
hideTvTip()
if (!shouldPause) {
qrCodeView.startCamera()
qrCodeView.startSpotAndShowRect()
}
}

override fun onFailed() {
hasPermission = false
showTvTip("为获取到相机权限\n点击重试", View.OnClickListener {
showTvTip("没有相机权限\n点击获取", View.OnClickListener {
hideTvTip()
requestPermission()
})
Expand All @@ -94,62 +91,60 @@ class ScanActivity : BaseActivity<ScanPresenter>(), ScanView, OnCaptureCallback

override fun onResume() {
super.onResume()
if (!shouldPause) {
mCaptureHelper.onResume()
if (hasPermission && !shouldPause) {
qrCodeView.startCamera()
qrCodeView.startSpotAndShowRect()
}
}

override fun onPause() {
super.onPause()
mCaptureHelper.onPause()
qrCodeView.stopSpotAndHiddenRect()
qrCodeView.stopCamera()
}

override fun onDestroy() {
super.onDestroy()
mCaptureHelper.onDestroy()
qrCodeView.onDestroy()
cancelTvTipAnim()
}

override fun onTouchEvent(event: MotionEvent): Boolean {
mCaptureHelper.onTouchEvent(event)
return super.onTouchEvent(event)
}

private var shouldPause = false

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQ_CODE_CAMERA -> {
mRuntimeRequester?.onActivityResult(requestCode)
}
REQ_CODE_SELECT_PIC -> {
shouldPause = true
PictureSelectorUtils.forResult(resultCode, data)?.let { path ->
val result: String? = presenter.parseCode(path)
LogUtils.d("ScanActivity", "result=$result")
if (result == null) {
shouldPause = true
mCaptureHelper.onPause()
showTvTip("未识别到二维码", View.OnClickListener {
presenter.getBitmapFromPath(path)?.let { bitmap ->
QRCodeDecoder.syncDecodeQRCode(bitmap)?.let { result ->
onScanQRCodeSuccess(result)
} ?: run {
showTvTip("没有识别到二维码\n点击继续", View.OnClickListener {
hideTvTip()
shouldPause = false
qrCodeView.startCamera()
qrCodeView.startSpotAndShowRect()
})
}
} ?: run {
showTvTip("打开图片失败\n点击继续", View.OnClickListener {
hideTvTip()
shouldPause = false
mCaptureHelper.onResume()
mCaptureHelper.surfaceCreated(surfaceView.holder)
qrCodeView.startCamera()
qrCodeView.startSpotAndShowRect()
})
} else {
UrlOpenUtils.with(result).open(context)
finish()
}
}
}
}
}

override fun onResultCallback(result: String?): Boolean {
LogUtils.d("ScanActivity", "result=$result")
UrlOpenUtils.with(result).open(context)
finish()
return true
private fun vibrate() {
val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
vibrator.vibrate(200)
}

private fun cancelTvTipAnim() {
Expand Down Expand Up @@ -215,4 +210,39 @@ class ScanActivity : BaseActivity<ScanPresenter>(), ScanView, OnCaptureCallback
start()
}
}

override fun onScanQRCodeSuccess(result: String?) {
LogUtils.d("ScanActivity", "result=$result")
qrCodeView.stopSpot()
qrCodeView.stopCamera()
vibrate()
UrlOpenUtils.with(result).open(context)
finish()
}

override fun onCameraAmbientBrightnessChanged(isDark: Boolean) {
if (isDark || ivTorch.isSelected) {
ivTorch.visible()
ivTorch.setOnClickListener {
ivTorch.isSelected = !ivTorch.isSelected
if (ivTorch.isSelected) {
qrCodeView.openFlashlight()
} else {
qrCodeView.closeFlashlight()
}
}
} else {
ivTorch.invisible()
ivTorch.isSelected = false
ivTorch.setOnClickListener(null)
qrCodeView.closeFlashlight()
}
}

override fun onScanQRCodeOpenCameraError() {
showTvTip("打开相机失败\n点击重试", View.OnClickListener {
hideTvTip()
requestPermission()
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.king.zxing.util.CodeUtils;

import cn.bingoogolapple.qrcode.zxing.QRCodeEncoder;
import per.goweii.anylayer.AnimatorHelper;
import per.goweii.anylayer.DialogLayer;
import per.goweii.anylayer.Layer;
Expand Down Expand Up @@ -97,7 +97,7 @@ public void onAttach() {
ImageView iv_qrcode = getView(R.id.dialog_qrcode_share_piv_qrcode);
TextView tv_title = getView(R.id.dialog_qrcode_share_tv_title);
Bitmap logo = BitmapFactory.decodeResource(getActivity().getResources(), R.drawable.ic_icon);
Bitmap qrcode = CodeUtils.createQRCode(mUrl, 300, logo);
Bitmap qrcode = QRCodeEncoder.syncEncodeQRCode(mUrl, 300, Color.BLACK, Color.WHITE, logo);
iv_qrcode.setImageBitmap(qrcode);
tv_title.setText(mTitle);
refreshJinrishici();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,98 +4,23 @@ import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import com.google.zxing.*
import com.google.zxing.common.GlobalHistogramBinarizer
import com.google.zxing.common.HybridBinarizer
import com.king.zxing.DecodeFormatManager
import per.goweii.basic.core.base.BasePresenter
import per.goweii.basic.utils.bitmap.BitmapUtils
import per.goweii.wanandroid.module.main.view.ScanView
import java.util.*
import kotlin.math.min

/**
* @author CuiZhen
* @date 2020/2/26
*/
class ScanPresenter : BasePresenter<ScanView>() {

fun parseCode(path: String): String? {
fun getBitmapFromPath(path: String): Bitmap? {
val uri = BitmapUtils.getImageContentUri(context, path)
uri ?: return null
val bm = getBitmapFromUri(context, uri)
bm ?: return null
val decodeFormats = Vector<BarcodeFormat>()
decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS)
decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS)
decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS)
decodeFormats.addAll(DecodeFormatManager.AZTEC_FORMATS)
decodeFormats.addAll(DecodeFormatManager.PDF417_FORMATS)
val hints: MutableMap<DecodeHintType, Any> = mutableMapOf()
hints[DecodeHintType.TRY_HARDER] = true
hints[DecodeHintType.POSSIBLE_FORMATS] = decodeFormats
var result: Result? = null
try {
val reader = MultiFormatReader()
reader.setHints(hints)
val source = getRGBLuminanceSource(bm)
source ?: return null
var isReDecode: kotlin.Boolean
try {
val bitmap = BinaryBitmap(HybridBinarizer(source))
result = reader.decodeWithState(bitmap)
isReDecode = false
} catch (e: Exception) {
isReDecode = true
}
if (isReDecode) {
try {
val bitmap = BinaryBitmap(HybridBinarizer(source.invert()))
result = reader.decodeWithState(bitmap)
isReDecode = false
} catch (e: Exception) {
isReDecode = true
}
}
if (isReDecode) {
try {
val bitmap = BinaryBitmap(GlobalHistogramBinarizer(source))
result = reader.decodeWithState(bitmap)
isReDecode = false
} catch (e: Exception) {
isReDecode = true
}
}
if (isReDecode && source.isRotateSupported) {
try {
val bitmap = BinaryBitmap(HybridBinarizer(source.rotateCounterClockwise()))
result = reader.decodeWithState(bitmap)
} catch (e: Exception) {
}
}
reader.reset()
} catch (e: Exception) {
e.printStackTrace()
} finally {
if (!bm.isRecycled) {
bm.recycle()
}
}
result ?: return null
return result.text
}


/**
* 获取RGBLuminanceSource
* @param bitmap
* @return
*/
private fun getRGBLuminanceSource(bitmap: Bitmap): RGBLuminanceSource? {
val width = bitmap.width
val height = bitmap.height
val pixels = IntArray(width * height)
bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
return RGBLuminanceSource(width, height, pixels)
return bm
}

private fun getBitmapFromUri(context: Context, uri: Uri): Bitmap? {
Expand All @@ -106,17 +31,11 @@ class ScanPresenter : BasePresenter<ScanView>() {
val newOpts = BitmapFactory.Options()
newOpts.inJustDecodeBounds = true
BitmapFactory.decodeFileDescriptor(fileDescriptor, null, newOpts)// 此时返回bm为空
val w = newOpts.outWidth
val h = newOpts.outHeight
val width = 800f
val height = 480f
var be = 1
if (w > h && w > width) {
be = (newOpts.outWidth / width).toInt()
} else if (w < h && h > height) {
be = (newOpts.outHeight / height).toInt()
}
if (be <= 0) be = 1
val w = newOpts.outWidth.toFloat()
val h = newOpts.outHeight.toFloat()
val s = 720f
var be = (min(w, h) / s).toInt()
if (be < 1) be = 1
newOpts.inSampleSize = be
newOpts.inJustDecodeBounds = false
val image = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, newOpts)
Expand Down
Loading

0 comments on commit 82daa74

Please sign in to comment.