From 8a1630f2a41bdac059ac19ae956ae1f6e5768c21 Mon Sep 17 00:00:00 2001 From: mazengfei <331023091@qq.com> Date: Tue, 10 Mar 2026 14:44:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=89=AB=E7=A0=81=E6=9E=AA?= =?UTF-8?q?=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sw/dualscreen/activity/BaseActivity.kt | 11 +- .../sw/dualscreen/activity/MainActivity.kt | 1 - .../com/sw/dualscreen/activity/PayActivity.kt | 31 +- .../sw/dualscreen/network/api/ApiService.kt | 6 +- .../dualscreen/repository/RemoteRepository.kt | 8 +- .../sw/dualscreen/viewmodel/UserViewModel.kt | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- .../sw/plate/utils/ScanGunKeyEventHelper.java | 284 +++++++++--------- 8 files changed, 193 insertions(+), 154 deletions(-) diff --git a/app/src/main/java/com/sw/dualscreen/activity/BaseActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/BaseActivity.kt index 4ec7296..89f6778 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/BaseActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/BaseActivity.kt @@ -59,7 +59,7 @@ abstract class BaseActivity : AppCompatActivity() { } override fun onDestroy() { - keyEventHelper?.onDestroy() + keyEventHelper?.release() EventBus.getDefault().unregister(this) super.onDestroy() } @@ -153,7 +153,7 @@ abstract class BaseActivity : AppCompatActivity() { */ fun registerKeyEvent() { keyEventHelper = - ScanGunKeyEventHelper(context, object : ScanGunKeyEventHelper.OnScanSuccessListener { + ScanGunKeyEventHelper( object : ScanGunKeyEventHelper.OnScanSuccessListener { override fun onScanSuccess(barcode: String?) { Timber.d("onScanSuccess barcode = $barcode") if (barcode == null) return @@ -166,10 +166,13 @@ abstract class BaseActivity : AppCompatActivity() { /** * 处理扫描枪数据 */ - open fun scanGunKeyEventCallback(scanInfo: String) { - Timber.tag("TAG").d("handleScanKeyInfo: $scanInfo") + fun scanGunKeyEventCallback(scanInfo: String){ + if (this is PayActivity) { + qrCodePay(scanInfo) + } } + override fun dispatchKeyEvent(event: KeyEvent): Boolean { if (keyEventHelper != null) { if (keyEventHelper!!.isScanGunEvent(event)) { diff --git a/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt index ce8785c..522e9f6 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/MainActivity.kt @@ -158,7 +158,6 @@ class MainActivity : BaseActivity() { } setupCamera() initData() - registerKeyEvent() } private fun initData() { diff --git a/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt b/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt index 91f076b..154b366 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt @@ -1,5 +1,7 @@ package com.sw.dualscreen.activity +import android.view.KeyEvent +import androidx.activity.OnBackPressedCallback import androidx.activity.viewModels import androidx.fragment.app.Fragment import com.sw.dualscreen.GlobalKey @@ -15,6 +17,7 @@ import com.sw.dualscreen.model.response.FoodInfo import com.sw.dualscreen.model.response.MemberInfo import com.sw.dualscreen.model.response.PaySuccessEvent import com.sw.dualscreen.presentation.pay.PayPresentation +import com.sw.dualscreen.utils.Debouncer import com.sw.dualscreen.utils.SPUtil import com.sw.dualscreen.utils.SoundPoolUtil import com.sw.dualscreen.viewmodel.BaseViewModel @@ -81,7 +84,8 @@ class PayActivity : BaseActivity() { override fun initialize() { super.initialize() presentation.show() - + registerKeyEvent() + addBackEventListener() val soundMap = hashMapOf() soundMap[PAY_SUCCESS] = R.raw.pay_success SoundPoolUtil.getInstance().loadR(this, soundMap) @@ -196,11 +200,15 @@ class PayActivity : BaseActivity() { presentation?.loadQrCodeImage(qrCodeUrl) } + private var debouncer = Debouncer(5000) + fun showPaySuccess(isVip: Boolean) { - playSoundOnPaySuccess() - EventBus.getDefault().post(PaySuccessEvent()) - showPayInfo(type = 2, isVip = isVip, memberInfo = memberInfo) - hidePayTab() + debouncer.debounce { + playSoundOnPaySuccess() + EventBus.getDefault().post(PaySuccessEvent()) + showPayInfo(type = 2, isVip = isVip, memberInfo = memberInfo) + hidePayTab() + } } fun getQrCodeImg( @@ -286,10 +294,11 @@ class PayActivity : BaseActivity() { } } - override fun scanGunKeyEventCallback(scanInfo: String) { - super.scanGunKeyEventCallback(scanInfo) + fun qrCodePay(scanInfo: String) { + showWaitingDialog("支付中……") userViewModel.qrCodePay(scanInfo, foodOrderId) { payState, backData -> Timber.d("qrCodePay支付返回数据:state=$payState,backData=$backData") + hideWaitingDialog() if (payState) { showPaySuccess(false) } @@ -340,4 +349,12 @@ class PayActivity : BaseActivity() { // } // } // } + + fun addBackEventListener() { + onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + + } + }) + } } \ No newline at end of file diff --git a/app/src/main/java/com/sw/dualscreen/network/api/ApiService.kt b/app/src/main/java/com/sw/dualscreen/network/api/ApiService.kt index 3962d50..d561ad0 100644 --- a/app/src/main/java/com/sw/dualscreen/network/api/ApiService.kt +++ b/app/src/main/java/com/sw/dualscreen/network/api/ApiService.kt @@ -220,12 +220,10 @@ interface ApiService { * 二维码支付 * @param orderType 0付款 1会员充值 */ - @GET + @POST suspend fun qrCodePay( @Url url: String = "${GlobalData.appBaseUrl}/terminal/neglect/pay/app/qrCodePay", - @Query("authCode") authCode: String, - @Query("outTradeNo") orderNo: String, - @Query("orderType") orderType:Int + @Body param: HashMap ): ApiResponse /** diff --git a/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt b/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt index 94dd563..6545d35 100644 --- a/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt +++ b/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt @@ -191,7 +191,13 @@ class RemoteRepository constructor( */ suspend fun qrCodePay(authCode: String,orderNo: String): ApiResponse { return safeApiCall { - apiService.qrCodePay(authCode = authCode, orderNo=orderNo, orderType = 0) + apiService.qrCodePay( + param = hashMapOf( + "authCode" to authCode, + "outTradeNo" to orderNo, + "orderType" to "0" + ) + ) } } diff --git a/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt b/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt index a7fbdaa..5c3b68f 100644 --- a/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt +++ b/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt @@ -104,7 +104,7 @@ class UserViewModel : BaseViewModel() { withContext(Dispatchers.Default) { val list: List = response.data ?: emptyList() if (pageNo == 1 && list.isEmpty()) { - ToastUtils.showToast("查询人脸数据为空") + //ToastUtils.showToast("查询人脸数据为空") return@withContext } //val item = list.map { it.member } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bea98ca..c996dd3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,8 +1,8 @@ #Mon Jul 14 11:28:37 CST 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.11.1-all.zip #distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip -#distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.11.1-all.zip -distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.14.3-all.zip +#distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.14.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/lib_face/src/main/java/com/sw/plate/utils/ScanGunKeyEventHelper.java b/lib_face/src/main/java/com/sw/plate/utils/ScanGunKeyEventHelper.java index b85214a..81072f0 100644 --- a/lib_face/src/main/java/com/sw/plate/utils/ScanGunKeyEventHelper.java +++ b/lib_face/src/main/java/com/sw/plate/utils/ScanGunKeyEventHelper.java @@ -5,7 +5,10 @@ import static android.content.Context.INPUT_SERVICE; import android.content.Context; import android.hardware.input.InputManager; import android.os.Handler; +import android.os.Looper; import android.text.TextUtils; +import android.view.InputDevice; +import android.view.KeyCharacterMap; import android.view.KeyEvent; import java.util.Arrays; @@ -14,172 +17,185 @@ import java.util.List; /** * 扫描枪事件处理 */ + public class ScanGunKeyEventHelper { - private final static long MESSAGE_DELAY = 500; //延迟500ms,判断扫码是否完成。 - private final StringBuffer mStringBufferResult; //扫码内容 - private boolean mCaps; //大小写区分 - private final Handler mHandler; - private final Runnable mScanningFishedRunnable; - private OnScanSuccessListener mOnScanSuccessListener; - private final Context mContext; - // private String mDeviceName = "TMC HIDKeyBoard"; - //private String mDeviceName = "Linux 3.4.35 with ak-hsudc Composite Gadget (ACM + HID)"; - //private String mDeviceName1 = "USBKey Chip USBKey Module"; + private static final long SCAN_DELAY = 200; // 扫码结束判断时间 - private String[] deviceNameArray = new String[]{ - "CROWN CROWN Barcode KeyBorad FS", - "Linux 3.4.35 with ak-hsudc Composite Gadget (ACM + HID)", - "USBKey Chip USBKey Module" - }; - private long lastTime = 0L; + private final StringBuilder resultBuffer = new StringBuilder(); + private boolean caps; - public ScanGunKeyEventHelper(Context context, OnScanSuccessListener onScanSuccessListener) { - mContext = context; - mOnScanSuccessListener = onScanSuccessListener; - mStringBufferResult = new StringBuffer(); - mHandler = new Handler(); - mScanningFishedRunnable = this::performScanSuccess; + private final Handler handler = new Handler(Looper.getMainLooper()); + private final Runnable scanFinishRunnable; + + private OnScanSuccessListener listener; + + private long lastScanTime = 0; + + public ScanGunKeyEventHelper(OnScanSuccessListener listener) { + this.listener = listener; + scanFinishRunnable = this::handleScanFinish; } /** - * 返回扫码成功后的结果 + * 扫码结束 */ - private void performScanSuccess() { - String barcode = mStringBufferResult.toString(); - L.d("performScanSuccess barcode = " + barcode); - long currentTime = System.currentTimeMillis(); - if (currentTime - lastTime < 5 * 1000) { - L.d("performScanSuccess 操作太频繁"); - mStringBufferResult.setLength(0); + private void handleScanFinish() { + + String barcode = resultBuffer.toString(); + + if (barcode.isEmpty()) { return; } - lastTime = currentTime; - if (mOnScanSuccessListener != null && !TextUtils.isEmpty(barcode)) - mOnScanSuccessListener.onScanSuccess(barcode); - mStringBufferResult.setLength(0); + + long now = System.currentTimeMillis(); + + // 防止重复扫描 + if (now - lastScanTime < 1000) { + resultBuffer.setLength(0); + return; + } + + lastScanTime = now; + + if (listener != null) { + listener.onScanSuccess(barcode); + } + + resultBuffer.setLength(0); } /** - * 扫码枪事件解析 - * - * @param event + * 解析 KeyEvent */ public void analysisKeyEvent(KeyEvent event) { - int keyCode = event.getKeyCode(); - //字母大小写判断 - checkLetterStatus(event); - if (event.getAction() == KeyEvent.ACTION_DOWN) { - char aChar = getInputCode(event); - if (aChar != 0) { - mStringBufferResult.append(aChar); - } - if (keyCode == KeyEvent.KEYCODE_ENTER) { - //若为回车键,直接返回 - mHandler.removeCallbacks(mScanningFishedRunnable); - mHandler.post(mScanningFishedRunnable); - } else { - //延迟post,若500ms内,有其他事件 - mHandler.removeCallbacks(mScanningFishedRunnable); - mHandler.postDelayed(mScanningFishedRunnable, MESSAGE_DELAY); - } + if (event.getAction() != KeyEvent.ACTION_DOWN) { + return; } + + checkCaps(event); + + int keyCode = event.getKeyCode(); + + if (keyCode == KeyEvent.KEYCODE_ENTER) { + + handler.removeCallbacks(scanFinishRunnable); + handler.post(scanFinishRunnable); + + return; + } + + char c = getInputCode(event); + + if (c != 0) { + resultBuffer.append(c); + } + + handler.removeCallbacks(scanFinishRunnable); + handler.postDelayed(scanFinishRunnable, SCAN_DELAY); } - //检查shift键 - private void checkLetterStatus(KeyEvent event) { + /** + * 判断是否为扫码枪 + */ + public boolean isScanGunEvent(KeyEvent event) { + + if (event == null) return false; + + InputDevice device = event.getDevice(); + + if (device == null) return false; + + int sources = device.getSources(); + + // HID keyboard + boolean isKeyboard = + (sources & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD; + + // 排除虚拟键盘 + boolean notVirtual = + event.getDeviceId() != KeyCharacterMap.VIRTUAL_KEYBOARD; + + return isKeyboard && notVirtual; + } + + /** + * SHIFT 状态 + */ + private void checkCaps(KeyEvent event) { + int keyCode = event.getKeyCode(); - if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT || keyCode == KeyEvent.KEYCODE_SHIFT_LEFT) { - if (event.getAction() == KeyEvent.ACTION_DOWN) { - //按着shift键,表示大写 - mCaps = true; - } else { - //松开shift键,表示小写 - mCaps = false; - } + + if (keyCode == KeyEvent.KEYCODE_SHIFT_LEFT + || keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT) { + + caps = event.getAction() == KeyEvent.ACTION_DOWN; } } /** - * 获取扫描内容 - * - * @param event - * @return + * KeyEvent 转字符 */ private char getInputCode(KeyEvent event) { + int keyCode = event.getKeyCode(); - char aChar; + if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) { - //字母 - aChar = (char) ((mCaps ? 'A' : 'a') + keyCode - KeyEvent.KEYCODE_A); + + return (char) ((caps ? 'A' : 'a') + keyCode - KeyEvent.KEYCODE_A); + } else if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) { - //数字 - aChar = (char) ('0' + keyCode - KeyEvent.KEYCODE_0); - } else { - //其他符号 - switch (keyCode) { - case KeyEvent.KEYCODE_PERIOD: - aChar = '.'; - break; - case KeyEvent.KEYCODE_MINUS: - aChar = mCaps ? '_' : '-'; - break; - case KeyEvent.KEYCODE_SLASH: - aChar = '/'; - break; - case KeyEvent.KEYCODE_BACKSLASH: - aChar = mCaps ? '|' : '\\'; - break; - default: - aChar = 0; - break; - } + + return (char) ('0' + keyCode - KeyEvent.KEYCODE_0); } - return aChar; + + switch (keyCode) { + + case KeyEvent.KEYCODE_MINUS: + return caps ? '_' : '-'; + + case KeyEvent.KEYCODE_EQUALS: + return caps ? '+' : '='; + + case KeyEvent.KEYCODE_LEFT_BRACKET: + return caps ? '{' : '['; + + case KeyEvent.KEYCODE_RIGHT_BRACKET: + return caps ? '}' : ']'; + + case KeyEvent.KEYCODE_BACKSLASH: + return caps ? '|' : '\\'; + + case KeyEvent.KEYCODE_SEMICOLON: + return caps ? ':' : ';'; + + case KeyEvent.KEYCODE_APOSTROPHE: + return caps ? '"' : '\''; + + case KeyEvent.KEYCODE_COMMA: + return caps ? '<' : ','; + + case KeyEvent.KEYCODE_PERIOD: + return caps ? '>' : '.'; + + case KeyEvent.KEYCODE_SLASH: + return caps ? '?' : '/'; + + case KeyEvent.KEYCODE_SPACE: + return ' '; + + default: + return 0; + } + } + + public void release() { + handler.removeCallbacks(scanFinishRunnable); + listener = null; } public interface OnScanSuccessListener { void onScanSuccess(String barcode); } - - public void onDestroy() { - mHandler.removeCallbacks(mScanningFishedRunnable); - mOnScanSuccessListener = null; - } - - /** - * 输入设备是否存在 - * - * @param deviceName - * @return - */ - public boolean isInputDeviceExist(String deviceName) { - - InputManager inputManager = (InputManager) mContext.getSystemService(INPUT_SERVICE); - int[] deviceIds = inputManager.getInputDeviceIds(); - for (int id : deviceIds) { - if (inputManager.getInputDevice(id).getName().equals(deviceName)) { - return true; - } - } - return false; - } - - /** - * 是否为扫码枪事件(部分机型KeyEvent获取的名字错误) - * - * @param event - * @return - */ - public boolean isScanGunEvent(KeyEvent event) { - if (event == null || event.getDevice() == null) return false; - String deviceName = event.getDevice().getName(); - L.e("event===" + deviceName + - "===Char===" + event.getCharacters() + - "===Action===" + event.getAction()); - //return deviceName.equals(mDeviceName) || deviceName.equals(mDeviceName1); - List devices = Arrays.asList(deviceNameArray); - return devices.contains(deviceName); - } -} +} \ No newline at end of file