_d-71
z*%c>$*Q;tqPL#*mnN<)yDMfD_x<4E(;_p0^@1yMzA@mFv3dSGXnP|?3{F!YQ7_>|u
z`EVL)Aslh>Uw#|+zhT0Qf<=S>vPMkZX}|*K7xiZ>07h;A>;H*1n`GD7=LrHX8(Wq+
z-lwd|&9y&gDwOhV1dukk>cqp2?Jgdc=q2c
zJ-9Q_4l4saooKLDL^sJ7P}<}@bT~*rvAa8P0TfEfd&5&6yJ4_Ra3>)*lgdF5w>Vh5
z8t{t}fx{sVX~Cz682DaN+Oc&YM}qwoUQ%7e;mR?a(c
z$vK3=u*w~?*Sk!9HM>aKq%*~g@1voTIex&$UBn!Yg#<3)n!^xsu+RqUZEXAH&Z#y5
zHqD6dKi&ScxUDQ^iK}5z?}xHp77$Q#-QLA-t4wo5prUl%*Sx&J6kwubhkk?(^>=CB!EykE5B)O6
z@ltpem5Kx7+eR?purPId*WmUr>z4fyU>K_KW-99peoouy)QJc;GD}1u+bI};UzfvC
z=C@;LHGZsp#|R(T>m#1-C{Xf({)b~Xw|ZT!fO-FD!45+=PB29znNcVlcdv(J>hR&1!!L+I^YVV-$W*`p270D
+
+
+
+
\ No newline at end of file
diff --git a/pos_android_studio_demo/pos_android_app/src/main/res/values/strings.xml b/pos_android_studio_demo/pos_android_app/src/main/res/values/strings.xml
index be0d33d7..0ed9618a 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/res/values/strings.xml
+++ b/pos_android_studio_demo/pos_android_app/src/main/res/values/strings.xml
@@ -194,6 +194,7 @@
Card error
Declined
Please enter amount
+ Enter amount
Incorrect PIN
Please insert card
Not accepted
@@ -459,7 +460,22 @@
content MaxHeight
- 欢迎光临(Simplified Chinese)\n歡迎光臨(traditional chinese)\nWelcome(English)\n어서 오세요.(Korean)\nいらっしゃいませ(Japanese)\nWillkommen in der(Germany)\nSouhaits de bienvenue(France)\nยินดีต้อนรับสู่(Thai)\nДобро пожаловать(Russian)\nBenvenuti a(Italian)\nvítejte v(Czech)\nBEM - vindo Ao(Portutuese)\nمرحبا بكم في(Arabic)\nBienvenido,transacción(Spanish)\nخوش اومدی(Farsi)\n
+ 欢迎光临(Simplified Chinese)
+歡迎光臨(traditional chinese)
+Welcome(English)
+어서 오세요.(Korean)
+いらっしゃいませ(Japanese)
+Willkommen in der(Germany)
+Souhaits de bienvenue(France)
+ยินดีต้อนรับสู่(Thai)
+Добро пожаловать(Russian)
+Benvenuti a(Italian)
+vítejte v(Czech)
+BEM - vindo Ao(Portutuese)
+مرحبا بكم في(Arabic)
+Bienvenido,transacción(Spanish)
+خوش اومدی(Farsi)
+
LEFT
RIGHT
CENTER
@@ -556,4 +572,38 @@
PLS SEE PHONE, and pls wait for cardholder to confirm, then to try again
Transaction failed because of the network!
+
+
+
+
+ Connected
+ Disconnected
+ No secondary display detected, please connect a secondary display device
+
+ %1$s succeeded
+ %1$s failed: secondary display not connected
+ %1$s failed: invalid parameter
+ %1$s failed: file not found
+ %1$s failed: hardware not supported
+ %1$s failed: display error
+ %1$s failed: code=%2$d
+
+ Secondary display not connected
+ Secondary #%1$d · %2$d × %3$d
+ Refresh rate: %1$.0f Hz
+ Landscape
+ Portrait
+ Type: %1$s
+ Touch: %1$s
+ Supported
+ Not reported
+ Supported modes: %1$d · current: %2$dx%3$d@%4$.0fHz
+ Name: %1$s
+ Secure
+ Presentation
+ Round
+ Touch
+ Not focusable
+ Standard display
+
\ No newline at end of file
From dd3ca3a3c0998bec2c8e448a7b025edfbbd029a6 Mon Sep 17 00:00:00 2001
From: ouyangwanli
Date: Tue, 15 Sep 2026 19:55:10 +0800
Subject: [PATCH 2/7] fix: add vic screen logic
---
.../dualScreen/view/AmountDisplayView.java | 97 ++++++++++++
.../com/dspread/pos/ui/home/HomeFragment.java | 9 +-
.../pos/ui/payment/PaymentActivity.java | 36 ++++-
.../pos/ui/payment/PaymentMethodActivity.java | 142 ++++++++++++++++++
.../pos/ui/payment/PaymentResultView.java | 82 ++++++++++
.../pos/ui/payment/PaymentStatusActivity.java | 16 +-
.../pos/ui/payment/ProcessingDisplayView.java | 70 +++++++++
7 files changed, 446 insertions(+), 6 deletions(-)
create mode 100644 pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/AmountDisplayView.java
create mode 100644 pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
create mode 100644 pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/AmountDisplayView.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/AmountDisplayView.java
new file mode 100644
index 00000000..0282ac94
--- /dev/null
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/AmountDisplayView.java
@@ -0,0 +1,97 @@
+package com.dspread.pos.dualScreen.view;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.dspread.pos_android_app.R;
+
+import java.util.Locale;
+
+/**
+ * 副屏金额显示自定义 View
+ *
+ * 白底布局:顶部 "Enter amount" 提示文字、中部大号粗体金额、底部分割线,
+ * 三者整体垂直居中。金额变化时调用 {@link #setAmount(String)} / {@link #setAmount(long)} 更新文本,
+ * 再通过 {@link com.dspread.pos.dualScreen.manager.ViceScreenManager#show(View)} 刷新到副屏。
+ */
+public class AmountDisplayView extends FrameLayout {
+
+ private final TextView tvAmount;
+
+ public AmountDisplayView(Context context) {
+ super(context);
+ setBackgroundColor(Color.WHITE);
+ // 作为副屏 Presentation 根容器的子 View,铺满整个副屏
+ setLayoutParams(new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+
+ // 内容容器:垂直排列,整体垂直居中,子元素水平居中
+ LinearLayout contentLayout = new LinearLayout(context);
+ contentLayout.setOrientation(LinearLayout.VERTICAL);
+ contentLayout.setGravity(Gravity.CENTER_HORIZONTAL);
+ LayoutParams contentLp = new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER);
+ addView(contentLayout, contentLp);
+
+ // 顶部提示文字
+ TextView tvHint = new TextView(context);
+ tvHint.setText(R.string.vice_screen_enter_amount);
+ tvHint.setTextColor(Color.BLACK);
+ tvHint.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
+ tvHint.setGravity(Gravity.CENTER);
+ contentLayout.addView(tvHint, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+
+ // 中部金额文字:大号粗体
+ tvAmount = new TextView(context);
+ tvAmount.setText("¥0.00");
+ tvAmount.setTextColor(Color.BLACK);
+ tvAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
+ tvAmount.setTypeface(Typeface.DEFAULT_BOLD);
+ tvAmount.setGravity(Gravity.CENTER);
+ LinearLayout.LayoutParams amountLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ amountLp.topMargin = dp(8);
+ contentLayout.addView(tvAmount, amountLp);
+
+ // 底部分割线:浅灰细线,贯穿整个宽度
+ View divider = new View(context);
+ divider.setBackgroundColor(Color.parseColor("#E0E0E0"));
+ LinearLayout.LayoutParams dividerLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT, dp(1));
+ dividerLp.topMargin = dp(24);
+ contentLayout.addView(divider, dividerLp);
+ }
+
+ /**
+ * 更新副屏显示的金额(原样显示)
+ */
+ public void setAmount(String amountText) {
+ if (amountText != null) {
+ tvAmount.setText(amountText);
+ }
+ }
+
+ /**
+ * 更新副屏显示的金额(单位:分),自动格式化为 ¥x.xx
+ */
+ public void setAmount(long amountInCents) {
+ tvAmount.setText(String.format(Locale.getDefault(), "%s%d.%02d",
+ getResources().getString(R.string.amount_identification),
+ amountInCents / 100, amountInCents % 100));
+ }
+
+ private int dp(float value) {
+ return (int) (getResources().getDisplayMetrics().density * value + 0.5f);
+ }
+}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java
index 517dfcf0..18a046e6 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java
@@ -54,7 +54,6 @@ private void viceShowDefault() {
}
}
-
private void initTimer() {
showTimer = new CountDownTimer(500, 500) {
@Override
@@ -84,9 +83,11 @@ public void initViewObservable() {
showTimer.start();
if(DeviceModelUtils.isD80()){
viceScreenManager = ViceScreenManager.getInstance(getContext());
- AmountDisplayView view = new AmountDisplayView(getContext());
- view.setAmount(inputMoney);
- viceScreenManager.show(view);
+ if(viceScreenManager.getPowerOnStatus() == 1){
+ AmountDisplayView view = new AmountDisplayView(getContext());
+ view.setAmount(inputMoney);
+ viceScreenManager.show(view);
+ }
}
navigateToPaymentMethod(inputMoney);
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java
index fca38d8d..f6f5a7d4 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java
@@ -2,20 +2,24 @@
import android.app.Dialog;
import android.content.Intent;
+import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
+import android.widget.FrameLayout;
import android.widget.ListView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.databinding.DataBindingUtil;
import com.dspread.pos.dualScreen.manager.ViceScreenManager;
+import com.dspread.pos.dualScreen.view.AmountDisplayView;
import com.dspread.pos.posAPI.ConnectionServiceCallback;
import com.dspread.pos.posAPI.POSManager;
import com.dspread.pos.posAPI.PaymentServiceCallback;
@@ -98,7 +102,27 @@ public int initVariableId() {
public void initData() {
TRACE.i("SN: " + SPUtils.getInstance().getString("posID") + " POSINFO: " + SPUtils.getInstance().getString("firmwareVersion"));
updateDeviceInfoUI();
-
+ if(DeviceModelUtils.isD80()){
+ ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(this);
+ if(viceScreenManager.getPowerOnStatus() == 1){
+ // 创建副屏视图:加载 D80_checkCard.json 动画
+ FrameLayout viceRoot = new FrameLayout(this);
+ viceRoot.setBackgroundColor(Color.WHITE);
+ viceRoot.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ com.airbnb.lottie.LottieAnimationView animationView = new com.airbnb.lottie.LottieAnimationView(this);
+ animationView.setAnimation("D80_checkCard.json");
+ animationView.setImageAssetsFolder("D80_images/");
+ animationView.loop(true);
+ animationView.playAnimation();
+ viceRoot.addView(animationView, new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ viceScreenManager.show(viceRoot);
+ }
+ }
viewModel.titleText.set("Paymenting");
paymentServiceCallback = new PaymentCallback();
amount = getIntent().getStringExtra("amount");
@@ -405,6 +429,16 @@ public void onConfirm(String password) {
@Override
public void onRequestDisplay(QPOSService.Display displayMsg) {
+ if(DeviceModelUtils.isD80()){
+ ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(PaymentActivity.this);
+ if(viceScreenManager.getPowerOnStatus() == 1){
+ String displayMsgStr = HandleTxnsResultUtils.getDisplayMessage(displayMsg, PaymentActivity.this);
+ // 创建副屏"执行中"视图:加载动画 + 提示文本
+ ProcessingDisplayView view = new ProcessingDisplayView(PaymentActivity.this);
+ view.setMessage(displayMsgStr);
+ viceScreenManager.show(view);
+ }
+ }
TRACE.d("onRequestDisplay(Display displayMsg):" + displayMsg.toString());
String msg = "";
if (displayMsg == QPOSService.Display.MSR_DATA_READY) {
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
index 110d46ef..8c4a938c 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
@@ -4,14 +4,27 @@
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.StateListDrawable;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
import com.dspread.pos.common.manager.FragmentCacheManager;
+import com.dspread.pos.dualScreen.manager.ViceScreenManager;
+import com.dspread.pos.dualScreen.view.AmountDisplayView;
import com.dspread.pos.ui.home.HomeFragment;
+import com.dspread.pos.utils.DeviceModelUtils;
import com.dspread.pos.utils.DeviceUtils;
import com.dspread.pos.utils.TRACE;
import com.dspread.pos_android_app.BR;
@@ -88,9 +101,138 @@ public void initData() {
}*/
}
);
+
+ if(DeviceModelUtils.isD80()){
+ ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(this);
+ if(viceScreenManager.getPowerOnStatus() == 1){
+ // 创建副屏显示视图:第一行金额,第二行 Card / Scan Code
+ LinearLayout viceRoot = new LinearLayout(this);
+ viceRoot.setOrientation(LinearLayout.VERTICAL);
+ viceRoot.setGravity(Gravity.CENTER);
+ viceRoot.setBackgroundColor(Color.WHITE);
+ viceRoot.setLayoutParams(new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT));
+
+ // 第一行:总金额标题
+ TextView tvTotalTitle = new TextView(this);
+ tvTotalTitle.setText("Total");
+ tvTotalTitle.setTextColor(Color.parseColor("#ff030303"));
+ tvTotalTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
+ tvTotalTitle.setGravity(Gravity.CENTER);
+ viceRoot.addView(tvTotalTitle, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+
+ // 第一行:总金额
+ TextView tvViceAmount = new TextView(this);
+ tvViceAmount.setText(viewModel.totalAmount.get());
+ tvViceAmount.setTextColor(Color.parseColor("#ff030303"));
+ tvViceAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
+ tvViceAmount.setTypeface(Typeface.DEFAULT_BOLD);
+ tvViceAmount.setGravity(Gravity.CENTER);
+ LinearLayout.LayoutParams viceAmountLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ viceAmountLp.topMargin = dp(4);
+ viceRoot.addView(tvViceAmount, viceAmountLp);
+
+ // 第二行:Card / Scan Code
+ LinearLayout methodRow = new LinearLayout(this);
+ methodRow.setOrientation(LinearLayout.HORIZONTAL);
+ methodRow.setGravity(Gravity.CENTER);
+ LinearLayout.LayoutParams methodRowLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ methodRowLp.topMargin = dp(5);
+ viceRoot.addView(methodRow, methodRowLp);
+
+ // Card 点击事件
+ methodRow.addView(createMethodItem(R.mipmap.ic_salemethod_card, "Card", v -> {
+ currentMethodIndex = 0;
+ paymentMethodsLayout.setSelectedPaymentMethod(currentMethodIndex);
+ handlePaymentMethodSelection(0);
+ }));
+
+ // Scan Code 点击事件
+ methodRow.addView(createMethodItem(R.mipmap.ic_salemethod_scan, "Scan Code", v -> {
+ currentMethodIndex = 1;
+ paymentMethodsLayout.setSelectedPaymentMethod(currentMethodIndex);
+ handlePaymentMethodSelection(1);
+ }));
+
+ // show
+ viceScreenManager.show(viceRoot);
+ }
+ }
+
+
}
+ /**
+ * 创建副屏支付方式选项(图标 + 文字,带点击事件)
+ */
+ private LinearLayout createMethodItem(int iconRes, String label, View.OnClickListener listener) {
+ LinearLayout item = new LinearLayout(this);
+ item.setOrientation(LinearLayout.VERTICAL);
+ item.setGravity(Gravity.CENTER);
+ item.setClickable(true);
+ item.setFocusable(true);
+ item.setPadding(dp(16), dp(16), dp(16), dp(16));
+ item.setBackground(createMethodItemBackground());
+ LinearLayout.LayoutParams itemLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT, dp(100));
+ itemLp.setMargins(dp(12), 0, dp(12), 0);
+ item.setLayoutParams(itemLp);
+
+ ImageView icon = new ImageView(this);
+ icon.setImageResource(iconRes);
+ icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+ item.addView(icon, new LinearLayout.LayoutParams(dp(30), dp(30)));
+
+ TextView labelTv = new TextView(this);
+ labelTv.setText(label);
+ labelTv.setTextColor(Color.parseColor("#ff030303"));
+ labelTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
+ labelTv.setGravity(Gravity.CENTER);
+ labelTv.setSingleLine(true);
+ LinearLayout.LayoutParams labelLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ labelLp.topMargin = dp(8);
+ item.addView(labelTv, labelLp);
+
+ item.setOnClickListener(listener);
+ return item;
+ }
+
+ /**
+ * 创建副屏支付方式选项的圆角边框背景(按压态变色)
+ */
+ private StateListDrawable createMethodItemBackground() {
+ GradientDrawable normalDrawable = new GradientDrawable();
+ normalDrawable.setShape(GradientDrawable.RECTANGLE);
+ normalDrawable.setCornerRadius(dp(20));
+ normalDrawable.setStroke(dp(1), Color.parseColor("#BCBCBC"));
+ normalDrawable.setColor(Color.WHITE);
+
+ GradientDrawable pressedDrawable = new GradientDrawable();
+ pressedDrawable.setShape(GradientDrawable.RECTANGLE);
+ pressedDrawable.setCornerRadius(dp(20));
+ pressedDrawable.setStroke(dp(1), Color.parseColor("#ffe47579"));
+ pressedDrawable.setColor(Color.parseColor("#ffffe9e9"));
+
+ StateListDrawable states = new StateListDrawable();
+ states.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable);
+ states.addState(new int[]{}, normalDrawable);
+ return states;
+ }
+
+ private int dp(int value) {
+ return (int) (getResources().getDisplayMetrics().density * value + 0.5f);
+ }
+
private void handlePaymentMethodSelection(int methodIndex) {
// Prevent duplicate clicks flag
if (isProcessingPayment) {
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
new file mode 100644
index 00000000..e157c9b5
--- /dev/null
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
@@ -0,0 +1,82 @@
+package com.dspread.pos.ui.payment;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.Typeface;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.dspread.pos_android_app.R;
+
+/**
+ * 副屏交易结果自定义 View
+ *
+ * 白底布局:左右排列,左侧为交易成功/失败图标,右侧为交易金额。
+ * 通过 {@link #setResult(boolean)} 切换图标、{@link #setAmount(String)} 更新金额,
+ * 再通过 {@link com.dspread.pos.dualScreen.manager.ViceScreenManager#show(View)} 刷新到副屏。
+ */
+public class PaymentResultView extends FrameLayout {
+
+ private final ImageView ivResult;
+ private final TextView tvAmount;
+
+ public PaymentResultView(Context context) {
+ super(context);
+ setBackgroundColor(Color.WHITE);
+ // 作为副屏 Presentation 根容器的子 View,铺满整个副屏
+ setLayoutParams(new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+
+ // 内容容器:水平排列,整体居中
+ LinearLayout contentLayout = new LinearLayout(context);
+ contentLayout.setOrientation(LinearLayout.VERTICAL);
+ contentLayout.setGravity(Gravity.CENTER);
+ addView(contentLayout, new LayoutParams(
+ LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER));
+
+ // 左侧结果图标
+ ivResult = new ImageView(context);
+ ivResult.setImageResource(R.mipmap.icon_success);
+ contentLayout.addView(ivResult, new LinearLayout.LayoutParams(dp(72), dp(72)));
+
+ // 右侧交易金额
+ tvAmount = new TextView(context);
+ tvAmount.setTextColor(Color.BLACK);
+ tvAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 32);
+ tvAmount.setTypeface(Typeface.DEFAULT_BOLD);
+ tvAmount.setGravity(Gravity.CENTER_VERTICAL);
+ LinearLayout.LayoutParams amountLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ amountLp.leftMargin = dp(16);
+ contentLayout.addView(tvAmount, amountLp);
+ }
+
+ /**
+ * 设置交易结果图标
+ *
+ * @param success true 显示成功图标,false 显示失败图标
+ */
+ public void setResult(boolean success) {
+ ivResult.setImageResource(success ? R.mipmap.icon_success : R.mipmap.payment_failed);
+ }
+
+ /**
+ * 更新副屏显示的交易金额
+ */
+ public void setAmount(String amountText) {
+ if (amountText != null) {
+ tvAmount.setText(amountText);
+ }
+ }
+
+ private int dp(float value) {
+ return (int) (getResources().getDisplayMetrics().density * value + 0.5f);
+ }
+}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
index e0f8c5a1..09681810 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
@@ -6,12 +6,13 @@
import android.os.Bundle;
import android.text.TextUtils;
+import com.dspread.pos.dualScreen.manager.ViceScreenManager;
+import com.dspread.pos.utils.DeviceModelUtils;
import com.dspread.pos.utils.DeviceUtils;
import com.dspread.pos_android_app.BR;
import com.dspread.pos_android_app.R;
import com.dspread.pos_android_app.databinding.ActivityPaymentstatusBinding;
-
import java.util.HashMap;
import java.util.Map;
@@ -57,6 +58,19 @@ public void initData() {
}
+ if(DeviceModelUtils.isD80()){
+ ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(PaymentStatusActivity.this);
+ if(viceScreenManager.getPowerOnStatus() == 1){
+ // 显示副屏:左侧结果图标 + 右侧交易金额
+ PaymentResultView view = new PaymentResultView(PaymentStatusActivity.this);
+ boolean isSuccess = isValidAmount(amount);
+ view.setResult(isSuccess);
+ if (isSuccess) {
+ view.setAmount("$ " + DeviceUtils.convertAmountToCents(amount));
+ }
+ viceScreenManager.show(view);
+ }
+ }
viewModel.isShouwPrinting.set(DeviceUtils.isPrinterDevices());
}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java
new file mode 100644
index 00000000..eda1c1f1
--- /dev/null
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java
@@ -0,0 +1,70 @@
+package com.dspread.pos.ui.payment;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+/**
+ * 副屏"执行中"提示自定义 View
+ *
+ * 白底布局:居中显示循环转动的加载动画,下方居中显示处理提示文本。
+ * 文本变化时调用 {@link #setMessage(String)} 更新,
+ * 再通过 {@link com.dspread.pos.dualScreen.manager.ViceScreenManager#show(View)} 刷新到副屏。
+ */
+public class ProcessingDisplayView extends FrameLayout {
+
+ private final TextView tvMessage;
+
+ public ProcessingDisplayView(Context context) {
+ super(context);
+ setBackgroundColor(Color.WHITE);
+ // 作为副屏 Presentation 根容器的子 View,铺满整个副屏
+ setLayoutParams(new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+
+ // 内容容器:垂直排列,整体居中
+ LinearLayout contentLayout = new LinearLayout(context);
+ contentLayout.setOrientation(LinearLayout.VERTICAL);
+ contentLayout.setGravity(Gravity.CENTER);
+ addView(contentLayout, new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER));
+
+ // 顶部加载动画:无限循环的圆形进度动画
+ ProgressBar progressBar = new ProgressBar(context);
+ progressBar.setIndeterminate(true);
+ LinearLayout.LayoutParams pbLp = new LinearLayout.LayoutParams(dp(40), dp(40));
+ pbLp.gravity = Gravity.CENTER_HORIZONTAL;
+ contentLayout.addView(progressBar, pbLp);
+
+ // 底部处理提示文本
+ tvMessage = new TextView(context);
+ tvMessage.setTextColor(Color.BLACK);
+ tvMessage.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
+ tvMessage.setGravity(Gravity.CENTER);
+ LinearLayout.LayoutParams msgLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ msgLp.topMargin = dp(16);
+ contentLayout.addView(tvMessage, msgLp);
+ }
+
+ /**
+ * 更新副屏显示的处理提示文本
+ */
+ public void setMessage(String msg) {
+ if (msg != null) {
+ tvMessage.setText(msg);
+ }
+ }
+
+ private int dp(float value) {
+ return (int) (getResources().getDisplayMetrics().density * value + 0.5f);
+ }
+}
From b463e16a7dab1cb9f1a505357c532c7b5bde059f Mon Sep 17 00:00:00 2001
From: ouyangwanli
Date: Wed, 16 Sep 2026 13:15:42 +0800
Subject: [PATCH 3/7] fix: add vic screen code to display UI
---
.../dualScreen/manager/ViceScreenManager.java | 14 ++++++++
.../com/dspread/pos/ui/home/HomeFragment.java | 6 +---
.../dspread/pos/ui/home/HomeViewModel.java | 12 +++++++
.../pos/ui/payment/PaymentActivity.java | 3 +-
.../pos/ui/payment/PaymentMethodActivity.java | 18 +++++-----
.../pos/ui/payment/PaymentResultView.java | 6 ++--
.../pos/ui/payment/PaymentStatusActivity.java | 1 -
.../ui/payment/PaymentStatusViewModel.java | 5 +++
.../pos/ui/payment/ProcessingDisplayView.java | 33 +++++++++++++++++--
9 files changed, 76 insertions(+), 22 deletions(-)
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/manager/ViceScreenManager.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/manager/ViceScreenManager.java
index 9748badf..36408103 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/manager/ViceScreenManager.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/manager/ViceScreenManager.java
@@ -1,10 +1,12 @@
package com.dspread.pos.dualScreen.manager;
import android.content.Context;
+import android.view.LayoutInflater;
import android.view.View;
import com.dspread.pos.dualScreen.original.ViceScreenOriginal;
+import com.dspread.pos_android_app.R;
import java.util.ArrayList;
@@ -63,6 +65,18 @@ public void show(View view, IResultCallback callback) {
original.show(view, callback);
}
+ /**
+ * 在副屏上显示默认欢迎页(副屏已开启时)
+ * 供任意页面复用,内部自动判断副屏电源状态
+ */
+ public void showDefaultView() {
+ if (getPowerOnStatus() == 1) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ View view = inflater.inflate(R.layout.vice_default, null);
+ show(view, null);
+ }
+ }
+
public void show(View view, ArrayList picDataList, IResultCallback callback) {
original.show(view, picDataList, callback);
}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java
index 18a046e6..6efecdbd 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java
@@ -47,11 +47,7 @@ public void initData() {
}
}
private void viceShowDefault() {
- if (viceScreenManager.getPowerOnStatus() == 1) {
- LayoutInflater inflater = LayoutInflater.from(getContext());
- View view = inflater.inflate(R.layout.vice_default, null);
- viceScreenManager.show(view, null);
- }
+ viceScreenManager.showDefaultView();
}
private void initTimer() {
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeViewModel.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeViewModel.java
index 18d176fa..9016218c 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeViewModel.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeViewModel.java
@@ -9,6 +9,7 @@
import com.dspread.pos.common.base.BaseAppViewModel;
import com.dspread.pos.dualScreen.manager.ViceScreenManager;
import com.dspread.pos.dualScreen.view.AmountDisplayView;
+import com.dspread.pos.utils.DeviceModelUtils;
import com.dspread.pos.utils.TRACE;
import com.dspread.pos_android_app.R;
@@ -54,6 +55,17 @@ private void updateAmountDisplay() {
String decimalPart = amountStr.substring(amountStr.length() - 2);
amount.set(String.format("$%s.%s", intPart, decimalPart));
}
+ TRACE.i("HomeviewModel amount:" + amountBuilder.toString());
+ if(DeviceModelUtils.isD80()) {
+ ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(getApplication());
+ if(viceScreenManager.getPowerOnStatus() == 1){
+ AmountDisplayView view = new AmountDisplayView(getApplication());
+ view.setAmount(amount.get());
+ viceScreenManager.show(view);
+ }
+
+ }
+
}
public void clearAmount() {
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java
index f6f5a7d4..3c432232 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java
@@ -433,8 +433,9 @@ public void onRequestDisplay(QPOSService.Display displayMsg) {
ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(PaymentActivity.this);
if(viceScreenManager.getPowerOnStatus() == 1){
String displayMsgStr = HandleTxnsResultUtils.getDisplayMessage(displayMsg, PaymentActivity.this);
- // 创建副屏"执行中"视图:加载动画 + 提示文本
+ // 创建副屏"执行中"视图:加载动画 + 金额 + 提示文本
ProcessingDisplayView view = new ProcessingDisplayView(PaymentActivity.this);
+ view.setAmount("$" + DeviceUtils.convertAmountToCents(amount));
view.setMessage(displayMsgStr);
viceScreenManager.show(view);
}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
index 8c4a938c..83c746f8 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
@@ -128,7 +128,7 @@ public void initData() {
TextView tvViceAmount = new TextView(this);
tvViceAmount.setText(viewModel.totalAmount.get());
tvViceAmount.setTextColor(Color.parseColor("#ff030303"));
- tvViceAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
+ tvViceAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 28);
tvViceAmount.setTypeface(Typeface.DEFAULT_BOLD);
tvViceAmount.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams viceAmountLp = new LinearLayout.LayoutParams(
@@ -148,7 +148,7 @@ public void initData() {
viceRoot.addView(methodRow, methodRowLp);
// Card 点击事件
- methodRow.addView(createMethodItem(R.mipmap.ic_salemethod_card, "Card", v -> {
+ methodRow.addView(createMethodItem(R.mipmap.ic_salemethod_card, " Card ", v -> {
currentMethodIndex = 0;
paymentMethodsLayout.setSelectedPaymentMethod(currentMethodIndex);
handlePaymentMethodSelection(0);
@@ -179,17 +179,17 @@ private LinearLayout createMethodItem(int iconRes, String label, View.OnClickLis
item.setGravity(Gravity.CENTER);
item.setClickable(true);
item.setFocusable(true);
- item.setPadding(dp(16), dp(16), dp(16), dp(16));
+ item.setPadding(dp(5), dp(5), dp(5), dp(5));
item.setBackground(createMethodItemBackground());
LinearLayout.LayoutParams itemLp = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT, dp(100));
- itemLp.setMargins(dp(12), 0, dp(12), 0);
+ LinearLayout.LayoutParams.WRAP_CONTENT, dp(50));
+ itemLp.setMargins(dp(5), 0, dp(15), 0);
item.setLayoutParams(itemLp);
ImageView icon = new ImageView(this);
icon.setImageResource(iconRes);
icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
- item.addView(icon, new LinearLayout.LayoutParams(dp(30), dp(30)));
+ item.addView(icon, new LinearLayout.LayoutParams(dp(20), dp(20)));
TextView labelTv = new TextView(this);
labelTv.setText(label);
@@ -200,7 +200,7 @@ private LinearLayout createMethodItem(int iconRes, String label, View.OnClickLis
LinearLayout.LayoutParams labelLp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
- labelLp.topMargin = dp(8);
+ labelLp.topMargin = dp(2);
item.addView(labelTv, labelLp);
item.setOnClickListener(listener);
@@ -213,13 +213,13 @@ private LinearLayout createMethodItem(int iconRes, String label, View.OnClickLis
private StateListDrawable createMethodItemBackground() {
GradientDrawable normalDrawable = new GradientDrawable();
normalDrawable.setShape(GradientDrawable.RECTANGLE);
- normalDrawable.setCornerRadius(dp(20));
+ normalDrawable.setCornerRadius(dp(2));
normalDrawable.setStroke(dp(1), Color.parseColor("#BCBCBC"));
normalDrawable.setColor(Color.WHITE);
GradientDrawable pressedDrawable = new GradientDrawable();
pressedDrawable.setShape(GradientDrawable.RECTANGLE);
- pressedDrawable.setCornerRadius(dp(20));
+ pressedDrawable.setCornerRadius(dp(2));
pressedDrawable.setStroke(dp(1), Color.parseColor("#ffe47579"));
pressedDrawable.setColor(Color.parseColor("#ffffe9e9"));
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
index e157c9b5..10ef9a8e 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
@@ -35,7 +35,7 @@ public PaymentResultView(Context context) {
// 内容容器:水平排列,整体居中
LinearLayout contentLayout = new LinearLayout(context);
- contentLayout.setOrientation(LinearLayout.VERTICAL);
+ contentLayout.setOrientation(LinearLayout.HORIZONTAL);
contentLayout.setGravity(Gravity.CENTER);
addView(contentLayout, new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER));
@@ -43,12 +43,12 @@ public PaymentResultView(Context context) {
// 左侧结果图标
ivResult = new ImageView(context);
ivResult.setImageResource(R.mipmap.icon_success);
- contentLayout.addView(ivResult, new LinearLayout.LayoutParams(dp(72), dp(72)));
+ contentLayout.addView(ivResult, new LinearLayout.LayoutParams(dp(40), dp(40)));
// 右侧交易金额
tvAmount = new TextView(context);
tvAmount.setTextColor(Color.BLACK);
- tvAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 32);
+ tvAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
tvAmount.setTypeface(Typeface.DEFAULT_BOLD);
tvAmount.setGravity(Gravity.CENTER_VERTICAL);
LinearLayout.LayoutParams amountLp = new LinearLayout.LayoutParams(
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
index 09681810..5336da06 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
@@ -57,7 +57,6 @@ public void initData() {
handleTransactionFailure();
}
-
if(DeviceModelUtils.isD80()){
ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(PaymentStatusActivity.this);
if(viceScreenManager.getPowerOnStatus() == 1){
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusViewModel.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusViewModel.java
index 1fdb7b54..665b867e 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusViewModel.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusViewModel.java
@@ -4,7 +4,9 @@
import android.content.Intent;
import com.dspread.pos.common.base.BaseAppViewModel;
+import com.dspread.pos.dualScreen.manager.ViceScreenManager;
import com.dspread.pos.ui.printer.activities.PrintTicketActivity;
+import com.dspread.pos.utils.DeviceModelUtils;
import com.dspread.pos.utils.TRACE;
import java.util.Map;
@@ -68,6 +70,9 @@ public void sendTranReceipt(Map map) {
isNavigating = true;
try {
finish();
+ if (DeviceModelUtils.isD80()) {
+ ViceScreenManager.getInstance(context).showDefaultView();
+ }
} catch (Exception e) {
isNavigating = false;
}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java
index eda1c1f1..3fade093 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java
@@ -2,6 +2,7 @@
import android.content.Context;
import android.graphics.Color;
+import android.graphics.Typeface;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
@@ -19,6 +20,7 @@
*/
public class ProcessingDisplayView extends FrameLayout {
+ private final TextView tvAmount;
private final TextView tvMessage;
public ProcessingDisplayView(Context context) {
@@ -37,11 +39,24 @@ public ProcessingDisplayView(Context context) {
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER));
// 顶部加载动画:无限循环的圆形进度动画
- ProgressBar progressBar = new ProgressBar(context);
+ /* ProgressBar progressBar = new ProgressBar(context);
progressBar.setIndeterminate(true);
- LinearLayout.LayoutParams pbLp = new LinearLayout.LayoutParams(dp(40), dp(40));
+ LinearLayout.LayoutParams pbLp = new LinearLayout.LayoutParams(dp(24), dp(24));
pbLp.gravity = Gravity.CENTER_HORIZONTAL;
- contentLayout.addView(progressBar, pbLp);
+ contentLayout.addView(progressBar, pbLp);*/
+
+ // 金额文本:位于提示文本上方,大号加粗显示
+ tvAmount = new TextView(context);
+ tvAmount.setTextColor(Color.BLACK);
+ tvAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 36);
+ tvAmount.setTypeface(Typeface.DEFAULT_BOLD);
+ tvAmount.setGravity(Gravity.CENTER);
+ tvAmount.setVisibility(View.GONE);
+ LinearLayout.LayoutParams amountLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ amountLp.topMargin = dp(12);
+ contentLayout.addView(tvAmount, amountLp);
// 底部处理提示文本
tvMessage = new TextView(context);
@@ -64,6 +79,18 @@ public void setMessage(String msg) {
}
}
+ /**
+ * 更新副屏显示的金额文本,金额为空时隐藏
+ */
+ public void setAmount(String amount) {
+ if (amount == null || amount.isEmpty()) {
+ tvAmount.setVisibility(View.GONE);
+ } else {
+ tvAmount.setText(amount);
+ tvAmount.setVisibility(View.VISIBLE);
+ }
+ }
+
private int dp(float value) {
return (int) (getResources().getDisplayMetrics().density * value + 0.5f);
}
From 42bf5e56af2c108d44238b7bffddc7fc0e2c477f Mon Sep 17 00:00:00 2001
From: ouyangwanli
Date: Wed, 16 Sep 2026 19:51:21 +0800
Subject: [PATCH 4/7] fix: add the vic screen logic
---
.../dspread/pos/ui/home/HomeViewModel.java | 9 ++++-
.../com/dspread/pos/ui/main/MainActivity.java | 6 ++-
.../pos/ui/payment/PaymentMethodActivity.java | 2 +-
.../pos/ui/payment/PaymentResultView.java | 38 +++++++++++++++++--
.../pos/ui/payment/PaymentStatusActivity.java | 7 ++--
5 files changed, 51 insertions(+), 11 deletions(-)
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeViewModel.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeViewModel.java
index 9016218c..c143c3ea 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeViewModel.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeViewModel.java
@@ -41,6 +41,14 @@ private void updateAmountDisplay() {
if (amountBuilder.length() == 0) {
amount.set("$0.00");
amountValid.set(false);
+ if(DeviceModelUtils.isD80()) {
+ ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(getApplication());
+ if(viceScreenManager.getPowerOnStatus() == 1){
+ AmountDisplayView view = new AmountDisplayView(getApplication());
+ view.setAmount(amount.get());
+ viceScreenManager.show(view);
+ }
+ }
return;
}
amountValid.set(true);
@@ -63,7 +71,6 @@ private void updateAmountDisplay() {
view.setAmount(amount.get());
viceScreenManager.show(view);
}
-
}
}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/main/MainActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/main/MainActivity.java
index fc183b1c..f319a412 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/main/MainActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/main/MainActivity.java
@@ -8,6 +8,7 @@
import android.widget.ImageView;
import com.dspread.pos.common.manager.FragmentCacheManager;
+import com.dspread.pos.dualScreen.manager.ViceScreenManager;
import com.dspread.pos.posAPI.POSManager;
import com.dspread.pos.ui.home.HomeFragment;
import com.dspread.pos.ui.transaction.SerachKeyboardUtils;
@@ -223,9 +224,12 @@ protected void onDestroy() {
if (viewPager != null) {
viewPager = null;
}
-
// Shutdown background executor
backgroundExecutor.shutdown();
+ ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(getApplication());
+ if(viceScreenManager.getPowerOnStatus() == 1){
+ viceScreenManager.power(false);
+ }
}
@Override
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
index 83c746f8..593db40d 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
@@ -148,7 +148,7 @@ public void initData() {
viceRoot.addView(methodRow, methodRowLp);
// Card 点击事件
- methodRow.addView(createMethodItem(R.mipmap.ic_salemethod_card, " Card ", v -> {
+ methodRow.addView(createMethodItem(R.mipmap.ic_salemethod_card, " Card ", v -> {
currentMethodIndex = 0;
paymentMethodsLayout.setSelectedPaymentMethod(currentMethodIndex);
handlePaymentMethodSelection(0);
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
index 10ef9a8e..10033de1 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
@@ -3,6 +3,7 @@
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
+import android.text.TextUtils;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
@@ -24,6 +25,7 @@ public class PaymentResultView extends FrameLayout {
private final ImageView ivResult;
private final TextView tvAmount;
+ private final TextView tvErrorMsg;
public PaymentResultView(Context context) {
super(context);
@@ -33,17 +35,25 @@ public PaymentResultView(Context context) {
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
- // 内容容器:水平排列,整体居中
+ // 内容容器:垂直排列,整体居中
LinearLayout contentLayout = new LinearLayout(context);
- contentLayout.setOrientation(LinearLayout.HORIZONTAL);
+ contentLayout.setOrientation(LinearLayout.VERTICAL);
contentLayout.setGravity(Gravity.CENTER);
addView(contentLayout, new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER));
+ // 上半部分:水平排列图标与金额
+ LinearLayout rowLayout = new LinearLayout(context);
+ rowLayout.setOrientation(LinearLayout.HORIZONTAL);
+ rowLayout.setGravity(Gravity.CENTER);
+ contentLayout.addView(rowLayout, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+
// 左侧结果图标
ivResult = new ImageView(context);
ivResult.setImageResource(R.mipmap.icon_success);
- contentLayout.addView(ivResult, new LinearLayout.LayoutParams(dp(40), dp(40)));
+ rowLayout.addView(ivResult, new LinearLayout.LayoutParams(dp(40), dp(40)));
// 右侧交易金额
tvAmount = new TextView(context);
@@ -55,7 +65,18 @@ public PaymentResultView(Context context) {
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
amountLp.leftMargin = dp(16);
- contentLayout.addView(tvAmount, amountLp);
+ rowLayout.addView(tvAmount, amountLp);
+
+ // 下方错误信息
+ tvErrorMsg = new TextView(context);
+ tvErrorMsg.setTextColor(Color.BLACK);
+ tvErrorMsg.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
+ tvErrorMsg.setGravity(Gravity.CENTER);
+ LinearLayout.LayoutParams errorLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ errorLp.topMargin = dp(8);
+ contentLayout.addView(tvErrorMsg, errorLp);
}
/**
@@ -76,6 +97,15 @@ public void setAmount(String amountText) {
}
}
+ /**
+ * 更新副屏显示的错误信息
+ */
+ public void setErrorMsg(String errorMsg) {
+ if (!TextUtils.isEmpty(errorMsg)) {
+ tvErrorMsg.setText(errorMsg);
+ }
+ }
+
private int dp(float value) {
return (int) (getResources().getDisplayMetrics().density * value + 0.5f);
}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
index 5336da06..9b94a008 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
@@ -47,7 +47,6 @@ public void initData() {
terminalTime = getStringExtraSafely(intent, KEY_TERMINAL_TIME);
errorMsg = getStringExtraSafely(intent, KEY_ERROR_MSG);
-
viewModel.isD70DisplayScreen.set(MODEL_D70.equals(Build.MODEL));
@@ -64,8 +63,11 @@ public void initData() {
PaymentResultView view = new PaymentResultView(PaymentStatusActivity.this);
boolean isSuccess = isValidAmount(amount);
view.setResult(isSuccess);
+ view.setErrorMsg("payment success");
if (isSuccess) {
view.setAmount("$ " + DeviceUtils.convertAmountToCents(amount));
+ } else {
+ view.setErrorMsg(errorMsg);
}
viceScreenManager.show(view);
}
@@ -95,14 +97,11 @@ private boolean isValidAmount(String amount) {
*/
private void handleTransactionSuccess() {
String amountInCents = DeviceUtils.convertAmountToCents(amount);
-
viewModel.displayAmount(amountInCents);
viewModel.setTransactionSuccess();
-
Map receiptData = createReceiptData(amountInCents, maskedPAN, terminalTime);
viewModel.sendTranReceipt(receiptData);
}
-
/**
* 创建收据数据
*/
From b78f4d7ffb2a43ad6c85fd0b7e1ee40f30325fce Mon Sep 17 00:00:00 2001
From: ouyangwanli
Date: Thu, 17 Sep 2026 18:28:31 +0800
Subject: [PATCH 5/7] fix: add secondary screen code
---
.../dualScreen/view/PaymentQRPromptView.java | 126 ++++++++++++++++++
.../view}/PaymentResultView.java | 14 +-
.../view}/ProcessingDisplayView.java | 5 +-
.../com/dspread/pos/ui/home/HomeFragment.java | 1 +
.../com/dspread/pos/ui/main/MainActivity.java | 24 ++++
.../pos/ui/payment/PaymentActivity.java | 3 +-
.../pos/ui/payment/PaymentMethodActivity.java | 80 ++++++-----
.../pos/ui/payment/PaymentStatusActivity.java | 5 +-
8 files changed, 212 insertions(+), 46 deletions(-)
create mode 100644 pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/PaymentQRPromptView.java
rename pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/{ui/payment => dualScreen/view}/PaymentResultView.java (90%)
rename pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/{ui/payment => dualScreen/view}/ProcessingDisplayView.java (96%)
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/PaymentQRPromptView.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/PaymentQRPromptView.java
new file mode 100644
index 00000000..b17fb7dc
--- /dev/null
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/PaymentQRPromptView.java
@@ -0,0 +1,126 @@
+package com.dspread.pos.dualScreen.view;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PorterDuff;
+import android.graphics.Typeface;
+import android.graphics.drawable.GradientDrawable;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.dspread.pos_android_app.R;
+
+/**
+ * 副屏扫码支付提示自定义 View
+ *
+ * 两列布局:左侧红色圆角卡片显示"Trans Amount"+金额,
+ * 右侧白色描边卡片显示红色圆形扫码图标+提示文字,
+ * 通过 {@link com.dspread.pos.dualScreen.manager.ViceScreenManager#show(android.view.View)} 显示到副屏。
+ */
+public class PaymentQRPromptView extends LinearLayout {
+
+ private final TextView tvAmount;
+
+ public PaymentQRPromptView(Context context) {
+ super(context);
+ setOrientation(HORIZONTAL);
+ setGravity(Gravity.CENTER);
+ setBackgroundColor(Color.WHITE);
+ setPadding(dp(4), dp(4), dp(4), dp(4));
+ // 作为副屏 Presentation 根容器的子 View,铺满整个副屏
+ setLayoutParams(new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+
+ // 左列:红色圆角卡片,显示 Trans Amount + 金额
+ LinearLayout amountCard = new LinearLayout(context);
+ amountCard.setOrientation(LinearLayout.VERTICAL);
+ amountCard.setGravity(Gravity.CENTER);
+ amountCard.setPadding(dp(4), dp(4), dp(4), dp(4));
+ amountCard.setBackground(roundedDrawable(Color.parseColor("#FFD32F2F"), dp(8), 0, Color.TRANSPARENT));
+ LayoutParams amountCardLp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1f);
+ amountCardLp.setMargins(0, 0, dp(4), 0);
+ addView(amountCard, amountCardLp);
+
+ TextView tvTitle = new TextView(context);
+ tvTitle.setText("Trans Amount");
+ tvTitle.setTextColor(Color.WHITE);
+ tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
+ tvTitle.setGravity(Gravity.CENTER);
+ amountCard.addView(tvTitle);
+
+ tvAmount = new TextView(context);
+ tvAmount.setTextColor(Color.WHITE);
+ tvAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
+ tvAmount.setTypeface(Typeface.DEFAULT_BOLD);
+ tvAmount.setGravity(Gravity.CENTER);
+ LayoutParams amountTextLp = new LayoutParams(
+ LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+ amountTextLp.topMargin = dp(4);
+ amountCard.addView(tvAmount, amountTextLp);
+
+ // 右列:白色圆角卡片(红色描边),显示扫码图标 + 提示文字
+ LinearLayout scanCard = new LinearLayout(context);
+ scanCard.setOrientation(LinearLayout.VERTICAL);
+ scanCard.setGravity(Gravity.CENTER);
+ scanCard.setPadding(dp(4), dp(4), dp(4), dp(4));
+ scanCard.setBackground(roundedDrawable(Color.WHITE, dp(8), dp(1), Color.parseColor("#FFD32F2F")));
+ LayoutParams scanCardLp = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1f);
+ scanCardLp.setMargins(dp(4), 0, 0, 0);
+ addView(scanCard, scanCardLp);
+
+ // 红色圆形背景 + 白色扫码图标
+ FrameLayout iconWrap = new FrameLayout(context);
+ GradientDrawable circleBg = new GradientDrawable();
+ circleBg.setShape(GradientDrawable.OVAL);
+ circleBg.setColor(Color.parseColor("#FFD32F2F"));
+ iconWrap.setBackground(circleBg);
+ scanCard.addView(iconWrap, new LayoutParams(dp(32), dp(32)));
+
+ ImageView ivScan = new ImageView(context);
+ ivScan.setImageResource(R.mipmap.ic_salemethod_scan);
+ ivScan.setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_IN);
+ ivScan.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+ iconWrap.addView(ivScan, new FrameLayout.LayoutParams(
+ dp(18), dp(18), Gravity.CENTER));
+
+ // 提示文字
+ TextView tvPrompt = new TextView(context);
+ tvPrompt.setText("Please place your payment code above the camera.");
+ tvPrompt.setTextColor(Color.BLACK);
+ tvPrompt.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
+ tvPrompt.setGravity(Gravity.CENTER);
+ LayoutParams promptLp = new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ promptLp.topMargin = dp(4);
+ scanCard.addView(tvPrompt, promptLp);
+ }
+
+ /**
+ * 更新副屏显示的金额
+ */
+ public void setAmount(String amountText) {
+ if (amountText != null) {
+ tvAmount.setText(amountText);
+ }
+ }
+
+ private GradientDrawable roundedDrawable(int fillColor, int radius, int strokeWidth, int strokeColor) {
+ GradientDrawable drawable = new GradientDrawable();
+ drawable.setShape(GradientDrawable.RECTANGLE);
+ drawable.setCornerRadius(radius);
+ drawable.setColor(fillColor);
+ if (strokeWidth > 0) {
+ drawable.setStroke(strokeWidth, strokeColor);
+ }
+ return drawable;
+ }
+
+ private int dp(int value) {
+ return (int) (getResources().getDisplayMetrics().density * value + 0.5f);
+ }
+}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/PaymentResultView.java
similarity index 90%
rename from pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
rename to pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/PaymentResultView.java
index 10033de1..2a6b9a4a 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentResultView.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/PaymentResultView.java
@@ -1,4 +1,4 @@
-package com.dspread.pos.ui.payment;
+package com.dspread.pos.dualScreen.view;
import android.content.Context;
import android.graphics.Color;
@@ -40,14 +40,14 @@ public PaymentResultView(Context context) {
contentLayout.setOrientation(LinearLayout.VERTICAL);
contentLayout.setGravity(Gravity.CENTER);
addView(contentLayout, new LayoutParams(
- LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER));
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER));
// 上半部分:水平排列图标与金额
LinearLayout rowLayout = new LinearLayout(context);
- rowLayout.setOrientation(LinearLayout.HORIZONTAL);
+ rowLayout.setOrientation(LinearLayout.VERTICAL);
rowLayout.setGravity(Gravity.CENTER);
contentLayout.addView(rowLayout, new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
// 左侧结果图标
@@ -64,18 +64,18 @@ public PaymentResultView(Context context) {
LinearLayout.LayoutParams amountLp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
- amountLp.leftMargin = dp(16);
+ //amountLp.leftMargin = dp(16);
rowLayout.addView(tvAmount, amountLp);
// 下方错误信息
tvErrorMsg = new TextView(context);
tvErrorMsg.setTextColor(Color.BLACK);
- tvErrorMsg.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
+ tvErrorMsg.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12);
tvErrorMsg.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams errorLp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
- errorLp.topMargin = dp(8);
+ errorLp.topMargin = dp(2);
contentLayout.addView(tvErrorMsg, errorLp);
}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/ProcessingDisplayView.java
similarity index 96%
rename from pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java
rename to pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/ProcessingDisplayView.java
index 3fade093..8004b5b0 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/ProcessingDisplayView.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/dualScreen/view/ProcessingDisplayView.java
@@ -1,4 +1,4 @@
-package com.dspread.pos.ui.payment;
+package com.dspread.pos.dualScreen.view;
import android.content.Context;
import android.graphics.Color;
@@ -8,7 +8,6 @@
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
-import android.widget.ProgressBar;
import android.widget.TextView;
/**
@@ -48,7 +47,7 @@ public ProcessingDisplayView(Context context) {
// 金额文本:位于提示文本上方,大号加粗显示
tvAmount = new TextView(context);
tvAmount.setTextColor(Color.BLACK);
- tvAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 36);
+ tvAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 26);
tvAmount.setTypeface(Typeface.DEFAULT_BOLD);
tvAmount.setGravity(Gravity.CENTER);
tvAmount.setVisibility(View.GONE);
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java
index 6efecdbd..a60c5309 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/home/HomeFragment.java
@@ -39,6 +39,7 @@ public int initVariableId() {
@Override
public void initData() {
+ TRACE.d("HomeFragment initData");
initTimer();
if(DeviceModelUtils.isD80()){
viceScreenManager = ViceScreenManager.getInstance(getContext());
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/main/MainActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/main/MainActivity.java
index f319a412..5df8286f 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/main/MainActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/main/MainActivity.java
@@ -1,6 +1,7 @@
package com.dspread.pos.ui.main;
import android.content.pm.ActivityInfo;
+import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.KeyEvent;
@@ -13,6 +14,7 @@
import com.dspread.pos.ui.home.HomeFragment;
import com.dspread.pos.ui.transaction.SerachKeyboardUtils;
import com.dspread.pos.upgrade.CustomUpgradeCallback;
+import com.dspread.pos.utils.DeviceModelUtils;
import com.dspread.pos.utils.Mydialog;
import com.dspread.pos.utils.TRACE;
import com.dspread.pos_android_app.BR;
@@ -79,11 +81,33 @@ protected void onResume() {
super.onResume();
}
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ setIntent(intent);
+ // 切回 HomeFragment
+ if (viewModel != null) {
+ TRACE.d("App started, 1");
+ viewModel.handleNavigationItemClick(R.id.nav_home);
+ } else if (viewPager != null) {
+ TRACE.d("App started, 2");
+ viewPager.setCurrentItem(MainFragmentAdapter.FRAGMENT_HOME, false);
+ updateNavigationMenuSelection(MainFragmentAdapter.FRAGMENT_HOME);
+ }
+ // 重新执行 HomeFragment.initData 中的副屏初始化(D80)
+ if (DeviceModelUtils.isD80()) {
+ TRACE.d("App started, 3");
+ ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(getApplication());
+ viceScreenManager.showDefaultView();
+ }
+ }
+
@Override
public void initData() {
super.initData();
// Reset update dialog shown flag on app start
SPUtils.getInstance().put("update_dialog_shown", false);
+ TRACE.d("App started, update dialog shown flag reset");
drawerLayout = binding.drawerLayout;
navigationView = binding.navView;
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java
index 3c432232..4c4d7fd5 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentActivity.java
@@ -7,7 +7,6 @@
import android.os.Handler;
import android.os.Looper;
import android.text.Html;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -19,7 +18,7 @@
import androidx.databinding.DataBindingUtil;
import com.dspread.pos.dualScreen.manager.ViceScreenManager;
-import com.dspread.pos.dualScreen.view.AmountDisplayView;
+import com.dspread.pos.dualScreen.view.ProcessingDisplayView;
import com.dspread.pos.posAPI.ConnectionServiceCallback;
import com.dspread.pos.posAPI.POSManager;
import com.dspread.pos.posAPI.PaymentServiceCallback;
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
index 593db40d..1173ccb8 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentMethodActivity.java
@@ -20,10 +20,8 @@
import android.widget.LinearLayout;
import android.widget.TextView;
-import com.dspread.pos.common.manager.FragmentCacheManager;
import com.dspread.pos.dualScreen.manager.ViceScreenManager;
-import com.dspread.pos.dualScreen.view.AmountDisplayView;
-import com.dspread.pos.ui.home.HomeFragment;
+import com.dspread.pos.dualScreen.view.PaymentQRPromptView;
import com.dspread.pos.utils.DeviceModelUtils;
import com.dspread.pos.utils.DeviceUtils;
import com.dspread.pos.utils.TRACE;
@@ -33,7 +31,6 @@
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.fragment.app.Fragment;
import me.goldze.mvvmhabit.base.BaseActivity;
import me.goldze.mvvmhabit.utils.ToastUtils;
@@ -95,13 +92,18 @@ public void initData() {
scanData = amount;
gotoPaymentstatusActivity(scanData);
finish();
- } /*else {
- gotoPaymentstatusActivity("");
- finish();
- }*/
+ } else {
+ showVicPaymentMothed();
+ }
}
);
+ showVicPaymentMothed();
+
+
+ }
+
+ private void showVicPaymentMothed() {
if(DeviceModelUtils.isD80()){
ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(this);
if(viceScreenManager.getPowerOnStatus() == 1){
@@ -114,41 +116,47 @@ public void initData() {
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
- // 第一行:总金额标题
+ // 第一行:amount 标题 + 总金额(同一行显示)
+ LinearLayout amountRow = new LinearLayout(this);
+ amountRow.setOrientation(LinearLayout.HORIZONTAL);
+ amountRow.setGravity(Gravity.CENTER_VERTICAL);
+ LinearLayout.LayoutParams amountRowLp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ amountRowLp.bottomMargin = dp(2);
+ viceRoot.addView(amountRow, amountRowLp);
+
TextView tvTotalTitle = new TextView(this);
- tvTotalTitle.setText("Total");
+ tvTotalTitle.setText("Total: ");
tvTotalTitle.setTextColor(Color.parseColor("#ff030303"));
- tvTotalTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
- tvTotalTitle.setGravity(Gravity.CENTER);
- viceRoot.addView(tvTotalTitle, new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
- LinearLayout.LayoutParams.WRAP_CONTENT));
+ tvTotalTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
+ tvTotalTitle.setTypeface(Typeface.DEFAULT_BOLD);
+ amountRow.addView(tvTotalTitle);
- // 第一行:总金额
TextView tvViceAmount = new TextView(this);
tvViceAmount.setText(viewModel.totalAmount.get());
tvViceAmount.setTextColor(Color.parseColor("#ff030303"));
- tvViceAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 28);
+ tvViceAmount.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
tvViceAmount.setTypeface(Typeface.DEFAULT_BOLD);
- tvViceAmount.setGravity(Gravity.CENTER);
LinearLayout.LayoutParams viceAmountLp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
- viceAmountLp.topMargin = dp(4);
- viceRoot.addView(tvViceAmount, viceAmountLp);
+ viceAmountLp.leftMargin = dp(2);
+ amountRow.addView(tvViceAmount, viceAmountLp);
- // 第二行:Card / Scan Code
+ // 第二行:Card / Scan Code(宽度均分,保证按钮文字不被裁剪)
LinearLayout methodRow = new LinearLayout(this);
methodRow.setOrientation(LinearLayout.HORIZONTAL);
methodRow.setGravity(Gravity.CENTER);
+ methodRow.setPadding(dp(6), 0, dp(6), 0);
LinearLayout.LayoutParams methodRowLp = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
- methodRowLp.topMargin = dp(5);
+ methodRowLp.topMargin = dp(2);
viceRoot.addView(methodRow, methodRowLp);
// Card 点击事件
- methodRow.addView(createMethodItem(R.mipmap.ic_salemethod_card, " Card ", v -> {
+ methodRow.addView(createMethodItem(R.mipmap.ic_salemethod_card, "Card", v -> {
currentMethodIndex = 0;
paymentMethodsLayout.setSelectedPaymentMethod(currentMethodIndex);
handlePaymentMethodSelection(0);
@@ -165,8 +173,6 @@ public void initData() {
viceScreenManager.show(viceRoot);
}
}
-
-
}
@@ -179,17 +185,18 @@ private LinearLayout createMethodItem(int iconRes, String label, View.OnClickLis
item.setGravity(Gravity.CENTER);
item.setClickable(true);
item.setFocusable(true);
- item.setPadding(dp(5), dp(5), dp(5), dp(5));
+ item.setPadding(dp(6), dp(6), dp(6), dp(6));
item.setBackground(createMethodItemBackground());
+ // 宽度采用 0dp + weight=1 均分副屏可用宽度,避免固定宽度超屏导致下方文字被裁切
LinearLayout.LayoutParams itemLp = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT, dp(50));
- itemLp.setMargins(dp(5), 0, dp(15), 0);
+ 0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f);
+ itemLp.setMargins(dp(6), 0, dp(6), 0);
item.setLayoutParams(itemLp);
ImageView icon = new ImageView(this);
icon.setImageResource(iconRes);
icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
- item.addView(icon, new LinearLayout.LayoutParams(dp(20), dp(20)));
+ item.addView(icon, new LinearLayout.LayoutParams(dp(32), dp(32)));
TextView labelTv = new TextView(this);
labelTv.setText(label);
@@ -200,7 +207,7 @@ private LinearLayout createMethodItem(int iconRes, String label, View.OnClickLis
LinearLayout.LayoutParams labelLp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
- labelLp.topMargin = dp(2);
+ labelLp.topMargin = dp(4);
item.addView(labelTv, labelLp);
item.setOnClickListener(listener);
@@ -271,6 +278,17 @@ private void startScanCodePayment() {
intent.putExtra("amount", amount);
startActivity(intent);*/
TRACE.d("PayMethodActivity startScanCodePayment");
+
+ if(DeviceModelUtils.isD80()){
+ ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(this);
+ if(viceScreenManager.getPowerOnStatus() == 1){
+ // 副屏显示扫码支付提示:左侧金额卡片,右侧扫码图标与提示文字
+ PaymentQRPromptView promptView = new PaymentQRPromptView(this);
+ promptView.setAmount(viewModel.totalAmount.get());
+ viceScreenManager.show(promptView);
+ }
+ }
+
initScanCode();
}
diff --git a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
index 9b94a008..399b89d9 100644
--- a/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
+++ b/pos_android_studio_demo/pos_android_app/src/main/java/com/dspread/pos/ui/payment/PaymentStatusActivity.java
@@ -7,6 +7,7 @@
import android.text.TextUtils;
import com.dspread.pos.dualScreen.manager.ViceScreenManager;
+import com.dspread.pos.dualScreen.view.PaymentResultView;
import com.dspread.pos.utils.DeviceModelUtils;
import com.dspread.pos.utils.DeviceUtils;
import com.dspread.pos_android_app.BR;
@@ -46,10 +47,8 @@ public void initData() {
maskedPAN = getStringExtraSafely(intent, KEY_MASKED_PAN);
terminalTime = getStringExtraSafely(intent, KEY_TERMINAL_TIME);
errorMsg = getStringExtraSafely(intent, KEY_ERROR_MSG);
-
viewModel.isD70DisplayScreen.set(MODEL_D70.equals(Build.MODEL));
-
if (isValidAmount(amount)) {
handleTransactionSuccess();
} else {
@@ -59,7 +58,7 @@ public void initData() {
if(DeviceModelUtils.isD80()){
ViceScreenManager viceScreenManager = ViceScreenManager.getInstance(PaymentStatusActivity.this);
if(viceScreenManager.getPowerOnStatus() == 1){
- // 显示副屏:左侧结果图标 + 右侧交易金额
+ // 显示副屏:左侧结果图标 + 右侧交易金额 + 下面是交易成功或交易失败
PaymentResultView view = new PaymentResultView(PaymentStatusActivity.this);
boolean isSuccess = isValidAmount(amount);
view.setResult(isSuccess);
From 3fa66d73853ef8f9e5ccb6df40236cc6eef3d683 Mon Sep 17 00:00:00 2001
From: ouyangwanli
Date: Sun, 20 Sep 2026 18:26:16 +0800
Subject: [PATCH 6/7] fix: add D80 dual screen logic
---
.../pos_android_app/build.gradle | 4 ++--
.../libs/dspread_pos_sdk_8.5.5-min.aar | Bin 1751139 -> 1751131 bytes
.../libs/dspread_pos_sdk_8.5.5.aar | Bin 6453997 -> 6454001 bytes
3 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pos_android_studio_demo/pos_android_app/build.gradle b/pos_android_studio_demo/pos_android_app/build.gradle
index 0ea2ca5a..471e749f 100644
--- a/pos_android_studio_demo/pos_android_app/build.gradle
+++ b/pos_android_studio_demo/pos_android_app/build.gradle
@@ -31,8 +31,8 @@ android {
applicationId "com.dspread.pos_android_app"
minSdk 24
targetSdk 34
- versionCode 148
- versionName "8.5.5-2609101405"
+ versionCode 149
+ versionName "8.5.5-2609201905"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
// Set up supported SO library architecture
diff --git a/pos_android_studio_demo/pos_android_app/libs/dspread_pos_sdk_8.5.5-min.aar b/pos_android_studio_demo/pos_android_app/libs/dspread_pos_sdk_8.5.5-min.aar
index e808cb95b24be409d19ee47753a3010fd711c86e..b03ffd5e4eaffefe18e1fbe1575c9f11e85267ba 100644
GIT binary patch
delta 697129
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