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 670e16a..4ec7296 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/BaseActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/BaseActivity.kt @@ -157,7 +157,7 @@ abstract class BaseActivity : AppCompatActivity() { override fun onScanSuccess(barcode: String?) { Timber.d("onScanSuccess barcode = $barcode") if (barcode == null) return - handleScanKeyInfo(barcode) + scanGunKeyEventCallback(barcode) } }) } @@ -166,12 +166,8 @@ abstract class BaseActivity : AppCompatActivity() { /** * 处理扫描枪数据 */ - protected open fun handleScanKeyInfo(scanInfo: String) { - var payCode = scanInfo - //if (scanInfo.length > 6) { - // payCode = scanInfo.take(6) - //} - Log.d("TAG", "handleScanKeyInfo: " + payCode) + open fun scanGunKeyEventCallback(scanInfo: String) { + Timber.tag("TAG").d("handleScanKeyInfo: $scanInfo") } override fun dispatchKeyEvent(event: KeyEvent): Boolean { 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 30100f0..91f076b 100644 --- a/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt +++ b/app/src/main/java/com/sw/dualscreen/activity/PayActivity.kt @@ -16,10 +16,12 @@ 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.SPUtil +import com.sw.dualscreen.utils.SoundPoolUtil import com.sw.dualscreen.viewmodel.BaseViewModel import com.sw.dualscreen.viewmodel.UserViewModel import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel import org.greenrobot.eventbus.EventBus +import timber.log.Timber class PayActivity : BaseActivity() { @@ -36,6 +38,7 @@ class PayActivity : BaseActivity() { const val TAG_PAY_NUMBER = "tagPayNumber" const val TAG_PAY_FACE = "tagPayFace" const val TAG_PAY_RESULT = "tagPayResult" + const val PAY_SUCCESS = "pay_success" } val userViewModel by viewModels() @@ -70,10 +73,19 @@ class PayActivity : BaseActivity() { ) } + fun playSoundOnPaySuccess() { + SoundPoolUtil.getInstance().play(PAY_SUCCESS, 0) + } + @Suppress("DEPRECATION") override fun initialize() { super.initialize() presentation.show() + + val soundMap = hashMapOf() + soundMap[PAY_SUCCESS] = R.raw.pay_success + SoundPoolUtil.getInstance().loadR(this, soundMap) + foodInfo = intent.getParcelableExtra(FOOD_INFO) foodOrderId = intent.getStringExtra(FOOD_ORDER_ID) ?: "" eatNum = intent.getIntExtra(FOOD_EAT_NUM, 1) @@ -185,6 +197,7 @@ class PayActivity : BaseActivity() { } fun showPaySuccess(isVip: Boolean) { + playSoundOnPaySuccess() EventBus.getDefault().post(PaySuccessEvent()) showPayInfo(type = 2, isVip = isVip, memberInfo = memberInfo) hidePayTab() @@ -273,6 +286,17 @@ class PayActivity : BaseActivity() { } } + override fun scanGunKeyEventCallback(scanInfo: String) { + super.scanGunKeyEventCallback(scanInfo) + userViewModel.qrCodePay(scanInfo, foodOrderId) { payState, backData -> + Timber.d("qrCodePay支付返回数据:state=$payState,backData=$backData") + if (payState) { + showPaySuccess(false) + } + } + + } + // fun bindOrder(userId: String, block: () -> Unit) { // val pickupMode = SPUtil.getInstance().get(GlobalKey.KEY_PICKUP_MODE, 0) // val mode = if (pickupMode == 1) 1 else 2 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 f8a186b..3962d50 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 @@ -216,6 +216,18 @@ interface ApiService { @Query("totalFee") totalFee: String? = null ): ApiResponse + /** + * 二维码支付 + * @param orderType 0付款 1会员充值 + */ + @GET + 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 + ): 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 2d188e4..94dd563 100644 --- a/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt +++ b/app/src/main/java/com/sw/dualscreen/repository/RemoteRepository.kt @@ -186,6 +186,15 @@ class RemoteRepository constructor( } } + /** + * 二维码支付 + */ + suspend fun qrCodePay(authCode: String,orderNo: String): ApiResponse { + return safeApiCall { + apiService.qrCodePay(authCode = authCode, orderNo=orderNo, orderType = 0) + } + } + suspend fun getDinnerType( // restId: String = GlobalData.restId, ): ApiResponse { diff --git a/app/src/main/java/com/sw/dualscreen/utils/SoundPoolUtil.java b/app/src/main/java/com/sw/dualscreen/utils/SoundPoolUtil.java new file mode 100644 index 0000000..4ace7ff --- /dev/null +++ b/app/src/main/java/com/sw/dualscreen/utils/SoundPoolUtil.java @@ -0,0 +1,427 @@ +package com.sw.dualscreen.utils; + +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.SoundPool; +import android.os.Build; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class SoundPoolUtil { + + private static final String TAG = SoundPoolUtil.class.getSimpleName(); + private static SoundPoolUtil mSound; + private SoundPool mSoundPool; + private boolean isLoadC = false; + private Map idCache; + private List sidCache; + + public SoundPoolUtil() { + idCache = new HashMap<>(); + sidCache = new ArrayList<>(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + AudioAttributes aab = new AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .setUsage(AudioAttributes.USAGE_MEDIA) + .build(); + mSoundPool = new SoundPool.Builder() + .setMaxStreams(10) + .setAudioAttributes(aab) + .build(); + } else { + mSoundPool = new SoundPool(10, AudioManager.STREAM_MUSIC, 8); + } +// mSoundPool = new SoundPool(60, AudioManager.USE_DEFAULT_STREAM_TYPE, 7); + mSoundPool.setOnLoadCompleteListener(new MyOnLoadCompleteListener()); + } + + public static SoundPoolUtil getInstance() { + + synchronized (SoundPoolUtil.class) { + if (mSound == null) { + mSound = new SoundPoolUtil(); + } + } + return mSound; + } + + private int loadCompleteSize = 0; + private LoadCompletion completionListener; + + public void setCompletionListener(LoadCompletion listener) { + this.completionListener = listener; + } + + private class MyOnLoadCompleteListener implements SoundPool.OnLoadCompleteListener { + + @Override + public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { + loadCompleteSize++; + + L.e("loadSize" + loadSize + "===" + loadCompleteSize); + if (loadSize == loadCompleteSize) { + isLoadC = true; + if (completionListener != null) { + completionListener.onCompletion(); + } + } + } + } + + + /** + * 加载指定资源 + * + * @param name + * @param path + */ + public void loadR(String name, String path) { + if (checkSoundPool()) { + if (!idCache.containsKey(name)) { + idCache.put(name, mSoundPool.load(path, 1)); + } + } + } + + private int loadSize = 0; + + /** + * 加载指定路径列表的资源 + * + * @param map + */ + public void loadR(Map map) { + loadSize = map.size(); + Set> entries = map.entrySet(); + for (Map.Entry entry : entries) { + String key = entry.getKey(); + if (checkSoundPool()) { + if (!idCache.containsKey(key)) { + idCache.put(key, mSoundPool.load(entry.getValue(), 1)); + } + } + } + } + + /** + * 加载指定AssetFileDescriptor的资源 + * + * @param name + * @param afd + */ + public void loadRF(String name, AssetFileDescriptor afd) { + if (checkSoundPool()) { + if (!idCache.containsKey(name)) { + idCache.put(name, mSoundPool.load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), 1)); + } + } + } + + /** + * 加载指定AssetFileDescriptor列表的资源 + * + * @param map + */ + public void loadRF(Map map) { + Set> entries = map.entrySet(); + for (Map.Entry entry : entries) { + String key = entry.getKey(); + if (checkSoundPool()) { + if (!idCache.containsKey(key)) { + idCache.put(key, mSoundPool.load(entry.getValue().getFileDescriptor(), entry.getValue().getStartOffset(), entry.getValue().getLength(), 1)); + } + } + } + } + + /** + * 加载指定列表资源 + * + * @param context + * @param map + */ + public void loadR(Context context, Map map) { + loadSize = map.size(); + Set> entries = map.entrySet(); + for (Map.Entry entry : entries) { + String key = entry.getKey(); + if (checkSoundPool()) { + + if (!idCache.containsKey(key)) { + idCache.put(key, mSoundPool.load(context, entry.getValue(), 1)); + } + } + } + } + + /** + * 加载单个音频 + * + * @param context + * @param name + * @param res + */ + public void loadR(Context context, String name, int res) { + if (checkSoundPool()) { + if (!idCache.containsKey(name)) { + idCache.put(name, mSoundPool.load(context, res, 1)); + } + } + } + + /** + * 播放指定音频,并返用于停止、暂停、恢复的StreamId + * + * @param name + * @param times + * @return + */ + public int play(String name, int times) { + L.e(String.format("play %s times=%s", name, times)); + return this.play(name, 1, 1, 1, times, 1); + } + + /** + * 播放指定音频,并指定播放次数和频率 + * + * @param name + * @param times + * @param rate + * @return + */ + public int play(String name, int times, int rate) { + return this.play(name, 1, 1, 1, times, rate); + } + + /** + * 播放指定音频,并指定优先级和播放频率 + * + * @param name + * @param property + * @param times + * @param rate + * @return + */ + public int play(String name, int property, int times, int rate) { + return this.play(name, 1, 1, property, times, rate); + } + + /** + * 播放指定音频,并指定左右声道、优先级、播放次数、播放频率 + * + * @param name + * @param leftVolume + * @param rightVolume + * @param property + * @param times + * @param rate + * @return + */ + public int play(String name, float leftVolume, float rightVolume, int property, int times, int rate) { + int streamId = -1; + if (checkSoundPool()) { + L.d(TAG, "play: " + name); + if (idCache.containsKey(name) && isLoadC) { + L.d(TAG, "name:" + idCache.get(name)); + streamId = mSoundPool.play(idCache.get(name), leftVolume, rightVolume, property, times, rate); + L.d(TAG, "streadmId:" + streamId); + sidCache.add(streamId); + } + } + return streamId; + } + + /** + * 播放指定列表的音频,并返回并返用于停止、暂停、恢复的StreamId列表 + * + * @param names + * @param times + * @return + */ + public List play(List names, int times) { + + return this.play(names, 1, 1, 1, times, 1); + } + + /** + * 播放指定列表的音频,并返回并返用于停止、暂停、恢复的StreamId列表,指定次数和频率 + * + * @param names + * @param times + * @param rate + * @return + */ + public List play(List names, int times, int rate) { + + return this.play(names, 1, 1, 1, times, rate); + } + + /** + * 播放指定列表的音频,并返回并返用于停止、暂停、恢复的StreamId列表,指定所有参数 + * + * @param names + * @param leftVolume + * @param rightVolume + * @param property + * @param times + * @param rate + * @return + */ + public List play(List names, int leftVolume, int rightVolume, int property, int times, int rate) { + List streamIds = new ArrayList<>(); + if (checkSoundPool()) { + for (String name : names) { + if (idCache.containsKey(name) && isLoadC) { + int a = mSoundPool.play(idCache.get(name), leftVolume, rightVolume, property, times, rate); + streamIds.add(a); + sidCache.add(a); + } + } + } + return streamIds; + } + + /** + * 停止指定id音频 + */ + public void stop(int r) { + if (checkSoundPool()) { + mSoundPool.stop(r); + } + } + + /** + * 停止指定列表音频 + */ + public void stopAll() { + if (checkSoundPool()) { + for (int r : sidCache) { + mSoundPool.stop(r); + } + } + } + + /** + * 暂停指定音效 + * + * @param r + */ + public void pause(int r) { + if (checkSoundPool()) { + mSoundPool.pause(r); + } + } + + /** + * 暂停指定列表音频 + * + * @param list + */ + public void pause(List list) { + if (checkSoundPool()) { + for (int r : list) { + mSoundPool.pause(r); + } + } + } + + /** + * 暂停所有音效 + */ + public void pauseAll() { + mSoundPool.autoPause(); + } + + /** + * 恢复指定音频播放 + * + * @param r + */ + public void resume(int r) { + if (checkSoundPool()) { + mSoundPool.resume(r); + } + } + + /** + * 恢复指定列表的音频 + * + * @param list + */ + public void resume(List list) { + if (checkSoundPool()) { + for (int r : list) { + mSoundPool.resume(r); + } + } + } + + /** + * 恢复所有暂停的音频 + */ + public void resumeAll() { + if (checkSoundPool()) { + mSoundPool.autoResume(); + } + } + + /** + * 卸载指定音频 + * + * @param name + */ + public void unLoad(String name) { + if (checkSoundPool()) { + if (idCache.containsKey(name)) { + mSoundPool.unload(idCache.get(name)); + idCache.remove(name); + } + } + } + + /** + * 卸载指定列表的音频 + * + * @param names + */ + public void unLoad(List names) { + if (checkSoundPool()) { + for (String name : names) { + if (idCache.containsKey(name)) { + mSoundPool.unload(idCache.get(name)); + idCache.remove(name); + } + } + } + } + + + /** + * 释放所有资源,如果想继续播放,需要重新加载资源 + */ + public void release() { + if (checkSoundPool()) { + mSound = null; + mSoundPool.release(); + idCache.clear(); + } + } + + private boolean checkSoundPool() { + if (mSoundPool != null) { + return true; + } + return false; + } + + public interface LoadCompletion { + void onCompletion(); + } +} + 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 a1dd0e1..ed548f4 100644 --- a/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt +++ b/app/src/main/java/com/sw/dualscreen/viewmodel/UserViewModel.kt @@ -5,6 +5,7 @@ import com.arcsoft.face.ErrorInfo import com.sw.dualscreen.GlobalData import com.sw.dualscreen.GlobalKey import com.sw.dualscreen.model.request.UserNutritionParam +import com.sw.dualscreen.model.response.ApiResponse import com.sw.dualscreen.model.response.DeviceConfig import com.sw.dualscreen.model.response.DinnerType import com.sw.dualscreen.model.response.FoodInfo @@ -359,6 +360,19 @@ class UserViewModel : BaseViewModel() { } } + /** + * 二维码支付 + */ + fun qrCodePay(authCode: String,orderNo: String, block:(Boolean, String?)-> Unit){ + launch { + val response = repository.qrCodePay(authCode, orderNo) + if (parseResponse(response)) { + block(true, response.data) + } else { + block(false, null) + } + } + } fun getDinnerType() { Timber.tag(TAG).d("getDinnerType") _dinnerTypeInfo.value = null diff --git a/app/src/main/res/raw/pay_success.mp3 b/app/src/main/res/raw/pay_success.mp3 new file mode 100644 index 0000000..2415638 Binary files /dev/null and b/app/src/main/res/raw/pay_success.mp3 differ