Merge branch 'hotfix/1.0.4'
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a5586c3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,21 @@
+.PHONEY: .o
+
+APPPATH=./app/build/outputs/apk/release
+BUILDAPK=app-release.apk
+SIGNAPK=app_sign.apk
+
+apk:
+	@echo "build app apk!"
+	gradlew assembleRelease
+	@echo "build android sign apk"
+	java -jar signapk.jar platform.x509.pem platform.pk8 $(APPPATH)/$(BUILDAPK) $(APPPATH)/$(SIGNAPK)
+	@echo "build upgrade zip"
+	python upgrade.py $(APPPATH)/$(SIGNAPK)
+clean:
+	@echo "remove build cache apk!"
+	rm -rf $(APPPATH)/$(BUILDAPK)
+	rm -rf $(APPPATH)/$(SIGNAPK)
+	rm -rf $(APPPATH)/hash256.sign
+	rm -rf $(APPPATH)/output.json
+	@echo "remove build cache file success"
+
diff --git a/app/build.gradle b/app/build.gradle
index 6737c2d..73373a4 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -24,6 +24,8 @@
             storePassword "123456"
             keyAlias "sup"
             keyPassword "123456"
+            v1SigningEnabled true
+            v2SigningEnabled true
         }
     }
     buildTypes {
diff --git a/app/src/main/java/com/supwisdom/activities/consume/ConsumeActivity.kt b/app/src/main/java/com/supwisdom/activities/consume/ConsumeActivity.kt
index 5a07853..7febabd 100644
--- a/app/src/main/java/com/supwisdom/activities/consume/ConsumeActivity.kt
+++ b/app/src/main/java/com/supwisdom/activities/consume/ConsumeActivity.kt
@@ -29,6 +29,7 @@
 import com.supwisdom.view.DialogPurchase
 import java.util.*
 import java.util.concurrent.locks.ReentrantLock
+import kotlin.collections.ArrayList
 
 /**
  ** create by zzq on 2019/7/24
@@ -65,6 +66,9 @@
     private var addAmount: Int = 0
     @Volatile
     private var amount: Int = 0
+    private var payMode: PayMode? = null
+    private val hotkeyPayMap = hashMapOf<Int, Int>()
+    private val hotkeyPayList = ArrayList<String>()
     private var payWay: String? = null
     private var counter: LastPayShowTimer? = null
     private var lastPayInfo: CardUserInfoBean? = null
@@ -87,9 +91,17 @@
                 if (isPaying) {
                     presenter.clickToInterrupt()
                 } else {
-                    presenter.clickNoPay()
-                    amountTxt.text = ""
-                    AuxScreenController.getInstance().refreshContent(Arrays.asList(" 欢迎光临!", " 请刷卡..."))
+                    when (payMode) {
+                        PayMode.FIXPAY -> checkAmtToPay(amount)
+                        PayMode.HOTKEY -> {
+                            AuxScreenController.getInstance().refreshContent(hotkeyPayList)
+                        }
+                        else -> {
+                            presenter.clickNoPay()
+                            amountTxt.text = ""
+                            AuxScreenController.getInstance().refreshContent(Arrays.asList(" 欢迎光临!", " 请刷卡..."))
+                        }
+                    }
                 }
             }
 
@@ -158,65 +170,126 @@
     @SuppressLint("SetTextI18n")
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {
         if (event.action == KeyEvent.ACTION_DOWN) {
-            val keyCode = event.keyCode
-            when (keyCode) {
-                KeyEvent.KEYCODE_BACK -> {
-                    amountTxt.text = "0"
-                    presenter.clickNoPay()
-                }
-                KeyEvent.KEYCODE_0,
-                KeyEvent.KEYCODE_1,
-                KeyEvent.KEYCODE_2,
-                KeyEvent.KEYCODE_3,
-                KeyEvent.KEYCODE_4,
-                KeyEvent.KEYCODE_5,
-                KeyEvent.KEYCODE_6,
-                KeyEvent.KEYCODE_7,
-                KeyEvent.KEYCODE_8,
-                KeyEvent.KEYCODE_9 -> {
-                    presenter.clickNoPay()
-                    addValueToEdit(keyCode - KeyEvent.KEYCODE_0)
-                }
-                KeyEvent.KEYCODE_POUND, KeyEvent.KEYCODE_PERIOD -> {
-                    presenter.clickNoPay()
-                    val str = amountTxt.text.toString()
-                    if (str.length < 8 && str.indexOf('.') < 0) {
-                        amountTxt.text = "$str."
-                        showScreenAmount()
-                    }
-                }
-                KeyEvent.KEYCODE_NUMPAD_ADD -> {
-                    //'+'
-                    addAmount += getCurAmount()
-                    amountTxt.text = ""
-                    showScreenAmount()
-                }
-                KeyEvent.KEYCODE_DPAD_LEFT -> {
-                    //'F1'
-                    isBackRuning = true
-                    jumpActivity(MenuActivity::class.java)
-                }
-//                KeyEvent.KEYCODE_DPAD_UP ->
-                //'F2'
-//                KeyEvent.KEYCODE_DPAD_DOWN ->
-                //'F3'
-                KeyEvent.KEYCODE_DPAD_RIGHT -> {
-                    //'F4'
-                    jumpActivity(TransdtlActivity::class.java)
-                }
-                KeyEvent.KEYCODE_DEL -> {
-                    //cancel
-                    presenter.clickNoPay()
-                    delValueToEdit()
-                }
-                KeyEvent.KEYCODE_ENTER -> {
-                    checkAmtToPay()
-                }
+            when (payMode) {
+                PayMode.FIXPAY -> fixInputPay(event.keyCode)
+                PayMode.HOTKEY -> hotkeyInputPay(event.keyCode)
+                else -> normalInputPay(event.keyCode)
             }
         }
         return super.dispatchKeyEvent(event)
     }
 
+    private fun fixInputPay(keyCode: Int) {
+        when (keyCode) {
+            KeyEvent.KEYCODE_DPAD_LEFT -> {
+                //'F1'
+                isBackRuning = true
+                jumpActivity(MenuActivity::class.java)
+            }
+            KeyEvent.KEYCODE_DPAD_RIGHT -> {
+                //'F4'
+                jumpActivity(TransdtlActivity::class.java)
+            }
+        }
+    }
+
+    private fun hotkeyInputPay(keyCode: Int) {
+        when (keyCode) {
+            KeyEvent.KEYCODE_0,
+            KeyEvent.KEYCODE_1,
+            KeyEvent.KEYCODE_2,
+            KeyEvent.KEYCODE_3,
+            KeyEvent.KEYCODE_4,
+            KeyEvent.KEYCODE_5,
+            KeyEvent.KEYCODE_6,
+            KeyEvent.KEYCODE_7,
+            KeyEvent.KEYCODE_8,
+            KeyEvent.KEYCODE_9 -> {
+                val key = keyCode - KeyEvent.KEYCODE_0
+                if (hotkeyPayMap.containsKey(key)) {
+                    amount = hotkeyPayMap[key]!!
+                    checkAmtToPay(amount)
+                }
+            }
+            KeyEvent.KEYCODE_DEL -> {
+                //cancel
+                presenter.clickNoPay()
+                AuxScreenController.getInstance().refreshContent(hotkeyPayList)
+            }
+            KeyEvent.KEYCODE_DPAD_LEFT -> {
+                //'F1'
+                isBackRuning = true
+                jumpActivity(MenuActivity::class.java)
+            }
+            KeyEvent.KEYCODE_DPAD_RIGHT -> {
+                //'F4'
+                jumpActivity(TransdtlActivity::class.java)
+            }
+        }
+    }
+
+    private fun normalInputPay(keyCode: Int) {
+        when (keyCode) {
+            KeyEvent.KEYCODE_BACK -> {
+                amountTxt.text = "0"
+                presenter.clickNoPay()
+            }
+            KeyEvent.KEYCODE_0,
+            KeyEvent.KEYCODE_1,
+            KeyEvent.KEYCODE_2,
+            KeyEvent.KEYCODE_3,
+            KeyEvent.KEYCODE_4,
+            KeyEvent.KEYCODE_5,
+            KeyEvent.KEYCODE_6,
+            KeyEvent.KEYCODE_7,
+            KeyEvent.KEYCODE_8,
+            KeyEvent.KEYCODE_9 -> {
+                presenter.clickNoPay()
+                addValueToEdit(keyCode - KeyEvent.KEYCODE_0)
+            }
+            KeyEvent.KEYCODE_POUND, KeyEvent.KEYCODE_PERIOD -> {
+                presenter.clickNoPay()
+                val str = amountTxt.text.toString()
+                if (str.length < 8 && str.indexOf('.') < 0) {
+                    amountTxt.text = "$str."
+                    showScreenAmount()
+                }
+            }
+            KeyEvent.KEYCODE_NUMPAD_ADD -> {
+                //'+'
+                addAmount += getCurAmount()
+                amountTxt.text = ""
+                showScreenAmount()
+            }
+            KeyEvent.KEYCODE_DPAD_LEFT -> {
+                //'F1'
+                isBackRuning = true
+                jumpActivity(MenuActivity::class.java)
+            }
+//                KeyEvent.KEYCODE_DPAD_UP ->
+            //'F2'
+//                KeyEvent.KEYCODE_DPAD_DOWN ->
+            //'F3'
+            KeyEvent.KEYCODE_DPAD_RIGHT -> {
+                //'F4'
+                jumpActivity(TransdtlActivity::class.java)
+            }
+            KeyEvent.KEYCODE_DEL -> {
+                //cancel
+                presenter.clickNoPay()
+                delValueToEdit()
+            }
+            KeyEvent.KEYCODE_ENTER -> {
+                amount = getCurAmount() + addAmount
+                if (amount > 0) {
+                    checkAmtToPay(amount)
+                } else {
+                    AuxScreenController.getInstance().refreshContent(Arrays.asList("请先输入金额:", "金额不能为0"))
+                }
+            }
+        }
+    }
+
     override fun showUserInfo(info: CardUserInfoBean) {
         CommonUtil.acquireWakeLock(this)
         vCitizenName.text = info.username
@@ -297,16 +370,32 @@
         AuxScreenController.getInstance().refreshBottom(DateUtil.getNowDateTime().substring(0, 16))
         AuxScreenController.getInstance().refreshContent(Arrays.asList(" 欢迎光临!", " 请刷卡..."))
 
-        val record = SPApplication.getInstance().getPos().getControlPara(PublicDef.CONTROL_FIXAMT)
-        if (record != null && PublicDef.CONTROL_NO_FIXPAY_FLAG != record.paraval) {
-            try {
-                amount = Integer.parseInt(record.paraval)
-                amountTxt.text = String.format("%.02f", amount / 100.0f)
-                payStatusEnable = true
-                presenter.clickToPay(amount)
-                showDialogPay()
-            } catch (ex: Exception) {
-                ex.printStackTrace()
+        SPApplication.getInstance().getPos().getControlPara(PublicDef.CONTROL_FIXAMT)?.also { mode ->
+            when {
+                mode.paraval == PayMode.HOTKEY.desc -> {
+                    presenter.setFixMode(false)
+                    payMode = PayMode.HOTKEY
+                    hotkeyPayMap.clear()
+                    hotkeyPayList.clear()
+                    SPApplication.getInstance().getPos().getHotkeyPay()?.forEach {
+                        hotkeyPayMap[it.key] = it.amount
+                        hotkeyPayList.add(String.format("按键%d - %.02f元", it.key, it.amount / 100.0f))
+                    }
+                    AuxScreenController.getInstance().refreshContent(hotkeyPayList)
+                }
+                mode.paraval == PayMode.NORMAL.desc -> {
+                    presenter.setFixMode(false)
+                    payMode = PayMode.NORMAL
+                }
+                else -> {
+                    presenter.setFixMode(true)
+                    payMode = PayMode.FIXPAY
+                    try {
+                        checkAmtToPay(Integer.parseInt(mode.paraval))
+                    } catch (ex: Exception) {
+                        ex.printStackTrace()
+                    }
+                }
             }
         }
     }
@@ -469,23 +558,33 @@
         }
     }
 
-    private fun checkAmtToPay() {
-        amount = getCurAmount() + addAmount
-        if (amount > 0) {
-            AuxScreenController.getInstance()
-                .refreshContent(Arrays.asList("等待付款", CommonUtil.showFormatAmount("金额", amount)))
-            amountTxt.text = String.format("%.02f", amount / 100.0f)
-            payStatusEnable = true
-            presenter.clickToPay(amount)
-            showDialogPay()
-        } else {
-            AuxScreenController.getInstance().refreshContent(Arrays.asList("请先输入金额:", "金额不能为0"))
+    private fun checkAmtToPay(inputAmt: Int) {
+        amount = inputAmt
+        amountTxt.text = String.format("%.02f", inputAmt / 100.0f)
+        payStatusEnable = true
+        presenter.clickToPay(inputAmt)
+        when (payMode) {
+            PayMode.FIXPAY -> {
+                AuxScreenController.getInstance()
+                    .refreshContent(Arrays.asList("定额付款", CommonUtil.showFormatAmount("金额", inputAmt)))
+                showDialogPay(true)
+            }
+            PayMode.HOTKEY -> {
+                AuxScreenController.getInstance()
+                    .refreshContent(Arrays.asList("热键付款", CommonUtil.showFormatAmount("金额", inputAmt)))
+                showDialogPay(false)
+            }
+            else -> {
+                AuxScreenController.getInstance()
+                    .refreshContent(Arrays.asList("等待付款", CommonUtil.showFormatAmount("金额", inputAmt)))
+                showDialogPay(false)
+            }
         }
     }
 
-    private fun showDialogPay() {
+    private fun showDialogPay(isFixPay: Boolean) {
         dialogPurchase!!.codePaying = false
-        dialogPurchase!!.isFixPay = false
+        dialogPurchase!!.isFixPay = isFixPay
         dialogPurchase!!.codePayingNoCancelEnable = false
         dialogPurchase!!.show("请刷卡", CommonUtil.showFormatAmount("金额", amount))
     }
diff --git a/app/src/main/java/com/supwisdom/activities/consume/ConsumePresenter.kt b/app/src/main/java/com/supwisdom/activities/consume/ConsumePresenter.kt
index b5aeb03..43b5ed2 100644
--- a/app/src/main/java/com/supwisdom/activities/consume/ConsumePresenter.kt
+++ b/app/src/main/java/com/supwisdom/activities/consume/ConsumePresenter.kt
@@ -32,7 +32,7 @@
     init {
         createHandler()
         cardPayService = CardPayService(iConsumeView, handler)
-        codePayService = CodePayService(iConsumeView, handler)
+        codePayService = CodePayService(handler)
     }
 
     private fun createHandler() {
@@ -91,6 +91,11 @@
         cardPayService.clickToInterrupt()
     }
 
+    fun setFixMode(isFixMode: Boolean) {
+        cardPayService.isFixMode = isFixMode
+        codePayService.isFixMode = isFixMode
+    }
+
     fun codeToPay(code: String, amount: Int) {
         this.code = code
         this.amount = amount
@@ -123,4 +128,10 @@
             codePayService.pay(code!!, amount)
         }
     }
+}
+
+enum class PayMode(val desc: String) {
+    NORMAL("none"),
+    FIXPAY("fixpay"),
+    HOTKEY("hotkey")
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/activities/consume/bean/LastPayBean.kt b/app/src/main/java/com/supwisdom/activities/consume/bean/LastPayBean.kt
new file mode 100644
index 0000000..5da0ba9
--- /dev/null
+++ b/app/src/main/java/com/supwisdom/activities/consume/bean/LastPayBean.kt
@@ -0,0 +1,11 @@
+package com.supwisdom.activities.consume.bean
+
+/**
+ ** create by zzq on 2019/9/16
+ ** @desc
+ **/
+class LastPayBean {
+    var cardphyid: String? = null
+    var code: String? = null
+    var suctime: Long = 0 //ms
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/activities/consume/mode/CardPayService.kt b/app/src/main/java/com/supwisdom/activities/consume/mode/CardPayService.kt
index cde67f4..4b39eea 100644
--- a/app/src/main/java/com/supwisdom/activities/consume/mode/CardPayService.kt
+++ b/app/src/main/java/com/supwisdom/activities/consume/mode/CardPayService.kt
@@ -20,10 +20,8 @@
  ** create by zzq on 2019/7/25
  ** @desc 刷卡消费
  **/
-class CardPayService constructor(iConsumeView: IConsumeView, handler: Handler) {
+class CardPayService constructor(private val iConsumeView: IConsumeView, private val handler: Handler) {
     private val TAG = "CardPayService"
-    private val iConsumeView = iConsumeView
-    private val handler = handler
     private val pos = SPApplication.getInstance().getPos()
     private val runnable = CardPayRunnable()
     private val consumeApi = ConsumeApi()
@@ -35,8 +33,13 @@
     private var amount: Int = 0
     @Volatile
     private var payQueryConfirm = false
+    var isFixMode = false
     private var thread: Thread? = null
     private var cardBean: CardBean? = null
+    /**
+     * 防止定额连续消费
+     */
+    private var lastPayBean = LastPayBean()
 
     fun start() {
         isExist = false
@@ -210,6 +213,13 @@
         }
 
         private fun doConsume() {
+            if (isFixMode) {
+                if (lastPayBean.cardphyid == cardBean!!.cardphyid) {
+                    if (System.currentTimeMillis() - lastPayBean.suctime < 15000) {
+                        throw CardPayFailError("15s内不能连续消费")
+                    }
+                }
+            }
             sendMsg(PublicDef.MSG_CARD_PAYING, "正在扣款...")
             if (SPApplication.getInstance().isOnline()) {
                 if (!doOnlineConsume()) {
@@ -487,6 +497,11 @@
                 "lock" -> throw CardPayFailError("卡已锁定")
                 else -> throw CardPayFailError("卡状态:${whiteRecord.status}")
             }
+
+            val payamt = pos.getTransdtlOfflineAmt(offRecord.transdate!!, offRecord.cardno!!, offRecord.cardphyid!!)
+            if ((payamt + offRecord.payamt) > sysRecord.maxDayOfflineAmt) {
+                throw CardPayFailError("已离线交易" + String.format("%.02f元", payamt / 100.0f))
+            }
         }
 
         private fun initTransdtlOffline() {
@@ -526,6 +541,8 @@
         }
 
         private fun showOnlSucInfo() {
+            lastPayBean.cardphyid = cardBean!!.cardphyid
+            lastPayBean.suctime = System.currentTimeMillis()
             val info = CardUserInfoBean(PublicDef.SUCCESS, "消费成功")
             info.showtime = pos.getSysPara()!!.sucShowtime
             info.amount = onlRecord.payamt
@@ -541,6 +558,8 @@
         }
 
         private fun showOffSucInfo() {
+            lastPayBean.cardphyid = cardBean!!.cardphyid
+            lastPayBean.suctime = System.currentTimeMillis()
             val info = CardUserInfoBean(PublicDef.SUCCESS, "消费成功")
             info.showtime = pos.getSysPara()!!.sucShowtime
             info.amount = offRecord.payamt
diff --git a/app/src/main/java/com/supwisdom/activities/consume/mode/CodePayService.kt b/app/src/main/java/com/supwisdom/activities/consume/mode/CodePayService.kt
index 08b68c1..eb076ea 100644
--- a/app/src/main/java/com/supwisdom/activities/consume/mode/CodePayService.kt
+++ b/app/src/main/java/com/supwisdom/activities/consume/mode/CodePayService.kt
@@ -3,10 +3,10 @@
 import android.os.Handler
 import android.os.Message
 import com.supwisdom.activities.SPApplication
-import com.supwisdom.activities.consume.IConsumeView
 import com.supwisdom.activities.consume.bean.CardPayConfirmRetBean
 import com.supwisdom.activities.consume.bean.CardPayInitRetBean
 import com.supwisdom.activities.consume.bean.CardUserInfoBean
+import com.supwisdom.activities.consume.bean.LastPayBean
 import com.supwisdom.entity.PayStatus
 import com.supwisdom.entity.ReversalFlag
 import com.supwisdom.entity.TransdtlOnlineRecord
@@ -14,16 +14,13 @@
 import com.supwisdom.okhttp.TransResp
 import com.supwisdom.utils.*
 import org.apache.http.HttpStatus
-import java.lang.Exception
 
 /**
  ** create by zzq on 2019/7/30
  ** @desc 二维码消费
  **/
-class CodePayService constructor(iConsumeView: IConsumeView, handler: Handler) {
+class CodePayService constructor(private val handler: Handler) {
     private val TAG = "CodePayService"
-    private val iConsumeView = iConsumeView
-    private val handler = handler
     private val pos = SPApplication.getInstance().getPos()
     private lateinit var codeRecord: TransdtlOnlineRecord
     private val consumeApi = ConsumeApi()
@@ -35,6 +32,8 @@
     private var interruptedPay: Boolean = false
     @Volatile
     private var amount = 0
+    var isFixMode = false
+    private val lastPayBean = LastPayBean()
 
     fun interruptPay() {
         interruptedPay = true
@@ -44,6 +43,13 @@
         this.amount = amount
         interruptedPay = false
         try {
+            if (isFixMode) {
+                if (lastPayBean.code == code) {
+                    if (System.currentTimeMillis() - lastPayBean.suctime < 15000) {
+                        throw CardPayFailError("15s内不能连续消费")
+                    }
+                }
+            }
             initTransdtlOnline(code, amount)
             var resp = consumeApi.payInit(codeRecord)
             parseInitResult(resp)
@@ -178,6 +184,8 @@
     }
 
     private fun showSucInfo() {
+        lastPayBean.code = codeRecord.qrcode
+        lastPayBean.suctime = System.currentTimeMillis()
         val info = CardUserInfoBean(PublicDef.SUCCESS, "消费成功")
         info.showtime = pos.getSysPara()!!.sucShowtime
         info.amount = codeRecord.payamt
diff --git a/app/src/main/java/com/supwisdom/activities/consumeMode/ConsumeModeActivity.kt b/app/src/main/java/com/supwisdom/activities/consumeMode/ConsumeModeActivity.kt
index d7f5e32..3daaf82 100644
--- a/app/src/main/java/com/supwisdom/activities/consumeMode/ConsumeModeActivity.kt
+++ b/app/src/main/java/com/supwisdom/activities/consumeMode/ConsumeModeActivity.kt
@@ -4,16 +4,24 @@
 import android.os.Bundle
 import android.os.CountDownTimer
 import android.view.KeyEvent
+import android.view.View
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.RadioButton
 import android.widget.TextView
 import com.supwisdom.R
 import com.supwisdom.activities.BaseActivity
 import com.supwisdom.activities.SPApplication
+import com.supwisdom.activities.consume.PayMode
 import com.supwisdom.activities.menu.MenuActivity
 import com.supwisdom.auxscreen.AuxScreenController
+import com.supwisdom.entity.HotKeyPayRecord
 import com.supwisdom.utils.CommonUtil
 import com.supwisdom.utils.DateUtil
 import com.supwisdom.utils.PublicDef
+import com.supwisdom.view.SWToast
 import java.util.*
+import kotlin.collections.ArrayList
 
 /**
  ** create by zzq on 2019/7/26
@@ -21,19 +29,127 @@
  **/
 class ConsumeModeActivity : BaseActivity() {
     private lateinit var vPayamt: TextView
+    private lateinit var vNormalMode: TextView
+    private lateinit var vFixMode: TextView
+    private lateinit var vHotkeyMode: TextView
+    private lateinit var llHotList: LinearLayout
+    private lateinit var llFixMode: LinearLayout
+    private lateinit var llHotMode: LinearLayout
     private val pos = SPApplication.getInstance().getPos()
     private var keyActive = true
     private var shoppwdPass = false
+    private var hotkey = false
     private var tmpPwd = ""
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         this.setContentView(R.layout.activity_consume_mode)
         initView()
+        initData()
+    }
+
+    private fun initData() {
+        pos.getHotkeyPay()?.forEach {
+            val item = View.inflate(this, R.layout.item_hotkey_pay, null)
+            item.findViewById<TextView>(R.id.tv_hot_del).setOnClickListener {
+                llHotList.removeView(item)
+                for (loop in 0 until llHotList.childCount) {
+                    val item = llHotList.getChildAt(loop)
+                    val key = item.findViewById<TextView>(R.id.tv_hot_key)
+                    key.text = "${(loop + 1)}"
+                }
+            }
+            val key = item.findViewById<TextView>(R.id.tv_hot_key)
+            key.text = "${llHotList.childCount + 1}"
+            val amt = item.findViewById<TextView>(R.id.tv_hot_amount)
+            amt.text = String.format("%.02f", it.amount / 100.0f)
+            llHotList.addView(item)
+        }
     }
 
     private fun initView() {
         vPayamt = findViewById<TextView>(R.id.tv_consume_mode_payamt)
+        llHotList = findViewById<LinearLayout>(R.id.ll_hot_list)
+        this.findViewById<TextView>(R.id.tv_hot_add).setOnClickListener {
+            if (llHotList.childCount >= 9) {
+                return@setOnClickListener
+            }
+            val item = View.inflate(this, R.layout.item_hotkey_pay, null)
+            item.findViewById<TextView>(R.id.tv_hot_del).setOnClickListener {
+                llHotList.removeView(item)
+                for (loop in 0 until llHotList.childCount) {
+                    val item = llHotList.getChildAt(loop)
+                    val key = item.findViewById<TextView>(R.id.tv_hot_key)
+                    key.text = "${(loop + 1)}"
+                }
+            }
+            val key = item.findViewById<TextView>(R.id.tv_hot_key)
+            key.text = "${llHotList.childCount + 1}"
+            llHotList.addView(item)
+        }
+        this.findViewById<TextView>(R.id.tv_hot_save).setOnClickListener {
+            if (llHotList.childCount == 0) {
+                SWToast.show(applicationContext, "请先添加热键", PublicDef.TOAST_SHOW_DOUBT)
+                return@setOnClickListener
+            }
+            val list = ArrayList<HotKeyPayRecord>()
+            for (loop in 0 until llHotList.childCount) {
+                val item = llHotList.getChildAt(loop)
+                val key = item.findViewById<TextView>(R.id.tv_hot_key)
+                val keyboard = key.text.toString()
+                val amt = item.findViewById<EditText>(R.id.tv_hot_amount)
+                val hotamt = CommonUtil.getEditView(amt)
+
+                val record = HotKeyPayRecord()
+                record.key = Integer.parseInt(keyboard)
+                record.amount = CommonUtil.YuanToFen(java.lang.Double.parseDouble(hotamt))
+                list.add(record)
+            }
+            pos.replaceControlPara(PublicDef.CONTROL_FIXAMT, PayMode.HOTKEY.desc)
+            if (!pos.saveHotkeyPay(list)) {
+                SWToast.show(applicationContext, "保持热键失败", PublicDef.TOAST_SHOW_CRY)
+                return@setOnClickListener
+            }
+            finish()
+        }
+        this.findViewById<TextView>(R.id.tv_return).setOnClickListener {
+            hotkey = false
+            llHotMode.visibility = View.GONE
+            llFixMode.visibility = View.VISIBLE
+            refreshToSetAmount()
+        }
+        vNormalMode = this.findViewById<RadioButton>(R.id.rb_normal_mode)
+        vFixMode = this.findViewById<RadioButton>(R.id.rb_fix_mode)
+        vHotkeyMode = this.findViewById<RadioButton>(R.id.rb_hot_mode)
+
+        llFixMode = this.findViewById<LinearLayout>(R.id.ll_fix_mode)
+        llHotMode = this.findViewById<LinearLayout>(R.id.ll_hot_mode)
+    }
+
+    @SuppressLint("SetTextI18n")
+    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        if (event.action == KeyEvent.ACTION_DOWN) {
+            if (!keyActive) {
+                return super.dispatchKeyEvent(event)
+            }
+            resetCounter(200)
+            if (shoppwdPass) {
+                setFixAmount(event.keyCode)
+            } else {
+                checkShopPwd(event.keyCode)
+            }
+        }
+        return super.dispatchKeyEvent(event)
+    }
+
+    override fun onResume() {
+        super.onResume()
+        shoppwdPass = false
+        hotkey = false
+        keyActive = true
+        llFixMode.visibility = View.VISIBLE
+        llHotMode.visibility = View.GONE
+        refreshToCheckPasswd()
     }
 
     private fun checkShopPwd(keyCode: Int) {
@@ -87,6 +203,10 @@
     }
 
     private fun setFixAmount(keyCode: Int) {
+        if (hotkey) {
+            AuxScreenController.getInstance().refreshContent(Arrays.asList<String>("请到大屏设置"))
+            return
+        }
         when (keyCode) {
             KeyEvent.KEYCODE_0,
             KeyEvent.KEYCODE_1,
@@ -98,44 +218,21 @@
             KeyEvent.KEYCODE_7,
             KeyEvent.KEYCODE_8,
             KeyEvent.KEYCODE_9 -> addValueToEdit(keyCode - KeyEvent.KEYCODE_0)
-            KeyEvent.KEYCODE_DEL ->
-                //cancel
-                delValueToEdit()
-            KeyEvent.KEYCODE_POUND, KeyEvent.KEYCODE_PERIOD -> {
-                val str = vPayamt.text.toString()
-                if (str.length < 8 && str.indexOf('.') < 0) {
-                    vPayamt.text = "$str."
-                    screenShowAmt()
-                }
-            }
+            KeyEvent.KEYCODE_DEL -> delValueToEdit()
+            KeyEvent.KEYCODE_POUND,
+            KeyEvent.KEYCODE_PERIOD -> addDotToEdit()
             KeyEvent.KEYCODE_ENTER -> {
                 pos.replaceControlPara(PublicDef.CONTROL_FIXAMT, getFixAmount())
                 jumpActivity(MenuActivity::class.java)
             }
-        }
-    }
-
-    @SuppressLint("SetTextI18n")
-    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
-        if (event.action == KeyEvent.ACTION_DOWN) {
-            if (!keyActive) {
-                return super.dispatchKeyEvent(event)
-            }
-            resetCounter(200)
-            if (shoppwdPass) {
-                setFixAmount(event.keyCode)
-            } else {
-                checkShopPwd(event.keyCode)
+            KeyEvent.KEYCODE_DPAD_LEFT -> {
+                //F1
+                hotkey = true
+                llHotMode.visibility = View.VISIBLE
+                llFixMode.visibility = View.GONE
+                AuxScreenController.getInstance().refreshContent(Arrays.asList<String>("请到大屏设置"))
             }
         }
-        return super.dispatchKeyEvent(event)
-    }
-
-    override fun onResume() {
-        super.onResume()
-        shoppwdPass = false
-        keyActive = true
-        refreshToCheckPasswd()
     }
 
     private fun refreshToCheckPasswd() {
@@ -145,11 +242,11 @@
     }
 
     private fun refreshToSetAmount() {
-        val record = pos.getControlPara(PublicDef.CONTROL_FIXAMT)
-        if (record != null && PublicDef.CONTROL_NO_FIXPAY_FLAG != record.paraval) {
-            vPayamt.text = String.format("%.02f", Integer.parseInt(record.paraval) / 100.0f)
-        } else {
-            vPayamt.text = PublicDef.CONTROL_NO_FIXPAY_FLAG
+        vPayamt.text = PayMode.NORMAL.desc
+        pos.getControlPara(PublicDef.CONTROL_FIXAMT)?.also {
+            if (PayMode.FIXPAY.desc == it.paraval) {
+                vPayamt.text = String.format("%.02f", Integer.parseInt(it.paraval) / 100.0f)
+            }
         }
         screenShowAmt()
     }
@@ -160,13 +257,12 @@
         } catch (e: Exception) {
             e.printStackTrace()
         }
-
-        return PublicDef.CONTROL_NO_FIXPAY_FLAG
+        return PayMode.NORMAL.desc
     }
 
     private fun addValueToEdit(value: Int) {
         var str = vPayamt.text.toString()
-        if ("0" == str || PublicDef.CONTROL_NO_FIXPAY_FLAG == str) {
+        if ("0" == str || PayMode.NORMAL.desc == str) {
             str = ""
         }
         //如果已经有小数点,则小数点后面不能超过两位
@@ -187,9 +283,9 @@
 
     private fun delValueToEdit() {
         val str = vPayamt.text.toString()
-        if (PublicDef.CONTROL_NO_FIXPAY_FLAG != str) {
+        if (PayMode.NORMAL.desc != str) {
             if (str.length <= 1) {
-                vPayamt.text = PublicDef.CONTROL_NO_FIXPAY_FLAG
+                vPayamt.text = PayMode.NORMAL.desc
             } else {
                 vPayamt.text = str.substring(0, str.length - 1)
             }
@@ -197,15 +293,28 @@
         screenShowAmt()
     }
 
+    private fun addDotToEdit() {
+        val str = vPayamt.text.toString()
+        if (PayMode.NORMAL.desc == str) {
+            vPayamt.text = "0."
+        } else {
+            if (str.length < 8 && str.indexOf('.') < 0) {
+                vPayamt.text = "$str."
+            }
+        }
+        screenShowAmt()
+    }
+
     private fun screenShowAmt() {
+        AuxScreenController.getInstance().refreshTitle("消费模式设置       F1-热键模式")
+        AuxScreenController.getInstance().refreshBottom(DateUtil.getNowDateTime())
         AuxScreenController.getInstance().refreshContent(
             Arrays.asList<String>(
-                PublicDef.CONTROL_NO_FIXPAY_FLAG + "-普通消费",
+                PayMode.NORMAL.desc + "-普通消费",
                 "值-定额消费(元)",
                 String.format("金额:%s", vPayamt.text.toString())
             )
         )
-
     }
 
     override fun onDestroy() {
diff --git a/app/src/main/java/com/supwisdom/activities/load/LoadPresenter.kt b/app/src/main/java/com/supwisdom/activities/load/LoadPresenter.kt
index f6d0578..77ba654 100644
--- a/app/src/main/java/com/supwisdom/activities/load/LoadPresenter.kt
+++ b/app/src/main/java/com/supwisdom/activities/load/LoadPresenter.kt
@@ -29,7 +29,7 @@
     private val LOAD_SUCCESS = 1
     private val JUMP_TO_UNREGISTER = 2
     private val LOAD_PROGRESS = 3
-    private val LOAD_DONE = 3
+    private val LOAD_DONE = 4
 
     private var hasInit: Boolean = false
     @Volatile
@@ -96,7 +96,7 @@
 
             try {
                 sendMessage(LOAD_PROGRESS, "加载白名单...")
-                apiInterface.downloadWhitelist(bean.cardverno!!)
+                apiInterface.downloadWhitelist(bean.whitelistid, bean.cardverno!!)
                 sendMessage(LOAD_DONE, "加载白名单成功")
             } catch (ex: Exception) {
                 sendMessage(LOAD_DONE, "加载白名单失败:${ex.message}")
diff --git a/app/src/main/java/com/supwisdom/activities/manage/ManagePresenter.kt b/app/src/main/java/com/supwisdom/activities/manage/ManagePresenter.kt
index cfc459c..681d57d 100644
--- a/app/src/main/java/com/supwisdom/activities/manage/ManagePresenter.kt
+++ b/app/src/main/java/com/supwisdom/activities/manage/ManagePresenter.kt
@@ -3,7 +3,9 @@
 import android.os.AsyncTask
 import com.supwisdom.activities.SPApplication
 import com.supwisdom.bean.BaseResp
+import com.supwisdom.exception.WhiteListError
 import com.supwisdom.service.EpayApiImpl
+import com.supwisdom.utils.FileUtil
 import com.supwisdom.utils.PublicDef
 
 /**
@@ -53,16 +55,22 @@
     private inner class ClearWhiteList : AsyncTask<Void, Int, BaseResp>() {
         override fun onPostExecute(resp: BaseResp) {
             if (resp.retcode == PublicDef.SUCCESS) {
-                iManageView.showOperResult("黑名单更新成功", "")
+                iManageView.showOperResult("白名单更新成功", "")
             } else {
-                iManageView.showOperResult("黑名单更新失败", resp.retmsg!!)
+                iManageView.showOperResult("白名单更新失败", resp.retmsg!!)
             }
         }
 
         override fun doInBackground(vararg params: Void): BaseResp {
+            if (!pos.clearWhiteList()) {
+                return BaseResp(PublicDef.ERROR, "清空白名单失败")
+            }
+            val dyRecord = pos.getDynamicPara()
+            dyRecord!!.cardverno = "0"
+            pos.replaceDynamicPara(dyRecord)
             return try {
-                EpayApiImpl().downloadWhitelist("0")
-                BaseResp(PublicDef.ERROR, "更新成功")
+                EpayApiImpl().downloadWhitelist(dyRecord.whitelistid, "0")
+                BaseResp(PublicDef.SUCCESS, "更新成功")
             } catch (ex: Exception) {
                 BaseResp(PublicDef.ERROR, ex.message)
             }
@@ -72,13 +80,14 @@
     private inner class OutTransdtl : AsyncTask<Void, Int, BaseResp>() {
         override fun doInBackground(vararg params: Void): BaseResp {
             var num = 0
-//            val bm1List = pos.getTransdtlBM1(null)
-//            if (bm1List != null) {
-//                num += bm1List!!.size
-//                for (i in bm1List!!.indices) {
-//                    FileUtil.writeDtlFile(bm1List!!.get(i).toString())
-//                }
-//            }
+            pos.getTransdtlOnline().forEach {
+                num++
+                FileUtil.writeDtlFile(it.toString())
+            }
+            pos.getTransdtlOffline().forEach {
+                num++
+                FileUtil.writeDtlFile(it.toString())
+            }
             return BaseResp(PublicDef.SUCCESS, "共导出" + num + "笔")
         }
 
diff --git a/app/src/main/java/com/supwisdom/activities/syspara/SysparaActivity.kt b/app/src/main/java/com/supwisdom/activities/syspara/SysparaActivity.kt
index 6cf2a8e..ec0c647 100644
--- a/app/src/main/java/com/supwisdom/activities/syspara/SysparaActivity.kt
+++ b/app/src/main/java/com/supwisdom/activities/syspara/SysparaActivity.kt
@@ -58,16 +58,17 @@
 //        } else {
 //            kvMap[index++] = ControlParaRecord("长连接使能>>", "启用")
 //        }
-        if (SPApplication.getInstance().isOnline()) {
-            kvMap[index++] = ControlParaRecord("网络状态>>", "联机")
-        } else {
-            kvMap[index++] = ControlParaRecord("网络状态>>", "脱机")
-        }
+//        if (SPApplication.getInstance().isOnline()) {
+//            kvMap[index++] = ControlParaRecord("网络状态>>", "联机")
+//        } else {
+//            kvMap[index++] = ControlParaRecord("网络状态>>", "脱机")
+//        }
         kvMap[index++] = ControlParaRecord("成功显时间>>", "${sysRecord.sucShowtime}s")
         kvMap[index++] = ControlParaRecord("失败显时间>>", "${sysRecord.failShowtime}s")
         kvMap[index++] = ControlParaRecord("联机流水号>>", pos.getTransdtlOnlineMaxSeqno().toString())
         kvMap[index++] = ControlParaRecord("离线流水号>>", pos.getTransdtlOfflineMaxSeqno().toString())
         kvMap[index++] = ControlParaRecord("未上传流水>>", pos.getTransdtlUnconfirmNum().toString())
+        kvMap[index++] = ControlParaRecord("当天离线最大金额>>", String.format("%.02f元", sysRecord.maxDayOfflineAmt / 100.0f))
         kvMap[index++] = ControlParaRecord("定额间隔时间(s)>>", "${sysRecord.fixpayGap}s")
         kvMap[index++] = ControlParaRecord("心跳间隔>>", "${sysRecord.heatBeat}s")
     }
diff --git a/app/src/main/java/com/supwisdom/activities/transdtl/TransdtlActivity.kt b/app/src/main/java/com/supwisdom/activities/transdtl/TransdtlActivity.kt
index 2516bf6..35a0be7 100644
--- a/app/src/main/java/com/supwisdom/activities/transdtl/TransdtlActivity.kt
+++ b/app/src/main/java/com/supwisdom/activities/transdtl/TransdtlActivity.kt
@@ -27,6 +27,7 @@
     private var isSearching: Boolean = false
     @Volatile
     private var keyActive = true
+    private var hasdtlFlag = true
     private val MAX_SEARCH_NUM = 19
 
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -77,6 +78,9 @@
     }
 
     private fun moveNextSeqno() {
+        if (!hasdtlFlag) {
+            return
+        }
         var seqno = getShowSeqno()
         if (seqno > MAX_SEARCH_NUM) {
             return
@@ -107,6 +111,7 @@
 
     override fun onResume() {
         super.onResume()
+        hasdtlFlag = true
         keyActive = true
         refresh()
     }
@@ -114,6 +119,7 @@
     fun showTransdtlResult(record: TransdtlUnionRecord?) {
         isSearching = false
         if (record == null) {
+            hasdtlFlag = false
             vContent.text = "未找到消费记录"
             AuxScreenController.getInstance().refreshContent(
                 Arrays.asList<String>(
@@ -122,6 +128,7 @@
                 )
             )
         } else {
+            hasdtlFlag = true
             val transdatetime = StringBuilder()
             transdatetime.append(record.transdate!!.substring(0, 4)).append("-")
                 .append(record.transdate!!.substring(4, 6)).append("-")
diff --git a/app/src/main/java/com/supwisdom/bean/AuthRetBean.kt b/app/src/main/java/com/supwisdom/bean/AuthRetBean.kt
index b488ac6..560f8fd 100644
--- a/app/src/main/java/com/supwisdom/bean/AuthRetBean.kt
+++ b/app/src/main/java/com/supwisdom/bean/AuthRetBean.kt
@@ -12,5 +12,6 @@
     var offlineseqno: Int = 0
     var paraverno: Int = 0
     var paragroupid: Int = 0
+    var whitelistid: Int = 0
     var cardverno: String? = null
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/bean/HeartBeatRetBean.kt b/app/src/main/java/com/supwisdom/bean/HeartBeatRetBean.kt
index 2c68992..da5a8f2 100644
--- a/app/src/main/java/com/supwisdom/bean/HeartBeatRetBean.kt
+++ b/app/src/main/java/com/supwisdom/bean/HeartBeatRetBean.kt
@@ -9,4 +9,5 @@
     var paragroupid: Int = 0
     var paraverno: Int = 0
     var cardverno: String? = null
+    var whitelistid: Int = 0
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/db/BeanPropEnum.kt b/app/src/main/java/com/supwisdom/db/BeanPropEnum.kt
index a89d80e..1c90e59 100644
--- a/app/src/main/java/com/supwisdom/db/BeanPropEnum.kt
+++ b/app/src/main/java/com/supwisdom/db/BeanPropEnum.kt
@@ -11,6 +11,7 @@
         heatBeat,
         offlineEnable,
         maxOfflineDays,
+        maxDayOfflineAmt,
         mngpasswd,
         fixpayGap,
         consumeShowtime,
@@ -41,6 +42,7 @@
         offlineseqno,
         paraverno,
         paragroupid,
+        whitelistid,
         cardverno,
         jwt,
         jwtexpire,
@@ -107,4 +109,9 @@
         status,
         upflag
     }
+
+    enum class HotkeyPay {
+        key,
+        amount
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/db/DBParaHelper.kt b/app/src/main/java/com/supwisdom/db/DBParaHelper.kt
index 3617287..4862731 100644
--- a/app/src/main/java/com/supwisdom/db/DBParaHelper.kt
+++ b/app/src/main/java/com/supwisdom/db/DBParaHelper.kt
@@ -19,6 +19,7 @@
         val TABLE_NAME_DYNAMICPARA = "tb_dynamicpara"
         val TABLE_NAME_CONTROLPARA = "tb_controlpara"
         val TABLE_NAME_WHITELIST = "tb_whitelist"
+        val TABLE_NAME_HOTKEY = "tb_hotkey"
 
         private var instance: DBParaHelper? = null
         fun getInstance(context: Context): DBParaHelper {
@@ -37,6 +38,10 @@
     /**
      * SQL for create table
      */
+    private val CREATE_TABLE_NAME_HOTKEY = ("create table IF NOT EXISTS "
+            + TABLE_NAME_HOTKEY + " ( "
+            + BeanPropEnum.HotkeyPay.key + " integer primary key,"
+            + BeanPropEnum.HotkeyPay.amount + " integer)")
     private val CREATE_TABLE_NAME_WHITELIST = ("create table IF NOT EXISTS "
             + TABLE_NAME_WHITELIST + " ( "
             + BeanPropEnum.WhiteList.cardphyid + " varchar(32),"
@@ -62,6 +67,7 @@
             + BeanPropEnum.DynamicPara.offlineseqno + " integer, "
             + BeanPropEnum.DynamicPara.paraverno + " integer, "
             + BeanPropEnum.DynamicPara.paragroupid + " integer, "
+            + BeanPropEnum.DynamicPara.whitelistid + " integer, "
             + BeanPropEnum.DynamicPara.cardverno + " varchar(32),"
             + BeanPropEnum.DynamicPara.jwt + " varchar(254),"
             + BeanPropEnum.DynamicPara.jwtexpire + " varchar(16),"
@@ -74,6 +80,7 @@
             + BeanPropEnum.Syspara.heatBeat + " integer, "
             + BeanPropEnum.Syspara.offlineEnable + " integer, "
             + BeanPropEnum.Syspara.maxOfflineDays + " integer, "
+            + BeanPropEnum.Syspara.maxDayOfflineAmt + " integer, "
             + BeanPropEnum.Syspara.mngpasswd + " char(6), "
             + BeanPropEnum.Syspara.fixpayGap + " integer, "
             + BeanPropEnum.Syspara.consumeShowtime + " integer, "
@@ -91,10 +98,14 @@
         db.execSQL(CREATE_TABLE_NAME_DYNAMICPARA)
         db.execSQL(CREATE_TABLE_NAME_CONTROLPARA)
         db.execSQL(CREATE_TABLE_NAME_WHITELIST)
+        db.execSQL(CREATE_TABLE_NAME_HOTKEY)
     }
 
     override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
         if (oldVersion < newVersion) {
+            if (oldVersion < 2 && newVersion >= 2) {
+//                db.execSQL("alter table $TABLE_NAME_SYSPARA add column ${BeanPropEnum.Syspara.maxDayOfflineAmt} integer")
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/db/DynamicParaDao.kt b/app/src/main/java/com/supwisdom/db/DynamicParaDao.kt
index 5c6b0fb..a0fc815 100644
--- a/app/src/main/java/com/supwisdom/db/DynamicParaDao.kt
+++ b/app/src/main/java/com/supwisdom/db/DynamicParaDao.kt
@@ -91,6 +91,7 @@
         record.offlineseqno = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.DynamicPara.offlineseqno.toString()))
         record.paraverno = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.DynamicPara.paraverno.toString()))
         record.paragroupid = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.DynamicPara.paragroupid.toString()))
+        record.whitelistid = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.DynamicPara.whitelistid.toString()))
         record.cardverno = cursor.getString(cursor.getColumnIndex(BeanPropEnum.DynamicPara.cardverno.toString()))
         record.jwt = cursor.getString(cursor.getColumnIndex(BeanPropEnum.DynamicPara.jwt.toString()))
         record.jwtExpire = cursor.getString(cursor.getColumnIndex(BeanPropEnum.DynamicPara.jwtexpire.toString()))
@@ -110,6 +111,7 @@
         values.put(BeanPropEnum.DynamicPara.offlineseqno.toString(), record.offlineseqno)
         values.put(BeanPropEnum.DynamicPara.paraverno.toString(), record.paraverno)
         values.put(BeanPropEnum.DynamicPara.paragroupid.toString(), record.paragroupid)
+        values.put(BeanPropEnum.DynamicPara.whitelistid.toString(), record.whitelistid)
         values.put(BeanPropEnum.DynamicPara.cardverno.toString(), record.cardverno)
         values.put(BeanPropEnum.DynamicPara.jwt.toString(), record.jwt)
         values.put(BeanPropEnum.DynamicPara.token.toString(), record.token)
diff --git a/app/src/main/java/com/supwisdom/db/HotkeyPayDao.kt b/app/src/main/java/com/supwisdom/db/HotkeyPayDao.kt
new file mode 100644
index 0000000..3826967
--- /dev/null
+++ b/app/src/main/java/com/supwisdom/db/HotkeyPayDao.kt
@@ -0,0 +1,98 @@
+package com.supwisdom.db
+
+import android.content.ContentValues
+import android.content.Context
+import android.database.Cursor
+import com.supwisdom.entity.HotKeyPayRecord
+import java.util.concurrent.locks.Lock
+
+/**
+ ** create by zzq on 2019/9/4
+ ** @desc
+ **/
+class HotkeyPayDao constructor(context: Context) {
+    private val dbHelper = DBParaHelper.getInstance(context)
+    private val TABLE = DBParaHelper.TABLE_NAME_HOTKEY
+
+    fun getLock(): Lock {
+        return dbHelper.getLock()
+    }
+
+    fun replace(record: HotKeyPayRecord): Boolean {
+        val db = dbHelper.readableDatabase
+        val values = getContentValues(record)
+        try {
+            db.beginTransaction()
+            if (db.replace(TABLE, null, values) > 0) {
+                db.setTransactionSuccessful()
+                return true
+            }
+        } finally {
+            db.endTransaction()
+        }
+        return false
+    }
+
+    fun save(list: List<HotKeyPayRecord>): Boolean {
+        val db = dbHelper.writableDatabase
+        try {
+            db.beginTransaction()
+            if (db.delete(TABLE, null, null) < 0) {
+                return false
+            }
+            list.forEach {
+                val values = getContentValues(it)
+                if (db.insert(TABLE, null, values) <= 0) {
+                    return false
+                }
+            }
+            db.setTransactionSuccessful()
+            return true
+        } finally {
+            db.endTransaction()
+        }
+    }
+
+    fun get(): List<HotKeyPayRecord>? {
+        val db = dbHelper.readableDatabase
+        var cursor: Cursor? = null
+        try {
+            cursor = db.query(TABLE, null, null, null, null, null, null)
+            val list = ArrayList<HotKeyPayRecord>()
+            while (cursor != null && cursor.moveToNext()) {
+                list.add(getRecord(cursor))
+            }
+            return list
+        } finally {
+            cursor?.close()
+        }
+    }
+
+    fun clear(): Boolean {
+        val db = dbHelper.writableDatabase
+        try {
+            db.beginTransaction()
+            if (db.delete(TABLE, null, null) < 0) {
+                return false
+            }
+            db.setTransactionSuccessful()
+            return true
+        } finally {
+            db.endTransaction()
+        }
+    }
+
+    private fun getRecord(cursor: Cursor): HotKeyPayRecord {
+        val record = HotKeyPayRecord()
+        record.key = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.HotkeyPay.key.toString()))
+        record.amount = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.HotkeyPay.amount.toString()))
+        return record
+    }
+
+    private fun getContentValues(record: HotKeyPayRecord): ContentValues {
+        val values = ContentValues()
+        values.put(BeanPropEnum.HotkeyPay.key.toString(), record.key)
+        values.put(BeanPropEnum.HotkeyPay.amount.toString(), record.amount)
+        return values
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/db/Pos.kt b/app/src/main/java/com/supwisdom/db/Pos.kt
index 0f36600..00ae522 100644
--- a/app/src/main/java/com/supwisdom/db/Pos.kt
+++ b/app/src/main/java/com/supwisdom/db/Pos.kt
@@ -17,6 +17,7 @@
     private var sysRecord: SysParaRecord? = null
     private val controlParaDao = ControlParaDao(context)
     private val whiteListDao = WhiteListDao(context)
+    private val hotkeyPayDao = HotkeyPayDao(context)
     private val transdtlOnlineDao = TransdtlOnlineDao(sdContext)
     private val transdtlOfflineDao = TransdtlOfflineDao(sdContext)
     private val transdtlUnionDao = TransdtlUnionDao(sdContext)
@@ -54,6 +55,24 @@
         return cfgRecord
     }
 
+    fun saveHotkeyPay(list: List<HotKeyPayRecord>): Boolean {
+        try {
+            hotkeyPayDao.getLock().lock()
+            return hotkeyPayDao.save(list)
+        } finally {
+            hotkeyPayDao.getLock().unlock()
+        }
+    }
+
+    fun getHotkeyPay(): List<HotKeyPayRecord>? {
+        try {
+            hotkeyPayDao.getLock().lock()
+            return hotkeyPayDao.get()
+        } finally {
+            hotkeyPayDao.getLock().unlock()
+        }
+    }
+
     fun replaceControlPara(record: ControlParaRecord): Boolean {
         try {
             controlParaDao.getLock().lock()
@@ -149,6 +168,15 @@
         }
     }
 
+    fun clearWhiteList(): Boolean {
+        try {
+            whiteListDao.getLock().lock()
+            return whiteListDao.clear()
+        } finally {
+            whiteListDao.getLock().unlock()
+        }
+    }
+
     fun getTransdtlOnlineMaxSeqno(): Int {
         if (onlMaxSeqno == 0) {
             try {
@@ -170,6 +198,15 @@
         }
     }
 
+    fun getTransdtlOnline(): List<TransdtlOnlineRecord> {
+        try {
+            transdtlOnlineDao.getLock().lock()
+            return transdtlOnlineDao.getAll()
+        } finally {
+            transdtlOnlineDao.getLock().unlock()
+        }
+    }
+
     fun getTransdtlOnlineUnconfirm(): List<TransdtlOnlineRecord> {
         try {
             transdtlOnlineDao.getLock().lock()
@@ -248,6 +285,24 @@
         }
     }
 
+    fun getTransdtlOffline(): List<TransdtlOfflineRecord> {
+        try {
+            transdtlOfflineDao.getLock().lock()
+            return transdtlOfflineDao.getAll()
+        } finally {
+            transdtlOfflineDao.getLock().unlock()
+        }
+    }
+
+    fun getTransdtlOfflineAmt(date: String, cardno: String, cardphyid: String): Int {
+        try {
+            transdtlOfflineDao.getLock().lock()
+            return transdtlOfflineDao.getOfflineAmt(date, cardno, cardphyid)
+        } finally {
+            transdtlOfflineDao.getLock().unlock()
+        }
+    }
+
     fun getTransdtlOfflineLast(): TransdtlOfflineRecord? {
         try {
             transdtlOfflineDao.getLock().lock()
diff --git a/app/src/main/java/com/supwisdom/db/SysParaDao.kt b/app/src/main/java/com/supwisdom/db/SysParaDao.kt
index 14872aa..50de288 100644
--- a/app/src/main/java/com/supwisdom/db/SysParaDao.kt
+++ b/app/src/main/java/com/supwisdom/db/SysParaDao.kt
@@ -47,7 +47,6 @@
         } finally {
             db.endTransaction()
         }
-        return false
     }
 
     fun get(): SysParaRecord? {
@@ -88,6 +87,7 @@
         val enable = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.Syspara.offlineEnable.toString()))
         record.offlineEnable = enable == 1
         record.maxOfflineDays = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.Syspara.maxOfflineDays.toString()))
+        record.maxDayOfflineAmt = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.Syspara.maxDayOfflineAmt.toString()))
         record.mngPasswd = cursor.getString(cursor.getColumnIndex(BeanPropEnum.Syspara.mngpasswd.toString()))
         record.fixpayGap = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.Syspara.fixpayGap.toString()))
         record.sucShowtime = cursor.getInt(cursor.getColumnIndex(BeanPropEnum.Syspara.consumeShowtime.toString()))
@@ -108,6 +108,7 @@
             values.put(BeanPropEnum.Syspara.offlineEnable.toString(), 0)
         }
         values.put(BeanPropEnum.Syspara.maxOfflineDays.toString(), record.maxOfflineDays)
+        values.put(BeanPropEnum.Syspara.maxDayOfflineAmt.toString(), record.maxDayOfflineAmt)
         values.put(BeanPropEnum.Syspara.mngpasswd.toString(), record.mngPasswd)
         values.put(BeanPropEnum.Syspara.fixpayGap.toString(), record.fixpayGap)
         values.put(BeanPropEnum.Syspara.consumeShowtime.toString(), record.sucShowtime)
diff --git a/app/src/main/java/com/supwisdom/db/TransdtlOfflineDao.kt b/app/src/main/java/com/supwisdom/db/TransdtlOfflineDao.kt
index fb9d0c0..8669aa8 100644
--- a/app/src/main/java/com/supwisdom/db/TransdtlOfflineDao.kt
+++ b/app/src/main/java/com/supwisdom/db/TransdtlOfflineDao.kt
@@ -56,6 +56,61 @@
         return false
     }
 
+    fun getAll(): List<TransdtlOfflineRecord> {
+        val db = dbHelper.readableDatabase
+        var cursor: Cursor? = null
+        val orderby = BeanPropEnum.TransdtlOffline.devseqno.toString() + " desc"
+        try {
+            cursor = db.query(TABLE, null, null, null, null, null, orderby)
+            val list = ArrayList<TransdtlOfflineRecord>()
+            while (cursor != null && cursor.moveToNext()) {
+                list.add(getRecord(cursor))
+            }
+            return list
+        } finally {
+            cursor?.close()
+        }
+    }
+
+    fun getOfflineAmt(date: String, cardno: String, cardphyid: String): Int {
+        val db = dbHelper.readableDatabase
+        var cursor: Cursor? = null
+        var sql = ("select sum(${BeanPropEnum.TransdtlOffline.payamt}) as sumamt from $TABLE where "
+                + BeanPropEnum.TransdtlOffline.transdate.toString() + "='" + date + "' and "
+                + BeanPropEnum.TransdtlOffline.cardno.toString() + "='" + cardno + "' and "
+                + BeanPropEnum.TransdtlOffline.cardphyid.toString() + "='" + cardphyid + "' and "
+                + BeanPropEnum.TransdtlOffline.reversalflag.toString() + "='" + ReversalFlag.NONE.toString() + "' and "
+                + BeanPropEnum.TransdtlOffline.status.toString() + "='" + PayStatus.SUC.toString() + "'")
+        var sumamt = 0
+        try {
+            cursor = db.rawQuery(sql, null, null)
+            if (cursor != null && cursor.moveToNext()) {
+                sumamt = cursor.getInt(cursor.getColumnIndex("sumamt"))
+            }
+        } finally {
+            cursor?.close()
+        }
+
+        sql = ("select sum(${BeanPropEnum.TransdtlOffline.payamt}) as sumamt from $TABLE where "
+                + BeanPropEnum.TransdtlOffline.transdate.toString() + "='" + date + "' and "
+                + BeanPropEnum.TransdtlOffline.cardno.toString() + "='" + cardno + "' and "
+                + BeanPropEnum.TransdtlOffline.cardphyid.toString() + "='" + cardphyid + "' and "
+                + BeanPropEnum.TransdtlOffline.reversalflag.toString() + "<>'" + ReversalFlag.NONE.toString() + "' and "
+                + BeanPropEnum.TransdtlOffline.status.toString() + "='" + PayStatus.SUC.toString() + "'")
+        try {
+            cursor = db.rawQuery(sql, null, null)
+            if (cursor != null && cursor.moveToNext()) {
+                val reverse = cursor.getInt(cursor.getColumnIndex("sumamt"))
+                if (sumamt > reverse) {
+                    return (sumamt - reverse)
+                }
+            }
+        } finally {
+            cursor?.close()
+        }
+        return 0
+    }
+
     fun getUnconfirm(): List<TransdtlOfflineRecord> {
         val db = dbHelper.readableDatabase
         var cursor: Cursor? = null
diff --git a/app/src/main/java/com/supwisdom/db/TransdtlOnlineDao.kt b/app/src/main/java/com/supwisdom/db/TransdtlOnlineDao.kt
index 78a4328..0a76b2b 100644
--- a/app/src/main/java/com/supwisdom/db/TransdtlOnlineDao.kt
+++ b/app/src/main/java/com/supwisdom/db/TransdtlOnlineDao.kt
@@ -56,6 +56,22 @@
         return false
     }
 
+    fun getAll(): List<TransdtlOnlineRecord> {
+        val db = dbHelper.readableDatabase
+        var cursor: Cursor? = null
+        val orderby = BeanPropEnum.TransdtlOnline.devseqno.toString() + " desc"
+        try {
+            cursor = db.query(TABLE, null, null, null, null, null, orderby)
+            val list = ArrayList<TransdtlOnlineRecord>()
+            while (cursor != null && cursor.moveToNext()) {
+                list.add(getRecord(cursor))
+            }
+            return list
+        } finally {
+            cursor?.close()
+        }
+    }
+
     fun getUnconfirm(): List<TransdtlOnlineRecord> {
         val db = dbHelper.readableDatabase
         var cursor: Cursor? = null
diff --git a/app/src/main/java/com/supwisdom/entity/DynamicParaRecord.kt b/app/src/main/java/com/supwisdom/entity/DynamicParaRecord.kt
index bee1dbe..9780e62 100644
--- a/app/src/main/java/com/supwisdom/entity/DynamicParaRecord.kt
+++ b/app/src/main/java/com/supwisdom/entity/DynamicParaRecord.kt
@@ -12,6 +12,7 @@
     var shopname: String? = null //商户名
     var paraverno: Int = 0//参数版本
     var paragroupid: Int = 0//参数组id
+    var whitelistid: Int = 0 //白名单组id
     var onlineseqno: Int = 0 //后台最大联机流水号
     var offlineseqno: Int = 0 //后台最大离线流水号
     var cardverno: String? = null // 黑名单版本号 12byte
diff --git a/app/src/main/java/com/supwisdom/entity/HotKeyPayRecord.kt b/app/src/main/java/com/supwisdom/entity/HotKeyPayRecord.kt
new file mode 100644
index 0000000..4d8bb24
--- /dev/null
+++ b/app/src/main/java/com/supwisdom/entity/HotKeyPayRecord.kt
@@ -0,0 +1,11 @@
+package com.supwisdom.entity
+
+/**
+ ** create by zzq on 2019/9/5
+ ** @desc
+ **/
+class HotKeyPayRecord {
+    var key: Int = 0
+    var amount: Int = 0
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/entity/SysParaRecord.kt b/app/src/main/java/com/supwisdom/entity/SysParaRecord.kt
index 65e1640..8829b75 100644
--- a/app/src/main/java/com/supwisdom/entity/SysParaRecord.kt
+++ b/app/src/main/java/com/supwisdom/entity/SysParaRecord.kt
@@ -9,6 +9,7 @@
     var heatBeat: Int = 0// 心跳间隔
     var offlineEnable: Boolean = false // 脱机消费时限开关  false-关闭, true-开启
     var maxOfflineDays: Int = 0// 最大脱机天数
+    var maxDayOfflineAmt: Int = 0//同卡当天离线交易最大金额
     var mngPasswd: String? = null// 维护密码
     var sucShowtime: Int = 0// 消费成功显示时间
     var failShowtime: Int = 0 //消费失败显示时间
diff --git a/app/src/main/java/com/supwisdom/entity/TransdtlOfflineRecord.kt b/app/src/main/java/com/supwisdom/entity/TransdtlOfflineRecord.kt
index 347d10a..a471c8f 100644
--- a/app/src/main/java/com/supwisdom/entity/TransdtlOfflineRecord.kt
+++ b/app/src/main/java/com/supwisdom/entity/TransdtlOfflineRecord.kt
@@ -27,4 +27,16 @@
         val tmp = GsonUtil.GsonString(this)
         return GsonUtil.GsonToBean(tmp, TransdtlOfflineRecord::class.java)
     }
+
+    override fun toString(): String {
+        val sb = StringBuilder()
+        sb.append("离线流水:").append("devphyid=").append(devphyid).append(",transdate=").append(transdate)
+            .append(",transtime=").append(transtime).append(",seqno=").append(devseqno).append(",cardno=")
+            .append(cardno).append(",payamt=").append(payamt).append(",extraamt=").append(extraamt)
+            .append(",managefeetype=").append(managefeetype).append(",reversalflag=").append(reversalflag)
+            .append(",reversalseqno=").append(reversalseqno).append(",reversaltransdate=").append(reversaltransdate)
+            .append(",reversaltranstime=").append(reversaltranstime).append(",status=").append(status)
+            .append(",upflag=").append(upflag)
+        return sb.toString()
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/entity/TransdtlOnlineRecord.kt b/app/src/main/java/com/supwisdom/entity/TransdtlOnlineRecord.kt
index 584e629..841ca3a 100644
--- a/app/src/main/java/com/supwisdom/entity/TransdtlOnlineRecord.kt
+++ b/app/src/main/java/com/supwisdom/entity/TransdtlOnlineRecord.kt
@@ -29,4 +29,16 @@
         val tmp = GsonUtil.GsonString(this)
         return GsonUtil.GsonToBean(tmp, TransdtlOnlineRecord::class.java)
     }
+
+    override fun toString(): String {
+        val sb = StringBuilder()
+        sb.append("联机流水:").append("devphyid=").append(devphyid).append(",transdate=").append(transdate)
+            .append(",transtime=").append(transtime).append(",seqno=").append(devseqno).append(",cardno=")
+            .append(cardno).append(",code=").append(qrcode).append(",transtype=").append(transtype)
+            .append(",payamt=").append(payamt).append(",extraamt=").append(extraamt).append(",managefeetype")
+            .append(managefeetype).append(",username=").append(username).append(",billno=").append(billno)
+            .append(",reversalflag=").append(reversalflag).append(",reversalbillno=").append(reversalbillno)
+            .append(",status=").append(status).append(",upflag=").append(upflag)
+        return sb.toString()
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/supwisdom/service/APIInterface.kt b/app/src/main/java/com/supwisdom/service/APIInterface.kt
index b24df22..4c970a2 100644
--- a/app/src/main/java/com/supwisdom/service/APIInterface.kt
+++ b/app/src/main/java/com/supwisdom/service/APIInterface.kt
@@ -14,7 +14,7 @@
 
     fun downloadSyspara(paragroupid: Int, paraverno: Int)
 
-    fun downloadWhitelist(maxCardverno: String)
+    fun downloadWhitelist(whitelistid: Int, maxCardverno: String)
 
     fun uploadTransdtl(record: TransdtlOnlineRecord)
 
diff --git a/app/src/main/java/com/supwisdom/service/AuthEpay.kt b/app/src/main/java/com/supwisdom/service/AuthEpay.kt
index 8c28078..6fe9a3e 100644
--- a/app/src/main/java/com/supwisdom/service/AuthEpay.kt
+++ b/app/src/main/java/com/supwisdom/service/AuthEpay.kt
@@ -87,7 +87,7 @@
             .append("/").append(record.epayUri)
             .append("/api/auth/authentication/").append(record.devphyid).append("?")
 
-        val secret = CryptUtil.HMACSHA256(pos.getDynamicPara()!!.appsecret!!, token)
+        val secret = CryptUtil.HMACSHA256(token, pos.getDynamicPara()!!.appsecret!!)
         val params = WebParams()
         params.setParameter("appid", pos.getDynamicPara()!!.appid)
             .setParameter("secret", secret)
diff --git a/app/src/main/java/com/supwisdom/service/EpayApiImpl.kt b/app/src/main/java/com/supwisdom/service/EpayApiImpl.kt
index 0cdffea..8b359b0 100644
--- a/app/src/main/java/com/supwisdom/service/EpayApiImpl.kt
+++ b/app/src/main/java/com/supwisdom/service/EpayApiImpl.kt
@@ -48,13 +48,6 @@
         if (retBean.retcode != PublicDef.SUCCESS) {
             throw HeartBeatError(retBean.getErrorMsg())
         }
-        if (cardverno < retBean.cardverno!!) {
-            try {
-                downloadWhitelist(retBean.cardverno!!)
-            } catch (ex: WhiteListError) {
-                throw HeartBeatError(ex.message ?: "null")
-            }
-        }
         if (dyRecord.paraverno != retBean.paraverno) {
             try {
                 downloadSyspara(retBean.paragroupid, retBean.paraverno)
@@ -62,6 +55,15 @@
                 throw HeartBeatError(ex.message ?: "null")
             }
         }
+        if (dyRecord.whitelistid != retBean.whitelistid ||
+            cardverno < retBean.cardverno!!
+        ) {
+            try {
+                downloadWhitelist(retBean.whitelistid, retBean.cardverno!!)
+            } catch (ex: WhiteListError) {
+                throw HeartBeatError(ex.message ?: "null")
+            }
+        }
         /**
          * 时钟校准
          */
@@ -105,6 +107,7 @@
                 it.paraname == "manage_passwd" -> record.mngPasswd = it.paraval
                 it.paraname == "offline_flag" -> record.offlineEnable = it.paraval == "1"
                 it.paraname == "max_offline_days" -> record.maxOfflineDays = it.paraval!!.toInt()
+                it.paraname == "max_day_offline_amt" -> record.maxDayOfflineAmt = it.paraval!!.toInt()
                 it.paraname == "communicate_time" -> record.commTime = it.paraval!!.toInt()
             }
         }
@@ -120,13 +123,36 @@
         if (record.commTime == 0) {
             record.commTime = 3
         }
+        if (record.maxDayOfflineAmt == 0) {
+            record.maxDayOfflineAmt = 10000
+        }
         if (!pos.replaceSysPara(record)) {
             throw SysParaError("保存参数失败")
         }
+        val dyRecord = pos.getDynamicPara()
+        dyRecord!!.paraverno = paraverno
+        dyRecord.paragroupid = paragroupid
+        if (!pos.replaceDynamicPara(dyRecord)) {
+            throw SysParaError("保存参数失败")
+        }
     }
 
     @Throws(WhiteListError::class)
-    override fun downloadWhitelist(maxCardverno: String) {
+    override fun downloadWhitelist(whitelistid: Int, maxCardverno: String) {
+        var dyRecord = pos.getDynamicPara()
+        /**
+         * 白名单组ID变化清空本地白名单重新下载
+         */
+        if (dyRecord!!.whitelistid != whitelistid) {
+            if (!pos.clearWhiteList()) {
+                throw WhiteListError("清空白名单失败")
+            }
+            dyRecord.cardverno = "0"
+            dyRecord.whitelistid = whitelistid
+            if (!pos.replaceDynamicPara(dyRecord)) {
+                throw WhiteListError("保存参数失败")
+            }
+        }
         val maxcount = 20
         do {
             val params = WebParams()
@@ -161,7 +187,7 @@
             if (!pos.saveWhiteList(list)) {
                 throw WhiteListError("保存白名单失败")
             }
-            val dyRecord = pos.getDynamicPara()
+            dyRecord = pos.getDynamicPara()
             dyRecord!!.cardverno = retBean.cardverno
             if (!pos.replaceDynamicPara(dyRecord)) {
                 throw WhiteListError("保存参数失败")
diff --git a/app/src/main/java/com/supwisdom/utils/PublicDef.kt b/app/src/main/java/com/supwisdom/utils/PublicDef.kt
index b7c482f..140f9a8 100644
--- a/app/src/main/java/com/supwisdom/utils/PublicDef.kt
+++ b/app/src/main/java/com/supwisdom/utils/PublicDef.kt
@@ -76,10 +76,7 @@
     const val CONTROL_FIXAMT = "fixamt"
     const val CONTROL_OFFLINE_DAY_DISABLE = "offdaydisable"
     const val CONTROL_DEBUG_ENABLE = "debugenable"
-    /**
-     * 非定额消费标识
-     */
-    const val CONTROL_NO_FIXPAY_FLAG = "none"
+
     /**
      * 消费冲正时限
      */
diff --git a/app/src/main/java/com/supwisdom/view/DialogPurchase.kt b/app/src/main/java/com/supwisdom/view/DialogPurchase.kt
index a03f510..fa71710 100644
--- a/app/src/main/java/com/supwisdom/view/DialogPurchase.kt
+++ b/app/src/main/java/com/supwisdom/view/DialogPurchase.kt
@@ -1,6 +1,7 @@
 package com.supwisdom.view
 
 import android.content.Context
+import android.content.Intent
 import android.graphics.Color
 import android.os.CountDownTimer
 import android.view.KeyEvent
@@ -11,6 +12,8 @@
 import com.newcapec.zxinglib.PosDecoder
 import com.supwisdom.R
 import com.supwisdom.activities.consume.bean.CardUserInfoBean
+import com.supwisdom.activities.menu.MenuActivity
+import com.supwisdom.activities.transdtl.TransdtlActivity
 import com.supwisdom.utils.CommonUtil
 import com.supwisdom.utils.LogUtil
 
@@ -73,11 +76,17 @@
                         finish(isManualCancel = true, isPaying = false)
                     }
                 }
+                KeyEvent.KEYCODE_DPAD_LEFT -> jumpActivity(MenuActivity::class.java)
+                KeyEvent.KEYCODE_DPAD_RIGHT -> jumpActivity(TransdtlActivity::class.java)
             }
         }
         return super.dispatchKeyEvent(event)
     }
 
+    private fun <T> jumpActivity(cls: Class<T>) {
+        context.startActivity(Intent(context, cls))
+    }
+
     fun show(hint: String, amount: String) {
         vPayhint.text = hint
         vPayhint.setTextColor(context.resources.getColor(R.color.blue))
diff --git a/app/src/main/res/drawable/corner_bg_blue.xml b/app/src/main/res/drawable/corner_bg_blue.xml
new file mode 100644
index 0000000..8619a1d
--- /dev/null
+++ b/app/src/main/res/drawable/corner_bg_blue.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/light_blue2" />
+    <corners android:radius="8dip" />
+    <stroke
+            android:width="1.0dip"
+            android:color="@color/light_blue2" />
+</shape>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_consume_mode.xml b/app/src/main/res/layout/activity_consume_mode.xml
index 99e494f..653add6 100644
--- a/app/src/main/res/layout/activity_consume_mode.xml
+++ b/app/src/main/res/layout/activity_consume_mode.xml
@@ -1,44 +1,127 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/head_title_out_style">
+              style="@style/head_title_out_style">
 
     <LinearLayout style="@style/head_title_inner_style">
 
         <TextView
-            style="@style/head_title_text_style"
-            android:text="消费模式" />
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:padding="10dp"
-            android:text="0-普通消费\n非0定额消费\n单位(分)"
-            android:textColor="@color/light_blue2"
-            android:textSize="20sp" />
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal">
-
-            <TextView
-                android:layout_width="wrap_content"
+                style="@style/head_title_text_style"
+                android:text="消费模式"/>
+        <RadioGroup
+                android:visibility="gone"
                 android:layout_height="wrap_content"
-                android:padding="10dp"
-                android:text="金额: "
-                android:textColor="@color/light_blue2"
-                android:textSize="30sp" />
-
-            <TextView
-                android:id="@+id/tv_consume_mode_payamt"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:maxLength="6"
+                android:orientation="vertical">
+            <RadioButton
+                    android:id="@+id/rb_normal_mode"
+                    android:text="普通消费"
+                    style="@style/consume_mode_rb_style"
+                    android:checked="true"/>
+            <RadioButton
+                    android:id="@+id/rb_fix_mode"
+                    android:text="定额消费"
+                    style="@style/consume_mode_rb_style"/>
+            <RadioButton
+                    android:id="@+id/rb_hot_mode"
+                    android:text="快捷消费"
+                    style="@style/consume_mode_rb_style"/>
+        </RadioGroup>
+        <LinearLayout
+                android:id="@+id/ll_fix_mode"
+                android:visibility="gone"
+                android:orientation="vertical"
                 android:padding="10dp"
-                android:text="0"
-                android:textColor="@color/light_blue2"
-                android:textSize="30sp" />
-        </LinearLayout>
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="普通消费(none)"
+                    android:textColor="@color/light_blue2"
+                    android:textSize="20sp"/>
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="定额消费(单位:元)"
+                    android:textColor="@color/light_blue2"
+                    android:textSize="20sp"/>
 
+            <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:orientation="horizontal">
+
+                <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="金额: "
+                        android:textColor="@color/light_blue2"
+                        android:textSize="30sp"/>
+
+                <TextView
+                        android:id="@+id/tv_consume_mode_payamt"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:maxLength="8"
+                        android:text="0"
+                        android:textColor="@color/light_blue2"
+                        android:textSize="30sp"/>
+            </LinearLayout>
+        </LinearLayout>
+        <LinearLayout
+                android:id="@+id/ll_hot_mode"
+                android:orientation="vertical"
+                android:padding="10dp"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+            <LinearLayout
+                    android:orientation="horizontal"
+                    android:gravity="center"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content">
+                <TextView
+                        android:id="@+id/tv_return"
+                        android:textSize="25sp"
+                        android:text="返回"
+                        android:background="@drawable/corner_bg_blue"
+                        android:padding="10dp"
+                        android:textColor="@color/white"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"/>
+                <TextView
+                        android:id="@+id/tv_hot_save"
+                        android:textSize="25sp"
+                        android:layout_marginLeft="50dp"
+                        android:text="保存"
+                        android:background="@drawable/corner_bg_blue"
+                        android:padding="10dp"
+                        android:textColor="@color/white"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"/>
+                <TextView
+                        android:id="@+id/tv_hot_add"
+                        android:textSize="25sp"
+                        android:text="添加"
+                        android:layout_marginLeft="50dp"
+                        android:background="@drawable/corner_bg_blue"
+                        android:padding="10dp"
+                        android:textColor="@color/white"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"/>
+            </LinearLayout>
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="快捷消费(单位:元)"
+                    android:layout_marginTop="10dp"
+                    android:textColor="@color/light_blue2"
+                    android:textSize="20sp"/>
+            <LinearLayout
+                    android:id="@+id/ll_hot_list"
+                    android:layout_width="match_parent"
+                    android:orientation="vertical"
+                    android:layout_height="match_parent"/>
+
+        </LinearLayout>
     </LinearLayout>
 </LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_hotkey_pay.xml b/app/src/main/res/layout/item_hotkey_pay.xml
new file mode 100644
index 0000000..060a897
--- /dev/null
+++ b/app/src/main/res/layout/item_hotkey_pay.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="horizontal"
+              android:background="@color/white"
+              android:layout_width="match_parent"
+              android:weightSum="5"
+              android:padding="5dp"
+              android:layout_marginTop="10dp"
+              android:layout_height="match_parent">
+    <TextView
+            android:layout_height="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:text="快捷键: "
+            android:textColor="@color/light_blue2"
+            android:textSize="25sp"/>
+    <TextView
+            android:id="@+id/tv_hot_key"
+            android:layout_height="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:text="1"
+            android:textColor="@color/cl_red"
+            android:textSize="25sp"/>
+    <EditText
+            android:id="@+id/tv_hot_amount"
+            android:layout_height="wrap_content"
+            android:layout_width="0dp"
+            android:inputType="numberDecimal"
+            android:layout_weight="2"
+            android:maxLines="1"
+            android:text="0"
+            android:textColor="@color/light_blue2"
+            android:textSize="25sp"/>
+    <TextView
+            android:id="@+id/tv_hot_del"
+            android:layout_height="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:text="删除"
+            android:layout_marginLeft="10dp"
+            android:gravity="center"
+            android:padding="10dp"
+            android:background="@drawable/corner_bg_blue"
+            android:textColor="@color/white"
+            android:textSize="25sp"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 123c964..d85e0af 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -426,7 +426,12 @@
         <item name="android:textColor">@color/black</item>
         <item name="android:gravity">center</item>
     </style>
-
+    <style name="consume_mode_rb_style">
+        <item name="android:layout_height">wrap_content</item>
+        <item name="android:layout_width">match_parent</item>
+        <item name="android:textSize">25sp</item>
+        <item name="android:textColor">@color/light_blue2</item>
+    </style>
     <style name="consume_pay_way_text_style">
         <item name="android:layout_height">wrap_content</item>
         <item name="android:layout_width">match_parent</item>
diff --git a/platform.pk8 b/platform.pk8
new file mode 100644
index 0000000..e27a393
--- /dev/null
+++ b/platform.pk8
Binary files differ
diff --git a/platform.x509.pem b/platform.x509.pem
new file mode 100644
index 0000000..087f02e
--- /dev/null
+++ b/platform.x509.pem
@@ -0,0 +1,27 @@
+-----BEGIN CERTIFICATE-----
+MIIEqDCCA5CgAwIBAgIJALOZgIbQVs/6MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD
+VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
+VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
+AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
+Fw0wODA0MTUyMjQwNTBaFw0zNTA5MDEyMjQwNTBaMIGUMQswCQYDVQQGEwJVUzET
+MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
+A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
+ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
+hvcNAQEBBQADggENADCCAQgCggEBAJx4BZKsDV04HN6qZezIpgBuNkgMbXIHsSAR
+vlCGOqvitV0Amt9xRtbyICKAx81Ne9smJDuKgGwms0sTdSOkkmgiSQTcAUk+fArP
+GgXIdPabA3tgMJ2QdNJCgOFrrSqHNDYZUer3KkgtCbIEsYdeEqyYwap3PWgAuer9
+5W1Yvtjo2hb5o2AJnDeoNKbf7be2tEoEngeiafzPLFSW8s821k35CjuNjzSjuqtM
+9TNxqydxmzulh1StDFP8FOHbRdUeI0+76TybpO35zlQmE1DsU1YHv2mi/0qgfbX3
+6iANCabBtJ4hQC+J7RGQiTqrWpGA8VLoL4WkV1PPX8GQccXuyCcCAQOjgfwwgfkw
+HQYDVR0OBBYEFE/koLPdnLop9x1yh8Tnw48ghsKZMIHJBgNVHSMEgcEwgb6AFE/k
+oLPdnLop9x1yh8Tnw48ghsKZoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
+QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
+CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJALOZgIbQVs/6MAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBAFclUbjZOh9z3g9tRp+G2tZwFAAp
+PIigzXzXeLc9r8wZf6t25iEuVsHHYc/EL9cz3lLFCuCIFM78CjtaGkNGBU2Cnx2C
+tCsgSL+ItdFJKe+F9g7dEtctVWV+IuPoXQTIMdYT0Zk4u4mCJH+jISVroS0dao+S
+6h2xw3Mxe6DAN/DRr/ZFrvIkl5+6bnoUvAJccbmBOM7z3fwFlhfPJIRc97QNY4L3
+J17XOElatuWTG5QhdlxJG3L7aOCA29tYwgKdNHyLMozkPvaosVUz7fvpib1qSN1L
+IC7alMarjdW4OZID2q4u1EYjLk/pvZYTlMYwDlE448/Shebk5INTjLixs1c=
+-----END CERTIFICATE-----
diff --git a/signapk.jar b/signapk.jar
new file mode 100644
index 0000000..4951807
--- /dev/null
+++ b/signapk.jar
Binary files differ
diff --git a/upgrade.py b/upgrade.py
index 6a2ec3c..957fed9 100644
--- a/upgrade.py
+++ b/upgrade.py
@@ -37,7 +37,10 @@
 	zf.close()
 
 if __name__ == '__main__':
-	appFile = './app/release/app-release.apk'
+	if len(sys.argv) < 2:
+		print('miss parameter:app path!!!')
+		exit(1)
+	appFile = sys.argv[1]
 	print('appFile = ' + appFile)
 	
 	if not path.exists(appFile):