新增蓝牙打印功能,加入测试代码

修复差旅助手无法切换市局级及不同民警的功能
master
马超 2025-10-21 11:01:55 +08:00
parent a2a8310573
commit 3b219cdea2
59 changed files with 2904 additions and 620 deletions

View File

@ -10,8 +10,8 @@ android {
applicationId "com.ycgis.macall.personalcenter"
minSdkVersion 23
targetSdkVersion 30
versionCode 2506051
versionName "3.1.20250605.01"
versionCode 2507041
versionName "3.1.20250704.01"
// versionCode 2000000
// versionName "2.0.202403221"
@ -101,6 +101,11 @@ dependencies {
//Zxing
implementation 'com.github.jenly1314:zxing-lite:2.1.1'
//
implementation files('libs\\4.0.0-release.aar')
implementation files('libs\\image-1.8.9.aar')
implementation files('libs\\LPAPI-2019-11-20-R.jar')
// implementation('com.github.gzu-liyujiang:Android_CN_OAID:4.2.5.1') {
// // 使SDK/荣耀官方广告标识服务SDK因为移动安全联盟SDK也依赖了华为/耀SDK
// // 广SDK build.gradle

BIN
app/libs/4.0.0-release.aar Normal file

Binary file not shown.

Binary file not shown.

BIN
app/libs/image-1.8.9.aar Normal file

Binary file not shown.

View File

@ -88,7 +88,7 @@
-keep public class com.ycgis.macall.personalcenter.p.request.UploadProgressResponsBody{*;}
-keep public class com.ycgis.macall.personalcenter.m.adapterbean.**{*;}
-keep public class com.ycgis.macall.personalcenter.m.datamodel.PrintModel{*;}
-keep public class com.ycgis.macall.personalcenter.m.datamodel.**{*;}
-keep public class com.ycgis.macall.personalcenter.m.event.MessageEvent{*;}
-keep public class com.ycgis.macall.personalcenter.m.enumbean.**{*;}
-keep public class com.ycgis.macall.personalcenter.m.provider.**{*;}
@ -306,3 +306,20 @@ long consumerIndex;
public <fields>;
}
-keepattributes Signature
#蓝牙打印机的配置
-keep public class com.gengcon.www.jcprintersdk.**{*;}
-keep public class com.niimbot.canvas.image.**{*; }
-keep public class com.dothantech.**{*;}
-keep public class zpSDK.zpSDK.**{*;}
-keep public class com.snbc.sdk.**{*;}
-keep public class android_serialport_api.**{*;}
-dontwarn com.gengcon.www.jcprintersdk.**
-dontwarn com.jingchen.jcimagesdk.**
-dontwarn com.niimbot.canvas.image.**
-dontwarn com.dothantech.**
-dontwarn zpSDK.zpSDK.**
-dontwarn com.snbc.sdk.**
-dontwarn android_serialport_api.**

View File

@ -10,8 +10,8 @@
{
"type": "SINGLE",
"filters": [],
"versionCode": 2506051,
"versionName": "3.1.20250605.01",
"versionCode": 2507041,
"versionName": "3.1.20250704.01",
"outputFile": "app-release.apk"
}
]

View File

@ -47,7 +47,10 @@
android:supportsRtl="true"
android:theme="@style/Theme.NewPersonalCenter"
tools:targetApi="n">
<activity android:name=".v.activity.BluetoothActivity"/>
<activity android:name=".v.activity.BluetoothActivity"
android:configChanges="orientation|screenSize"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustUnspecified|stateHidden|stateAlwaysHidden|adjustPan"/>
<activity
android:name=".v.activity.applyfo.PersonnelReviewActivity"
android:configChanges="orientation|screenSize"

View File

@ -8,7 +8,7 @@
<button class="buttonClass" id="buttonId22" onclick="callJS()">JS弹框</button>
<p>
<button class="buttonClass" id="buttonId101" onclick="linkBluetooth()">接蓝牙</button>
<button class="buttonClass" id="buttonId101" onclick="linkBluetooth()">接蓝牙</button>
<p>
<button class="buttonClass" id="buttonId102" onclick="printContentssss()">打印内容</button>
@ -60,14 +60,14 @@
<script>
function linkBluetooth() {
callByAndroid.openBluetooth();
callByAndroid.openJCBluetooth();
}
function printContentssss() {
<!-- alert(111111111)-->
var json = '[{"content":"文字内容","printType":1},{"content":"二维码内容","printType":2}]';
callByAndroid.printContentsJSON(json);
var json = '[{"pageWidth":70,"pageHeight":50,"printData":[{"content":"文字内容","printType":1,"contentWidth":70,"contentHeight:":90},{"content":"二维码内容","printType":2,"zoomLevel":5,"contentWidth":35,"contentHeight:":35}]},{"pageWidth":70,"pageHeight":50,"printData":[{"content":"文字内容","printType":1,"contentWidth":70,"contentHeight:":90},{"content":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAACdFJREFUeF7tnc1uFEcQgKsXIxEJInDkA5IjecnNvAA3mwtP4AM34+BIzgEpL5CAkxdAyiFImNi55eAn4GJz4wXinGAXYYkDwlhRJJBib0e19sAwTHdXT/9M906NhEDsTE9X1ddV1T39I4CvTmtAdFp6Fh4YgI5DwAAwAB3XQMfFZw/AAHRcAx0Xnz0AA5CnBi6uDeZ6R7A8rr0czbUihegNhYAXbx72t1p5v4eXZucBxob/b3QXhLjlQX4/RUgYAsjd0dne+uGD/tBPoXFKyQqA6dXBXQB5L45qGrwFQRBi62Cjv97g6VYeyQaAS6vPdwTAYitasn6puJcLBFkAkHzLrwUkDwiSB+Di6mCxB3LHuhEm8MAIxPXDjf5uAlVRViF5AKZvPx+AgNosf+bLKViYvzAWDv8d+9rbfwdP9v5Vv1bC8ODRlX7setm8L2kAvvpucEtKuVknEBp87cYMXJ09ZyOv93tf/3MEP2+/Avy7/ko7FCQNgK71/7h0uXXjFwZH49/5/WW9/RP3AskCoGv9C/Pn4fsbM95bs0uBvz1+rQwHQoiVVAeLkgVA1+3784f0wqrOC0iA3bcbV667ABbq2SQAKA/rSpCLuv5+iq2/MA7mAnv775WhQAoYCimHotd7cixhmEIPoTUAPhrdbmQPXT9CkOL11/57+GX7Fb1qpyOHI4AnbcEQHQDs1wuQd5uO6qXo/knJoAkLCcORECuxQYgGQNMWX9Zbyu6fFAZMEIx/j9ttjAKALqMn6eT0pqVrl2Dp2kWbR6Lfu/30ELafvnV7b8SPSsEB8DmOn3L8LyxunQdoUQnvDYICMH372ab1d/sx/fVDv79++3UrQ742zdnUHbTPfcJCEAwAq8+3RTY8BX+gsntHclCn9JQTwHJ9b96vrT7gxyGYguGZY1gcSblMhkHKrYNH36zYgEi9NwgAZLcvYSh6Yr08SqbKF+Znz8FPS5epcrV6n2o8oPp1EGWlgxDGE3gHgP75tl4gFQA59ABMPQHVkDC1wYT4vOwdgOnV51Lb/Az93UkAQP1dQN2KT+Y6yh1V/jPWKerurLjuc96hVwBMcZ8yJq5qDTl0AQvw1V1BvRtHCMSR3NTlBhQd2sQ/bwCYXD+14l0GAA1HgcBnKPAGgLb1a76Jo8BlYlVTvtEDpPoNoNricJZQ3WAQNgI5JT5k8ypXbgoH1MZE8QReADC1fh2xjcYKKJLlcI+me3cydF7fHUbRfHkBLwDoY78+7jEA6v69rnfgywt4AUCZ+ROmQzEAagC0+QBBtxQn6AyA7kMPZSoUA6Af4dPp10cYcAZAaUAioQyAHgC9F3AfIvYAgGrePm3ochznpExnoSfFb3q7R+5SxviVuQCxkemq6w6AYuRvNCX6PkesvOk8w4J0vSzXMOAEgK5iBxtXnMrO0E5Bq6xKtFsFQJmgBPx8GVTLCReu6mpTEu1gIYABiEeMekyAlmupaurkpkNVKp5a83lTKF27AaCY8uXqlvIxS7yahvK2DEA8Gzq9iQFwUl/+DzMA+dvQSQIGwEl9+T/MAORvQycJGAAn9eX/MAOQuQ1Phs1hoen+gQxAxgB8Or2r2cgdA5ApAPUTPO0hYAAyBUA5X9JykQcDkCEApoUyNit9GIDMAKCs97OZ2csAZASAaZ0EimJjfLyfAcgEANOCjrEYlvGfAcjJ+KYVvg1X9bAHyAACY9LX0PjsASbE+C5bwLEHSBgC3xl/nagMQKIAUDJ+TPpcD45gABIEgJTxO8T9ssgMQGIAmDZxKKrrunCjKIcBSAwASsbvkvRVxWUAEgKAYnzbkT6TeAyASUORfo+R8XMvIJIxbV8TK+NnAGwtE+H+mBk/AxDBoDaviJ3xZw9A0339ca/9B49fjzeFbuMkUBUU2sOgTh8KvZMp7j2IW9B+djkuxQ+yNrAJAOWDFlI5FRSVTTF+jJ3MJxqAukMWinOB2zwihnL8SwzjI4gTDYCulYV2rSq3Tzn6BSGNFa4mFgCKi40NgfYs4BIxMc8vnkgAzCdvf9Q2tjY8Myj0Ra1TTONPdAhAhWN2qzxytWTxGC43RY800QCgcAiBaov1aosP2UOgGD9W0leVeyJDQFVIStaNz4ToIVDeHSsM1YW5TgCAglMMUSjIV3JIyfjxnbHjfhmEzgCgjXc1TcMVghQz/k57gEJ4ajZehIQmPQTqO5qMbPrurXTKAzSFwHZQJuWkr5NJYF2rse0mrt2Ygauz54wNMCfjT3w30GQt227iwvwF7THzlESzzYyfc4AaDdhAgI+rksMcMn4GQOMSKK1X1U3MJeNnAAwxQZkR1zxXuHJqxu/arTSFs6a/d7IXoFMW1aBFNxFBMH1vaGuYlwIFA6DICzCbRxhcr5SN3/legMkTUL8mqsqJ8ZXRFVD2ABoN2vYQqkW1OcZPBSNNAPDMP5D3qkK0kUg1hSAH46cbAhICoIDQpZtIbY1t3KeWy37X0XL9naaFqxYsLsyfB/yA0tZF6SamnvRVdYd5DspVvVzPZ3ICQLVWLgXl6rqJqQ3zUhqK6ttFkgCkomAVBLnE/TIYN+8PajlxPaLXzQOsDeZ6R7K2ZqkouQpBKvWitPriHl1Icz2i1wkArKBqs4S284CygosewslcwvM2uk/iXlX8B8d1gSicMwCqDRNSCQOFBRGClBac2pB15/eXtaOdrvHfCwC6dfMpTKWyUXSK9+rcv2v89wKALgyk5gVSNLCpTqrWj8+5xn9vACg3MNJMzDAJzr9rVgSPleM2AFTo1zkHwIJ0YSDkSp5JhsQ0c8lH6/fmAbAgnRfgUGCPqn7Sqp/W7xUA0yZKKXUL7c0R9wnTjGVfrd8rACYvgL8zBGaQTMb3Ffu95gBlsaZvP9sEIW6pROVwoIbAZHzfu4969wAfEkLDsSmcGH4KQbE7mnZqm4ct5+vQ89ILqBZsygeK+zEk4OSRXEfozA5df4fNJBZfu45XaxQEgLEnGB+WLHdMSkLj4+fj+dkvshynN8lX9zu2+L/338P207ekx0MZP0gIKEtE3WGzeAZhKP4gEJNyFa59b/+dcWr6JzLj8XJCrBxu9HdD6SKYBygqbAtBKEGzKzdQzI8WAj7zBEewXDeBNDvDRKmwv4EeU3WDe4AqCOJIbgqARVPFOvl7gxNFXfUUFYCisjhsPJJymUE41YiEoeiJ9TcP+1uuBrV9vhUAyvnBmWNY7CQMEoYgxNbBRn/d1mg+728VgGp4gCOYOyNgDv9fjkYLPgVttSzRG467XAJeHEsYhszqbeVMBgDbivP9fjTAAPjRY7alMADZms5PxRkAP3rMthQGIFvT+ak4A+BHj9mWwgBkazo/FWcA/Ogx21L+ByHRYvkl6tFhAAAAAElFTkSuQmCC","printType":3,"contentWidth:":90,"contentHeight:":90}]}]';
callByAndroid.printJCContentsJSON(json);
}
function showNetError() {

View File

@ -0,0 +1,467 @@
package com.ycgis.macall.jcBluetooth;
import android.graphics.Bitmap;
import android.os.Handler;
import android.util.Log;
import com.gengcon.www.jcprintersdk.JCPrintApi;
import com.gengcon.www.jcprintersdk.bean.PaperInfo;
import com.gengcon.www.jcprintersdk.callback.Callback;
import com.gengcon.www.jcprintersdk.callback.PrintCallback;
import com.rs.macall.androidx.basemodel.utils.BitMapUtils;
import com.rs.macall.androidx.basemodel.utils.StringUtil;
import com.ycgis.macall.personalcenter.m.datamodel.PrintData;
import com.ycgis.macall.personalcenter.m.datamodel.PrintModel;
import com.ycgis.macall.personalcenter.p.app.RuanseeApplication;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
*
* @author zhangbin
*/
public class PrintUtil {
public static final Map<Integer, String> ERROR_MESSAGES = new HashMap<>();
private static final int PERMISSION_REQUEST_CODE = 1524;
static {
ERROR_MESSAGES.put(-1, "打印机未连接");
ERROR_MESSAGES.put(1, "盒盖打开");
ERROR_MESSAGES.put(2, "缺纸");
ERROR_MESSAGES.put(3, "电量不足");
ERROR_MESSAGES.put(4, "电池异常");
ERROR_MESSAGES.put(5, "手动停止");
ERROR_MESSAGES.put(6, "数据错误");
ERROR_MESSAGES.put(7, "温度过高");
ERROR_MESSAGES.put(8, "出纸异常");
ERROR_MESSAGES.put(9, "正在打印");
ERROR_MESSAGES.put(10, "没有检测到打印头");
ERROR_MESSAGES.put(11, "环境温度过低");
ERROR_MESSAGES.put(12, "打印头未锁紧");
ERROR_MESSAGES.put(13, "未检测到碳带");
ERROR_MESSAGES.put(14, "不匹配的碳带");
ERROR_MESSAGES.put(15, "用完的碳带");
ERROR_MESSAGES.put(16, "不支持的纸张类型");
ERROR_MESSAGES.put(17, "纸张类型设置失败");
ERROR_MESSAGES.put(18, "打印模式设置失败");
ERROR_MESSAGES.put(19, "设置浓度失败");
ERROR_MESSAGES.put(20, "写入rfid失败");
ERROR_MESSAGES.put(21, "边距设置失败");
ERROR_MESSAGES.put(22, "通讯异常");
ERROR_MESSAGES.put(23, "打印机连接断开");
ERROR_MESSAGES.put(24, "画板参数错误");
ERROR_MESSAGES.put(25, "旋转角度错误");
ERROR_MESSAGES.put(26, "json参数错误");
ERROR_MESSAGES.put(27, "出纸异常(B3S)");
ERROR_MESSAGES.put(28, "检查纸张类型");
ERROR_MESSAGES.put(29, "RFID标签未进行写入操作");
ERROR_MESSAGES.put(30, "不支持浓度设置");
ERROR_MESSAGES.put(31, "不支持的打印模式");
}
private static final String TAG = "PrintUtil";
private static int mConnectedType = -1;
/**
* 使 volatile 线
*/
private static volatile JCPrintApi api;
/**
*
*/
private static final Callback CALLBACK = new Callback() {
private static final String TAG = "PrintUtil";
/**
*
*
* @param address MAC WIFI IP
* @param type 0 1 WIFI
*/
@Override
public void onConnectSuccess(String address, int type) {
mConnectedType = type;
}
/**
*
*
*/
@Override
public void onDisConnect() {
mConnectedType = -1;
}
/**
*
*
*
* @param powerLevel 1 4 1 4 4
*/
@Override
public void onElectricityChange(int powerLevel) {
}
/**
*
* H10/D101/D110/D11/B21/B16/B32/Z401/B3S/B203/B1/B18
*
* @param coverStatus 0 1
*/
@Override
public void onCoverStatus(int coverStatus) {
}
/**
*
* H10/D101/D110/D11/B21/B16/B32/Z401/B203/B1/B18
*
* @param paperStatus 0 1
*/
@Override
public void onPaperStatus(int paperStatus) {
}
/**
* rfid
* rfid
*
* @param rfidReadStatus 0RFID 1RFID H10/D101/D110/D11/B21/B16/B32/Z401/B203/B1/B18
*/
@Override
public void onRfidReadStatus(int rfidReadStatus) {
}
/**
* rfid
* rfid
*
* @param ribbonRfidReadStatus 0RFID 1RFID B18/B32/Z401/P1/P1S
*/
@Override
public void onRibbonRfidReadStatus(int ribbonRfidReadStatus) {
}
/**
*
*
*
* @param ribbonStatus 0 1 B18/B32/Z401/P1/P1S
*/
@Override
public void onRibbonStatus(int ribbonStatus) {
}
/**
*
*
*/
@Override
public void onFirmErrors() {
}
};
/**
* JCPrintApi
*
* @return JCPrintApi
*/
public static JCPrintApi getInstance() {
// 双重检查锁定以确保只初始化一次实例
if (api == null) {
synchronized (PrintUtil.class) {
if (api == null) {
api = JCPrintApi.getInstance(CALLBACK);
//api.init已废弃使用initSdk替代方法名含义更准确
api.initSdk(RuanseeApplication.getApplication());
//获取内置目录路径
// File directory = MyApplication.getInstance().getFilesDir();
//获取自定义字体路径
// File customFontDirectory = new File(directory, "custom_font");
// api.initDefaultImageLibrarySettings(customFontDirectory.getAbsolutePath(), "");
}
}
}
return api;
}
/**
* mac
*
* @param address
* @return
*/
public static int connectBluetoothPrinter(String address) {
// 获取单例实例以确保线程安全
JCPrintApi localApi = getInstance();
//api.openPrinterByAddress(address)使用connectBluetoothPrinter替代方法名含义更准确
return localApi.connectBluetoothPrinter(address);
}
/**
*
*/
public static void close() {
// 获取单例实例以确保线程安全
JCPrintApi localApi = getInstance();
localApi.close();
}
public static int getConnectedType() {
return mConnectedType;
}
public static void setConnectedType(int connectedType) {
mConnectedType = connectedType;
}
/**
*
*
* @return
*/
public static int isConnection() {
// 获取单例实例以确保线程安全
JCPrintApi localApi = getInstance();
return localApi.isConnection();
}
/**
*
*/
public interface PrintStatusCallback {
void onProgress(int pageIndex, int quantityIndex);
void onError(int errorCode, int printState);
void onCancelJob(boolean isSuccess);
void onPrintComplete();
}
public static void startLabelPrintJob(int copies, int density, int labelType, int mode,
Handler handler,
List<String> jsonList, List<String> infoList, PrintStatusCallback callback) {
// 打印参数校验
if (isConnection() != 0) {
handler.post(() -> callback.onError(-1, 0));
return;
}
// 初始化打印状态
AtomicInteger generatedPages = new AtomicInteger(0);
AtomicBoolean isError = new AtomicBoolean(false);
AtomicBoolean isCancel = new AtomicBoolean(false);
int pages = jsonList.size();
// 设置打印总量
getInstance().setTotalPrintQuantity(pages * copies);
// 启动打印任务
getInstance().startPrintJob(density, labelType, mode, new PrintCallback() {
@Override
public void onProgress(int pageIndex, int quantityIndex, HashMap<String, Object> hashMap) {
handler.post(() -> callback.onProgress(pageIndex, quantityIndex));
if (pageIndex == pages && quantityIndex == copies) {
getInstance().endPrintJob();
handler.post(callback::onPrintComplete);
}
}
@Override
public void onError(int i) {
//无需处理
}
@Override
public void onError(int errorCode, int printState) {
isError.set(true);
handler.post(() -> callback.onError(errorCode, printState));
}
@Override
public void onCancelJob(boolean success) {
isCancel.set(success);
handler.post(() -> callback.onCancelJob(success));
}
@Override
public void onBufferFree(int pageIndex, int bufferSize) {
if (isError.get() || isCancel.get() || pageIndex > pages) return;
Log.d(TAG, "测试:onBufferFree ");
// 生成打印数据
int commitSize = Math.min(pages - generatedPages.get(), bufferSize);
List<String> subJson = jsonList.subList(generatedPages.get(), generatedPages.get() + commitSize);
List<String> subInfo = infoList.subList(generatedPages.get(), generatedPages.get() + commitSize);
getInstance().commitData(subJson, subInfo);
generatedPages.addAndGet(commitSize);
}
});
}
/**
*
*/
public static boolean drawLabelJson(PrintModel printModel) {
/**
* //-1失败0成功
* public int state = -1;
*
* //间隙⾼度(⿊标⾼度)(单位像素)
* public int gapHeightPixel;
*
* //纸张⾼度(包含间隙)(单位像素)
* public int totalHeightPixel;
*
* //纸张类型 1:间隙纸; 2:⿊标纸; 3:连续纸; 4:定孔纸; 5:透明纸; 6:标牌;
* public int paperType;
*
* //间隙⾼度(⿊标⾼度)(单位毫⽶)
* public float gapHeight;
*
* //纸张⾼度(包含间隙)(单位毫⽶)
* public float totalHeight;
*
* //纸张宽度(包含间隙)(单位像素)
* public int paperWidthPixel;
*
* //纸张宽度(包含间隙)(单位毫⽶)
* public float paperWidth;
*
* //尾巴⽅向1上2下3左4右暂不⽀持
* public int direction;
*
* //尾巴⻓度(单位像素)
* public int tailLengthPixel;
* //尾巴⻓度(单位毫⽶)
* public float tailLength
*/
List<PrintData> printData = printModel.getPrintData();
if (printData == null) return false;
float width = printModel.getPageWidth();
float height = printModel.getPageHeight();
int orientation = 0;
float marginX = 2.0F;
float marginY = 2.0F;
float rectangleWidth = width - marginX * 2;
float rectangleHeight = height - marginY * 2;
float fontSize = 6.0F;
float offsetY = 0F;
float offsetX = 0F;
float lineWidth = 0.5F;
float lineHeight = rectangleHeight / 5.0F;
PrintUtil.getInstance().drawEmptyLabel(width, height, orientation, new ArrayList<>());
//已经绘制的高度
float yhzgd = 2f;
for (int i = 0; i < printData.size(); i++) {
PrintData data = printData.get(i);
if (data == null) continue;
if (data.getPrintType() == 1) {
String content = data.getContent();
if (StringUtil.isNullOrEmpty(content)) {
continue;
}
fontSize = data.getTextSize();
// 绘制⽂本
PrintUtil.getInstance().drawLabelText(marginX, yhzgd, rectangleWidth, rectangleHeight,
content, "", fontSize, 0, 1, 0, 2, 0, 1, new boolean[]{true, false, false, false});
float v = content.length() * fontSize + (marginX * 2);
yhzgd += fontSize;
if (v > width) {//如果换行了就再加一行的高度
yhzgd = fontSize + 1f;
}
} else if (data.getPrintType() == 2) {//二维码
float qrWidth = 10;
int contentHeight = Math.max(data.getContentHeight(), data.getContentWidth());
//页面可用高度
float v = height - (yhzgd + 3f) - marginY * 2;
if (contentHeight > v) {
qrWidth = v;
} else {
qrWidth = contentHeight;
}
float v1 = rectangleWidth - qrWidth;
float startX = 2f;
if (v1>0){
startX = v1/2 +marginX;
}
//绘制二维码
PrintUtil.getInstance().drawLabelQrCode(startX, yhzgd + 3f,
qrWidth, qrWidth, data.getContent(), 31, 0);
yhzgd += 3f + qrWidth;
} else if (data.getPrintType() == 3) {// 图片
if (StringUtil.isNullOrEmpty(data.getContent()))continue;
String base64 = data.getContent().replace("data:image/png;base64,", "");
Bitmap bitmap = BitMapUtils.base64ToBitmap(base64);
if (bitmap == null) continue;
int bitmapWidth = bitmap.getWidth();
int bitmapHeight = bitmap.getHeight();
//页面可用高度
float v = height - (yhzgd + 3f) - marginY * 2;
float imgWidth = 10;
float imgHeight = 10;
// 如果图片本身就小于画布,直接返回原始尺寸
if (bitmapWidth <= rectangleWidth && bitmapHeight <= v) {
imgWidth = bitmapWidth;
imgHeight = bitmapHeight;
} else {
// 计算宽高缩放比例
float widthRatio = (float) rectangleWidth / bitmapWidth;
float heightRatio = (float) v / bitmapHeight;
// 选择较小的缩放比例,以确保图片能完整显示在画布内
float scaleRatio = Math.min(widthRatio, heightRatio);
// 计算缩放后的新尺寸
imgWidth = (bitmapWidth * scaleRatio);
imgHeight = (bitmapHeight * scaleRatio);
}
float v1 = rectangleWidth - imgWidth;
float startX = 2f;
if (v1>0){
startX = v1/2 +marginX;
}
//绘制二维码
PrintUtil.getInstance().drawLabelImage(base64, startX, yhzgd + 3f,
imgWidth, imgHeight, 0, 1, 127);
}
}
return true;
}
}

View File

@ -0,0 +1,87 @@
package com.ycgis.macall.personalcenter.m.datamodel;
/**
* created by: Macall
* create time: 2025/6/27 9:43
* copyright: @ruansee.com
* Describe:
*/
public class PrintData {
private String content;
private int printType;
private int contentWidth;
private int contentHeight;
//文字大小
private int textSize;
private int zoomLevel;
private int pageWidth;
private int pageHeight;
public int getZoomLevel() {
if (zoomLevel>32) return 32;
return Math.max(zoomLevel, 1);
}
public void setZoomLevel(int zoomLevel) {
this.zoomLevel = zoomLevel;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getPrintType() {
return printType;
}
public void setPrintType(int printType) {
this.printType = printType;
}
public int getContentWidth() {
return contentWidth;
}
public void setContentWidth(int contentWidth) {
this.contentWidth = contentWidth;
}
public int getContentHeight() {
return contentHeight;
}
public void setContentHeight(int contentHeight) {
this.contentHeight = contentHeight;
}
public int getPageWidth() {
return pageWidth;
}
public void setPageWidth(int pageWidth) {
this.pageWidth = pageWidth;
}
public int getPageHeight() {
return pageHeight;
}
public void setPageHeight(int pageHeight) {
this.pageHeight = pageHeight;
}
public int getTextSize() {
return Math.max(textSize,6);
}
public void setTextSize(int textSize) {
this.textSize = textSize;
}
}

View File

@ -1,5 +1,7 @@
package com.ycgis.macall.personalcenter.m.datamodel;
import java.util.List;
/**
* created by: Macall
* create time: 2025/5/29 16:56
@ -7,73 +9,34 @@ package com.ycgis.macall.personalcenter.m.datamodel;
* Describe:
*/
public class PrintModel {
// "content":"文字内容",
// * "printType":1
private String content;
private int printType;
private int contentWidth;
private int contentHeight;
private int pageHeight;
private int pageWidth;
private int zoomLevel;
private float pageWidth;
private float pageHeight;
public int getZoomLevel() {
if (zoomLevel>32) return 32;
return Math.max(zoomLevel, 1);
private List<PrintData> printData;
public float getPageWidth() {
return pageWidth;
}
public void setZoomLevel(int zoomLevel) {
this.zoomLevel = zoomLevel;
public void setPageWidth(float pageWidth) {
this.pageWidth = pageWidth;
}
public String getContent() {
return content;
public float getPageHeight() {
return pageHeight;
}
public void setContent(String content) {
this.content = content;
}
public int getPrintType() {
return printType;
}
public void setPrintType(int printType) {
this.printType = printType;
}
public int getContentWidth() {
return contentWidth;
}
public void setContentWidth(int contentWidth) {
this.contentWidth = contentWidth;
}
public int getContentHeight() {
return contentHeight;
}
public void setContentHeight(int contentHeight) {
this.contentHeight = contentHeight;
}
public int getPageHeight() {
if (pageHeight<100)return 100;
return Math.min(pageHeight,2000);
}
public void setPageHeight(int pageHeight) {
public void setPageHeight(float pageHeight) {
this.pageHeight = pageHeight;
}
public int getPageWidth() {
if (pageWidth<100)return 100;
return Math.min(pageWidth,2000);
public List<PrintData> getPrintData() {
return printData;
}
public void setPageWidth(int pageWidth) {
this.pageWidth = pageWidth;
public void setPrintData(List<PrintData> printData) {
this.printData = printData;
}
}

View File

@ -61,7 +61,7 @@ public class RuanseeApplication extends BaseApplication {
AuthConfig config = AuthConfig.builder();
config.setThemeColor(ContextCompat.getColor(getApplicationContext(), R.color.colorAccent));
config.setAuthTypes(types);
AuthSDK.init("55b161aefd464849b48986a1073d5622", this, config);
AuthSDK.init(getAppCache().getSysmCode(), this, config);
// AuthMarkManager.setShowAuthMark(true);
//应用中心检测更新
MarketConfigure.init(this, "442eab382e6a49649e3402115bd8837f", MarketConfigure.MarketDeviceType.DEVICE_TYPE_PHONE);

View File

@ -32,6 +32,7 @@ import com.rs.macall.androidx.basemodel.utils.BitMapUtils;
import com.rs.macall.androidx.basemodel.utils.LogUtils;
import com.ycgis.macall.personalcenter.R;
import com.ycgis.macall.personalcenter.m.adapterbean.BluetoothOV;
import com.ycgis.macall.personalcenter.m.datamodel.PrintData;
import com.ycgis.macall.personalcenter.m.datamodel.PrintModel;
import com.ycgis.macall.personalcenter.m.provider.BluetoothBroadcastReceiver;
import com.ycgis.macall.personalcenter.v.adapter.BluetoothListAdapter;
@ -105,12 +106,12 @@ public class BluetoothManage {
}
// 发送数据
public boolean sendData(List<PrintModel> dataList) {
public boolean sendData(List<PrintData> dataList) {
if (outputStream != null) {
if (dataList == null) return false;
try {
for (int i = 0; i < dataList.size(); i++) {
PrintModel printModel = dataList.get(i);
PrintData printModel = dataList.get(i);
if (printModel.getPrintType() == 1) {
outputStream.write(printModel.getContent().getBytes("GBK")); // 部分打印机需GBK编码
} else if (printModel.getPrintType() == 2) {

View File

@ -103,16 +103,16 @@ public class BluetoothActivity extends BaseViewBindActivity<ActivityBluetoothBin
if (v.getId() == R.id.btn_printer) {
//{"content":"二维码内容","printType":2},{"content":"base64","printType":3}
String prContent = "[{\"content\":\"皖A97B21\n\",\"printType\":1},{\"content\":\"测试全部中文\",\"printType\":2}]";
Type type = new TypeToken<List<PrintModel>>() {
}.getType();
List<PrintModel> data = new Gson().fromJson(prContent, type);
boolean b = BluetoothSocket.getInstance().sendData(data);
if (b) {
ToastUtil.centered(getContext(),"打印完成");
} else {
ToastUtil.centered(getContext(),"打印失败");
// mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-4", "打印失败!");
}
// Type type = new TypeToken<List<PrintModel>>() {
// }.getType();
// List<PrintModel> data = new Gson().fromJson(prContent, type);
// boolean b = BluetoothSocket.getInstance().sendData(data);
// if (b) {
// ToastUtil.centered(getContext(),"打印完成");
// } else {
// ToastUtil.centered(getContext(),"打印失败");
//// mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-4", "打印失败!");
// }
}
}

View File

@ -5,12 +5,14 @@ import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
@ -19,7 +21,11 @@ import android.view.ViewGroup;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.annotation.MainThread;
import com.gengcon.www.jcprintersdk.bean.PaperInfo;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.just.agentweb.AgentWeb;
@ -29,6 +35,7 @@ import com.king.zxing.CameraScan;
import com.rs.macall.androidx.basemodel.base.BaseViewBindActivity;
import com.rs.macall.androidx.basemodel.callback.CustomClickListener;
import com.rs.macall.androidx.basemodel.callback.PermissionListener;
import com.rs.macall.androidx.basemodel.utils.BitMapUtils;
import com.rs.macall.androidx.basemodel.utils.HandlerUtils;
import com.rs.macall.androidx.basemodel.utils.LogUtils;
import com.rs.macall.androidx.basemodel.utils.StatusBarUtil;
@ -43,9 +50,11 @@ import com.ruansee.macall.unifyservemodulesdk.bean.ComponentBaseBean;
import com.ruansee.macall.unifyservemodulesdk.bean.FaceIdentifyBean;
import com.ruansee.macall.unifyservemodulesdk.bean.NFCBean;
import com.ruansee.macall.unifyservemodulesdk.bean.OcrSfzBean;
import com.ycgis.macall.jcBluetooth.PrintUtil;
import com.ycgis.macall.personalcenter.BuildConfig;
import com.ycgis.macall.personalcenter.R;
import com.ycgis.macall.personalcenter.databinding.ActivityOpenAppBinding;
import com.ycgis.macall.personalcenter.m.datamodel.PrintData;
import com.ycgis.macall.personalcenter.m.datamodel.PrintModel;
import com.ycgis.macall.personalcenter.m.model.SelectFileOptions;
import com.ycgis.macall.personalcenter.p.app.CrashHandler;
@ -66,6 +75,8 @@ import com.ycgis.zpSDK.BluetoothSocket;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.net.URLDecoder;
@ -307,36 +318,6 @@ public class OpenAppActivity extends BaseViewBindActivity<ActivityOpenAppBinding
// }
}
/**
* RemoteService
*/
// private void initService() {
// Log.w(TAG, "initService");
// Intent intent = new Intent(getContext(), RemoteService.class);
//// intent.setComponent(new ComponentName("com.hongri.webview", "com.hongri.webview.service.RemoteService"));
// bindService(intent, mConn, BIND_AUTO_CREATE);
// }
//
// private final ServiceConnection mConn = new ServiceConnection() {
// @Override
// public void onServiceConnected(ComponentName name, IBinder service) {
//// Log.w(TAG, "onServiceConnected");
// //当Service绑定成功时通过Binder获取到远程服务代理
// calculateInterface = CalculateInterface.Stub.asInterface(service);
//
// String url = getUrl();
// LogUtils.d(TAG, url);
//// mAgentWeb.getUrlLoader().loadUrl("file:///android_asset/TestJs.html");
// mAgentWeb.getUrlLoader().loadUrl(url);
// }
//
// @Override
// public void onServiceDisconnected(ComponentName name) {
//// Log.d(TAG, "onServiceDisconnected");
// calculateInterface = null;
// }
// };
private void createFileDir(String fileDirName) {
File file = new File(fileDirName);
if (file.exists()) return;
@ -868,11 +849,11 @@ public class OpenAppActivity extends BaseViewBindActivity<ActivityOpenAppBinding
return;
}
BluetoothDevice remoteDevice = BluetoothSocket.getInstance().getRemoteDevice();
if (remoteDevice!=null){
ToastUtil.centered(getContext(),"蓝牙已连接");
if (remoteDevice != null) {
ToastUtil.centered(getContext(), "蓝牙已连接");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothResult", "1", "蓝牙已连接!");
}else {
openBluetoothFragment();
} else {
openBluetoothFragment(false);
}
}
@ -897,12 +878,92 @@ public class OpenAppActivity extends BaseViewBindActivity<ActivityOpenAppBinding
* "pageHeight":100
* }
* ]
*
* @param json
*/
@JavascriptInterface
public void printContentsJSON(String json) {
ToastUtil.centered(getContext(),"JS调起打印事件");
LogUtils.w(TAG,"打印内容:"+json);
ToastUtil.centered(getContext(), "JS调起打印事件");
LogUtils.w(TAG, "打印内容:" + json);
if (StringUtil.isNullOrEmpty(json)) {
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-3", "没有打印内容!");
return;
}
Type type = new TypeToken<List<PrintData>>() {
}.getType();
List<PrintData> data = new Gson().fromJson(json, type);
boolean b = BluetoothSocket.getInstance().sendData(data);
if (b) {
ToastUtil.centered(getContext(), "打印完成");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothResult", "2", "打印完成!");
} else {
ToastUtil.centered(getContext(), "打印失败");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-4", "打印失败!");
}
}
@JavascriptInterface
public void openJCBluetooth() {
BluetoothManage instance = BluetoothManage.getInstance();
if (!instance.init()) {
ToastUtil.centered(getContext(), "当前设备不支持蓝牙!");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-1", "当前设备不支持蓝牙");
return;
}
if (!instance.isBluetoothOpen(getActivity(), true)) {
ToastUtil.centered(getContext(), "请先打开蓝牙!");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-2", "蓝牙未打开");
return;
}
if (PrintUtil.isConnection() == 0) {
ToastUtil.centered(getContext(), "蓝牙已连接");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothResult", "1", "蓝牙已连接!");
return;
}
openBluetoothFragment(true);
}
/**
* [
* {
* "pageWidth": 100,
* "pageHeight": 100,
* "printData": [
* {
* "content": "文字内容",
* "printType": 1,
* "contentWidth": 100,
* "contentHeight:": 90
* },
* {
* "content": "二维码内容",
* "printType": 2,
* "zoomLevel": 5,
* "contentWidth": 100,
* "contentHeight:": 100
* },
* {
* "content": "data:image/png;base64",
* "printType": 3,
* "contentWidth:": 90,
* "contentHeight:": 90
* }
* ]
* }
* ]
* @param json
*/
@JavascriptInterface
public void printJCContentsJSON(String json) {
if (PrintUtil.isConnection() != 0) {
ToastUtil.centered(getContext(), "打印机未连接,请先链接打印机!");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-3", "打印机未连接");
return;
}
ToastUtil.centered(getContext(), "JS调起打印事件");
LogUtils.w(TAG, "打印内容:" + json);
if (StringUtil.isNullOrEmpty(json)) {
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-3", "没有打印内容!");
return;
@ -910,29 +971,97 @@ public class OpenAppActivity extends BaseViewBindActivity<ActivityOpenAppBinding
Type type = new TypeToken<List<PrintModel>>() {
}.getType();
List<PrintModel> data = new Gson().fromJson(json, type);
boolean b = BluetoothSocket.getInstance().sendData(data);
if (b) {
ToastUtil.centered(getContext(),"打印完成");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothResult", "2", "打印完成!");
} else {
ToastUtil.centered(getContext(),"打印失败");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-4", "打印失败!");
if (data == null){
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-3", "没有打印内容!");
return;
}
List<String> jsonList = new ArrayList<>();
List<String> infoList = new ArrayList<>();
for (int i = 0; i < data.size(); i++) {
PrintModel printModel = data.get(i);
if (printModel == null)continue;
//绘制内容
boolean b = PrintUtil.drawLabelJson(printModel);
if (!b)continue;
//⽣成打印数据
byte[] jsonByte = PrintUtil.getInstance().generateLabelJson();
try {
jsonList.add(new String(jsonByte,"UTF-8"));
String info = "{\"printerImageProcessingInfo\": {"+
"\"orientation\": 0,"+
"\"margin\": [3,3,3,3],"+
"\"printQuantity\": 1,"+
"\"horizontalOffset\": 0,"+
"\"verticalOffset\": 0,"+//垂直偏移
"\"width\":"+printModel.getPageWidth()+","+//画布宽度单位mm
"\"height\": "+printModel.getPageHeight()+","+//画布⾼度单位mm
"\"printMultiple\": 11.81,"+//打印倍率 200dpi的打印机为8300dpi的打印机为11.81
"\"epc\": \"\"}}";//RFID标签写⼊数据B32R机器打印RFID标签时填充数据其他场景默认”“
infoList.add(info);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
if (jsonList.isEmpty()){
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-3", "没有打印内容!");
return;
}
PrintUtil.startLabelPrintJob(1, 5, 1, 2, new Handler(Looper.getMainLooper()),jsonList ,infoList , new PrintUtil.PrintStatusCallback() {
@Override
public void onProgress(int pageIndex, int quantityIndex) {
String progress = "打印进度:已打印到第" + pageIndex + "页,第" + quantityIndex + "份";
LogUtils.w(progress);
}
@Override
public void onError(int errorCode, int printState) {
String errorMessage = PrintUtil.ERROR_MESSAGES.containsKey(errorCode) ? PrintUtil.ERROR_MESSAGES.get(errorCode) : "未知错误";
ToastUtil.centered(getContext(),errorMessage);
LogUtils.e("onError",errorCode,printState);
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-4", "打印失败!");
}
@Override
public void onCancelJob(boolean isSuccess) {
String s = isSuccess ? "打印已取消" : "取消失败";
LogUtils.i("onCancelJob",s);
ToastUtil.centered(getContext(),s);
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-4", "打印失败!");
}
@Override
public void onPrintComplete() {
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothResult", "2", "打印完成!");
}
});
}
}
private void openBluetoothFragment() {
/**
* 使
* @param isJC
*/
private void openBluetoothFragment(boolean isJC) {
// 在Activity中
BluetoothDialogFragment dialog = new BluetoothDialogFragment();
dialog.setBluetoothFragmentListener(new BluetoothFragmentListener() {
@Override
public void onClickBluetoothDevice(BluetoothDevice device) {
if (isJC){
linkBluetoothJC(device);
}else {
linkBluetooth(device);
}
}
@Override
public void onError(int code, String msg) {
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", code+"",msg);
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", code + "", msg);
}
});
dialog.show(getSupportFragmentManager(), "MyDialog");
@ -946,13 +1075,33 @@ public class OpenAppActivity extends BaseViewBindActivity<ActivityOpenAppBinding
private void linkBluetooth(BluetoothDevice device) {
baseShowDialog("正在链接");
if (!BluetoothSocket.getInstance().ConnectPrinter(device.getAddress())) {
ToastUtil.centered(getContext(),"蓝牙连接失败");
ToastUtil.centered(getContext(), "蓝牙连接失败");
//Toast.makeText(this, "Connect Fail", Toast.LENGTH_SHORT).show();
baseDismissDialog();
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-3", "蓝牙连接失败!");
isLinkPrinter = false;
} else {
ToastUtil.centered(getContext(),"蓝牙已连接");
ToastUtil.centered(getContext(), "蓝牙已连接");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothResult", "1", "蓝牙已连接!");
baseDismissDialog();
isLinkPrinter = true;
}
}
/*
*
*/
private void linkBluetoothJC(BluetoothDevice device) {
baseShowDialog("正在链接");
int i = PrintUtil.connectBluetoothPrinter(device.getAddress());
if (i == -1) {
ToastUtil.centered(getContext(), "蓝牙连接失败");
//Toast.makeText(this, "Connect Fail", Toast.LENGTH_SHORT).show();
baseDismissDialog();
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothError", "-3", "蓝牙连接失败!");
isLinkPrinter = false;
} else {
ToastUtil.centered(getContext(), "蓝牙已连接");
mAgentWeb.getJsAccessEntrace().quickCallJs("callBluetoothResult", "1", "蓝牙已连接!");
baseDismissDialog();
isLinkPrinter = true;

View File

@ -84,21 +84,22 @@ public class BluetoothDialogFragment extends DialogFragment {
boolean init = BluetoothManage.getInstance().init();
if (!init) {
ToastUtil.centered(getContext(), "当前设备不支持蓝牙!");
if (bluetoothFragmentListener!=null) bluetoothFragmentListener.onError(-1,"当前设备不支持蓝牙");
if (bluetoothFragmentListener != null)
bluetoothFragmentListener.onError(-1, "当前设备不支持蓝牙");
dismiss();
return;
}
if (!BluetoothManage.getInstance().isBluetoothOpen(getActivity(), true)) {
ToastUtil.centered(getContext(), "请先打开蓝牙!");
if (bluetoothFragmentListener!=null) bluetoothFragmentListener.onError(-2,"蓝牙未打卡");
if (bluetoothFragmentListener != null) bluetoothFragmentListener.onError(-2, "蓝牙未打卡");
dismiss();
return;
}
btAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice remoteDevice = BluetoothSocket.getInstance().getRemoteDevice();
if (remoteDevice != null){
viewBinding.tvPrinters.setText("已连接|"+remoteDevice.getName());
}else {
if (remoteDevice != null) {
viewBinding.tvPrinters.setText("已连接|" + remoteDevice.getName());
} else {
viewBinding.tvPrinters.setText("未连接打印机");
}
@ -113,7 +114,7 @@ public class BluetoothDialogFragment extends DialogFragment {
getActivity().registerReceiver(mBroadcastReceiver, filter);
}
private void onBindView(int viewId){
private void onBindView(int viewId) {
if (viewId == R.id.btn_search) {
discovry_do();
}
@ -132,7 +133,7 @@ public class BluetoothDialogFragment extends DialogFragment {
// 设置Dialog宽度
if (getDialog() != null && getDialog().getWindow() != null) {
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
DimensionConvert.dip2px(getContext(),680));
DimensionConvert.dip2px(getContext(), 640));
}
}
@ -156,8 +157,8 @@ public class BluetoothDialogFragment extends DialogFragment {
Set<BluetoothDevice> PairedDevices = btAdapter.getBondedDevices();
if (PairedDevices.size() > 0) {
for (BluetoothDevice device : PairedDevices) {
if (device == null)continue;
if (StringUtil.isNullOrEmpty(device.getAddress()))continue;
if (device == null) continue;
if (StringUtil.isNullOrEmpty(device.getAddress())) continue;
// String device_info = device.getName()+"\n"+device.getAddress();
pdDataList.add(device);
}
@ -172,7 +173,7 @@ public class BluetoothDialogFragment extends DialogFragment {
listAdapter1.setListClickListener(new SimpleListClickListener() {
@Override
public void onSingleClick(View v, int pointer) {
if (bluetoothFragmentListener != null){
if (bluetoothFragmentListener != null) {
bluetoothFragmentListener.onClickBluetoothDevice(listAdapter1.getDataItem(pointer));
}
dismiss();
@ -208,9 +209,8 @@ public class BluetoothDialogFragment extends DialogFragment {
}
private void initSearch(BluetoothDevice device) {
if (StringUtil.isNullOrEmpty(device.getAddress()))return;
if (StringUtil.isNullOrEmpty(device.getAddress())) return;
if (listAdapter2 == null) {
searchDataList.add(device);
listAdapter2 = new BluetoothListAdapter(getContext(), searchDataList);
@ -218,7 +218,7 @@ public class BluetoothDialogFragment extends DialogFragment {
listAdapter2.setListClickListener(new SimpleListClickListener() {
@Override
public void onSingleClick(View v, int pointer) {
if (bluetoothFragmentListener != null){
if (bluetoothFragmentListener != null) {
bluetoothFragmentListener.onClickBluetoothDevice(listAdapter2.getDataItem(pointer));
}
dismiss();
@ -237,8 +237,11 @@ public class BluetoothDialogFragment extends DialogFragment {
Log.d("BT", "----------onReceive----------" + action);
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
initSearch(device);
boolean supportBluetoothType = device.getType() == BluetoothDevice.DEVICE_TYPE_CLASSIC || device.getType() == BluetoothDevice.DEVICE_TYPE_DUAL;
if (supportBluetoothType) {
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
initSearch(device);
}
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
viewBinding.btnSearch.setVisibility(View.VISIBLE);

View File

@ -11,6 +11,7 @@ import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.rs.macall.androidx.basemodel.utils.BitMapUtils;
import com.rs.macall.androidx.basemodel.utils.StringUtil;
import com.ycgis.macall.personalcenter.m.datamodel.PrintData;
import com.ycgis.macall.personalcenter.m.datamodel.PrintModel;
import java.io.ByteArrayOutputStream;
@ -193,16 +194,15 @@ public class BluetoothSocket {
return true;
}
// 发送数据
public boolean sendData(List<PrintModel> dataList) {
public boolean sendData(List<PrintData> dataList) {
if (!isConnected())return false;
if (myOutStream != null) {
if (dataList == null) return false;
try {
boolean isNewline = dataList.size()>1;
for (int i = 0; i < dataList.size(); i++) {
PrintModel printModel = dataList.get(i);
PrintData printModel = dataList.get(i);
if (printModel == null) continue;
if (printModel.getPrintType() == 1) {
String content = printModel.getContent();
@ -235,8 +235,8 @@ public class BluetoothSocket {
}
public boolean printText(String content, PrintModel model) throws UnsupportedEncodingException {
zpPrinter zpSDK = new zpPrinter();
public boolean printText(String content, PrintData model) throws UnsupportedEncodingException {
ZpPrinter zpSDK = new ZpPrinter();
zpSDK.pageSetup(model.getPageWidth(), model.getPageHeight());
//zpSDK.drawBarCode(10,10,"123456789012",1,0,4,80);
zpSDK.alignLeft();
@ -245,10 +245,10 @@ public class BluetoothSocket {
return Write(print.getBytes(GBK));
}
public boolean printBitMap(PrintModel model){
public boolean printBitMap(PrintData model){
Bitmap bitmap = BitMapUtils.base64ToBitmap(model.getContent());
if (bitmap == null) return false;
zpPrinter zpSDK = new zpPrinter();
ZpPrinter zpSDK = new ZpPrinter();
zpSDK.pageSetup(model.getPageWidth(), model.getPageHeight());
zpSDK.drawGraphic(10,10,model.getContentHeight(),model.getContentWidth(),bitmap);
byte[] bytes = zpSDK.printByte(0, 1);
@ -256,8 +256,8 @@ public class BluetoothSocket {
return Write(gzipBytes); // 部分打印机需GBK编码
}
public boolean printQrCode(PrintModel model) {
zpPrinter zpSDK = new zpPrinter();
public boolean printQrCode(PrintData model) {
ZpPrinter zpSDK = new ZpPrinter();
try {
zpSDK.pageSetup(model.getPageWidth(), model.getPageHeight());
zpSDK.drawQrCode(10, 10, model.getContent(), 0, model.getZoomLevel(), 4);

View File

@ -19,12 +19,12 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class printPDF {
public class PrintPDF {
Context mCotext;
ArrayList<Bitmap> mbitmaps=null;
public printPDF(Context con)
public PrintPDF(Context con)
{
mCotext = con;
mbitmaps = new ArrayList<Bitmap>();

View File

@ -1,227 +0,0 @@
package com.ycgis.zpSDK;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
public class UsbSocket {
Context context;
String TAG="zpSDK";
static UsbSocket mUsbSocket=null;
private int sysVersion;
public static UsbSocket getInstance(Context context)
{
if (mUsbSocket==null)
mUsbSocket=new UsbSocket(context);
return mUsbSocket;
}
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
UsbManager mUsbManager;
UsbSocket(Context context)
{
this.context=context;
sysVersion = Integer.parseInt(Build.VERSION.SDK);
// if(sysVersion<19)
// context.onNewIntent(context.getIntent());
context.registerReceiver(mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED));
context.registerReceiver(mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
}
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if(UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action))
{
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if(device.getVendorId()==1155&&device.getProductId()==22339)
{
Log.e(TAG, "USB打印机已接入");
Toast.makeText(context,"USB打印机已接入", Toast.LENGTH_LONG).show();
}
}
if(UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action))
{
UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if(device.getVendorId()==1155&&device.getProductId()==22339)
{
Log.e(TAG, "USB打印机已断开");
Toast.makeText(context,"USB打印机已断开", Toast.LENGTH_LONG).show();
}
}
}
};
public void ConnectPrinter()
{
context.registerReceiver(mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED));
context.registerReceiver(mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
}
public String Write(byte[] prnData)
{
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
while(deviceIterator.hasNext())
{
//Log.d("zpSDK","USB deviceIterator");
UsbDevice usbDevice = deviceIterator.next();
//Log.d("zpSDK",String.valueOf(usbDevice.getVendorId())+","+String.valueOf(usbDevice.getProductId()));
if(usbDevice.getVendorId()!=1155||usbDevice.getProductId()!=22339)continue;
if(writePort(usbManager,usbDevice,prnData))
{
Log.e(TAG, "USB打印成功");
//Looper.prepare();
Toast.makeText(context,"USB打印成功", Toast.LENGTH_LONG).show();
//Looper.loop();
return "USB打印成功";
}
else
{
Log.e(TAG, "USB打印失败");
// Looper.prepare();
Toast.makeText(context,"USB打印失败", Toast.LENGTH_LONG).show();
// Looper.loop();
return "USB打印失败";
}
}
Log.e(TAG, "无法连接USB打印机");
// Looper.prepare();
Toast.makeText(context,"无法连接USB打印机", Toast.LENGTH_LONG).show();
// Looper.loop();
return "无法连接USB打印机";
}
boolean writePort(UsbManager manager,UsbDevice usbDev, byte[] data)
{
boolean success=false;
UsbEndpoint end_in = null;
UsbEndpoint end_out = null;
byte[] buffer = new byte[64];
try {
UsbInterface interf = usbDev.getInterface(0);
UsbDeviceConnection connection = manager.openDevice(usbDev);//连接usb设备
if (connection == null) {
Log.d(TAG, "mUsbDeviceConnection can't be null");
return false;
}
if (connection.claimInterface(interf, true)) {
//Log.d(TAG,"claimInterface success");
int endpointCount = interf.getEndpointCount();
for (int i = 0; i < endpointCount; i++) {
UsbEndpoint endpoint = interf.getEndpoint(i);
if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (UsbConstants.USB_DIR_IN == endpoint.getDirection()) {
end_in = endpoint;//获取读数据通道
} else if(UsbConstants.USB_DIR_OUT == endpoint.getDirection()){
end_out = endpoint;//获取写数据通道
}
}
}
} else {
connection.close();
Log.d(TAG,"claimInterface fail");
return false;
}
if (end_out != null)
{
// bulkTransfer通过给定的endpoint来进行大量的数据传输传输的方向取决于该节点的方向
// 传输成果返回传输字节数组的长度,失败返回负数
int send_ret = connection.bulkTransfer(end_out, buffer,buffer.length,0 );
send_ret=0;
int total_length=data.length;
//API28之前的系统bulkTransfer最大包不能超过16384所以要拆包
int pack = data.length / 16384;
int j = 0;
for (j = 0; j < pack; j++) {
byte[] newBuffer = Arrays.copyOfRange(data, j * 16384, 16384 + j * 16384);
// 参数依次为:下行端点,字节数组消息,消息长度,响应时间
send_ret += connection.bulkTransfer(end_out, newBuffer, newBuffer.length, 0);
}
if(send_ret<total_length){
byte[] newBuffer = Arrays.copyOfRange(data, j * 16384, total_length);
send_ret += connection.bulkTransfer(end_out, newBuffer, newBuffer.length, 0);
}
Log.d(TAG,"send Data:"+","+String.valueOf(send_ret));
if (send_ret >= data.length)success=true;
if (connection != null)
{
connection.releaseInterface(interf);
connection.close();
}
interf = null;
connection = null;
}
} catch (Exception e)
{
e.printStackTrace();
}
return success;
}
public byte[] Read(int Timeout)
{
// UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
// UsbDeviceConnection connection = manager.openDevice(usbDev);
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
HashMap<String,UsbDevice> deviceHashMap = usbManager.getDeviceList();
Iterator<UsbDevice> iterator = deviceHashMap.values().iterator();
System.out.println("deviceHashMap.isEmpty()"+deviceHashMap.isEmpty());
UsbEndpoint inEndpoint=null;
byte[] byte2 = new byte[1024];
while(iterator.hasNext()) {
UsbDevice usbDevice = iterator.next();
if(usbDevice.getVendorId()!=1155||usbDevice.getProductId()!=22339)continue;
UsbInterface usbInterface = usbDevice.getInterface(0);//USBEndpoint为读写数据所需的节点
UsbDeviceConnection connection = usbManager.openDevice(usbDevice);
if (connection.claimInterface(usbInterface, true)) {
int endpointCount = usbInterface.getEndpointCount();
for (int i = 0; i < endpointCount; i++) {
UsbEndpoint endpoint = usbInterface.getEndpoint(i);
if (endpoint.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (UsbConstants.USB_DIR_IN == endpoint.getDirection()) {
inEndpoint = endpoint;//获取读数据通道
}
}
}
} else {
connection.close();
Log.d(TAG,"claimInterface fail");
return null;
}
int ret = connection.bulkTransfer(inEndpoint, byte2, byte2.length, Timeout);
Log.i(TAG, "ret:" + ret);
Log.i(TAG, "bat is ok length:" + byte2.length);
for (Byte byte1 : byte2) {
Log.i(TAG,"byte1 :" + byte1);
}
}
return byte2;
}
}

View File

@ -1,216 +0,0 @@
package com.ycgis.zpSDK;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Timer;
import java.util.TimerTask;
public class WifiSocket {
public static String ErrorMessage = "No Error";
private static Socket wifiSocket = null;
private static OutputStream myOutStream = null;
private static InputStream myInStream = null;
private static WifiSocket mWifiSocket = null;
wifiListener mwifiListener=null;
boolean isWrite = true;
boolean isRead = true;
private WifiSocket(wifiListener listener) {
mwifiListener = listener;
}
public static WifiSocket getInstance(wifiListener listener){
if (mWifiSocket==null)
mWifiSocket = new WifiSocket(listener);
return mWifiSocket;
}
public void ConnectPrinter(String ip) {
InetAddress mInetaddr = null;
int port = 9100;
if (ip == null||ip.equals("")) {
} else {
try {
mInetaddr = InetAddress.getByName(ip);
} catch (UnknownHostException e) {
e.printStackTrace();
}
InetAddress finalMInetaddr = mInetaddr;
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
try {
wifiSocket = new Socket(finalMInetaddr, port);
myOutStream = wifiSocket.getOutputStream();
myInStream = wifiSocket.getInputStream();
mwifiListener.receivedmsg("finish");
} catch (UnknownHostException var4) {
mwifiListener.receivedmsg("timeout");
} catch (IOException var5) {
mwifiListener.receivedmsg("timeout");
}
}
}, 1500);
mwifiListener.receivedmsg("");
}
}
public boolean disconncet() {
try {
Thread.sleep(1000L);
} catch (InterruptedException var6) {
}
mwifiListener.receivedmsg("");
mwifiListener.receivedstatus(null);
if (myOutStream != null) {
try {
myOutStream.flush();
} catch (IOException var5) {
}
try {
myOutStream.close();
} catch (IOException var4) {
}
myOutStream = null;
}
if (myInStream != null) {
try {
myInStream.close();
} catch (IOException var3) {
}
myInStream = null;
}
if (wifiSocket != null) {
try {
wifiSocket.close();
} catch (IOException var2) {
}
wifiSocket = null;
}
try {
Thread.sleep(200L);
} catch (InterruptedException var1) {
}
return true;
}
public void Write(byte[] Data) {
isWrite = true;
if (isWrite)
{
isWrite = false;
new Thread(){
@Override
public void run()
{
try {
myOutStream.write(Data);
isWrite = true;
} catch (IOException var2) {
mwifiListener.receivedmsg("发送数据失败");
}
}
}.start();
}
}
public void Write(byte[] Data, int DataLen) {
isWrite = true;
if (isWrite)
{
isWrite = false;
new Thread(){
@Override
public void run()
{
try {
myOutStream.write(Data, 0, DataLen);
isWrite = true;
} catch (IOException var2) {
mwifiListener.receivedmsg("发送数据失败");
}
}
}.start();
}
}
public static void Flush() {
int DataLen = 0;
try {
DataLen = myInStream.available();
} catch (IOException var4) {
}
for(int i = 0; i < DataLen; ++i) {
try {
myInStream.read();
} catch (IOException var3) {
}
}
}
public void Read(int Timeout) {
new Thread(){
@Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
int len = 0;
try {
len = myInStream.available();
} catch (IOException var4) {
}
if (len>0)
{
try {
myInStream.skip(myInStream.available());
} catch (IOException e) {
e.printStackTrace();
}
}
while (true)
{
try {
bytes = myInStream.read(buffer);
if (bytes>0)
{
final byte[] data = new byte[bytes];
System.arraycopy(buffer, 0, data, 0, bytes);
mwifiListener.receivedstatus(data);
return;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
}

View File

@ -11,7 +11,7 @@ import java.io.FileNotFoundException;
import java.util.List;
public class zpPrinter
public class ZpPrinter
{
private Context context;
static int w;

View File

@ -1,7 +0,0 @@
package com.ycgis.zpSDK;
public interface wifiListener {
void receivedmsg(String msg);
void receivedstatus(byte[] statue);
}

View File

@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:background="@drawable/round_top_white_8"
android:orientation="vertical"
android:layout_height="680dp">
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"

View File

@ -1,10 +1,8 @@
## This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file should *NOT* be checked into Version Control Systems,
## This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Wed Jun 25 16:46:01 CST 2025
sdk.dir=D\:\\Program Files\\sdk

View File

@ -4,7 +4,6 @@ plugins {
android {
compileSdkVersion 29
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.ruansee.macall.testwebview"
@ -58,8 +57,6 @@ dependencies {
//
implementation 'com.wang.avi:library:2.1.3'
//
implementation 'cn.jzvd:jiaozivideoplayer:7.7.0'
// Glide OkHttp
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
@ -70,4 +67,23 @@ dependencies {
implementation files('libs/com.code.base.jar')
implementation files('libs/unifyservemoduleSDK_V1.2.231127.aar')
implementation project(':BaseModel')
//Ormlite
implementation 'com.j256.ormlite:ormlite-android:5.1'
implementation 'com.j256.ormlite:ormlite-core:5.1'
implementation 'tv.danmaku.ijk.media:ijkplayer-java:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
//
implementation 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
implementation 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'
//
implementation files('libs/jiaozivideoplayer-debug.aar')
//
implementation files('libs/JCamera-release.aar')
}

Binary file not shown.

Binary file not shown.

View File

@ -13,7 +13,8 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS"/>
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:name=".app.RuanseeApp"
@ -24,18 +25,30 @@
android:roundIcon="@drawable/icon_login2"
android:supportsRtl="true"
android:theme="@style/Theme.NewPersonalCenter">
<activity android:name=".activity.SettingActivity"/>
<activity android:name=".activity.StartActivity">
<activity android:name=".activity.RecordVideoActivity"></activity>
<activity android:name=".activity.PlayVideoActivity" />
<activity
android:name=".activity.WorkbenchActivity"
android:screenOrientation="portrait" />
<activity
android:name=".activity.SettingActivity"
android:screenOrientation="portrait" />
<activity
android:name=".activity.StartActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".activity.MainActivity"/>
<activity android:name=".activity.OpenAppActivity"
<activity
android:name=".activity.MainActivity"
android:screenOrientation="portrait" />
<activity
android:name=".activity.OpenAppActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"/>
android:screenOrientation="portrait" />
<provider
android:name="androidx.core.content.FileProvider"

View File

@ -7,9 +7,11 @@ import android.os.Bundle;
import android.view.View;
import com.rs.macall.androidx.basemodel.base.BaseViewBindActivity;
import com.rs.macall.androidx.basemodel.callback.CustomClickListener;
import com.rs.macall.androidx.basemodel.utils.StringUtil;
import com.rs.macall.androidx.basemodel.utils.ToastUtil;
import com.ruansee.macall.testwebview.app.AppCacheData;
import com.ruansee.macall.testwebview.app.ContinuouslyClickListener;
import com.ruansee.macall.testwebview.app.RuanseeApp;
import com.ruansee.macall.testwebview.databinding.ActivityMainBinding;
@ -52,13 +54,17 @@ public class MainActivity extends BaseViewBindActivity<ActivityMainBinding> {
}
viewBinding.mainUserName.setText(String.format("%s(%s)",appCacheData.getUserName(),appCacheData.getDeptCode()));
viewBinding.mainDeptName.setText(StringUtil.get(appCacheData.getDeptName(),appCacheData.getDeptCode()));
viewBinding.imageView3.setOnClickListener(new ContinuouslyClickListener(){
@Override
public void onFastClick(View v) {
startActivity(new Intent(getContext(),WorkbenchActivity.class));
}
});
String idCardNum = appCacheData.getIdCardNum();
if (StringUtil.isNullOrEmpty(idCardNum)){
viewBinding.mainUserSfzh.setText("暂无");
}else {
char[] chars = idCardNum.toCharArray();
//3424221993 0 6 0 4 1 4 1 3
//0123456789 10 11 12 13 14 15
StringBuilder builder = new StringBuilder();
for (int i = 0; i <chars.length; i++) {
if (i>= 8 && i<=14){
@ -79,7 +85,7 @@ public class MainActivity extends BaseViewBindActivity<ActivityMainBinding> {
intent.putExtra(OpenAppActivity.paramKey2, appCacheData.getClientSecret());
intent.putExtra(OpenAppActivity.paramKey3, appCacheData.getAppUrl());
intent.putExtra(OpenAppActivity.paramKey9, appCacheData.getAppName());
intent.putExtra(OpenAppActivity.paramKey10, "管理员");
intent.putExtra(OpenAppActivity.paramKey10, "运维人员");
intent.putExtra(OpenAppActivity.paramKey11, "18888686866");
startActivity(intent);
}

View File

@ -0,0 +1,58 @@
package com.ruansee.macall.testwebview.activity;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import com.rs.macall.androidx.basemodel.base.BaseViewBindActivity;
import com.ruansee.macall.testwebview.databinding.ActivityPlayVideoBinding;
import com.ruansee.macall.testwebview.model.JZMediaIjk;
import cn.jzvd.Jzvd;
import cn.jzvd.JzvdStd;
public class PlayVideoActivity extends BaseViewBindActivity<ActivityPlayVideoBinding> {
private String filePath;
private String name;
@Override
protected ActivityPlayVideoBinding getViewBinding() {
return ActivityPlayVideoBinding.inflate(getLayoutInflater());
}
@Override
protected void init() {
}
@Override
protected void readInstanceState(Bundle savedInstanceState) {
filePath = getIntent().getStringExtra("filePath");
name = getIntent().getStringExtra("name");
}
@Override
protected void start() {
// 启用自动全屏时的方向旋转
Jzvd.FULLSCREEN_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
Jzvd.NORMAL_ORIENTATION = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
viewBinding.jzVideo.setUp(filePath, name, JzvdStd.SCREEN_NORMAL, JZMediaIjk.class);
viewBinding.jzVideo.startVideo();
}
@Override
public void onBackPressed() {
if (Jzvd.backPress()) {
return;
}
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
Jzvd.releaseAllVideos();
}
}

View File

@ -0,0 +1,133 @@
package com.ruansee.macall.testwebview.activity;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.View;
import com.rs.macall.androidx.basemodel.base.BaseViewBindActivity;
import com.rs.macall.androidx.basemodel.utils.BitMapUtils;
import com.rs.macall.androidx.basemodel.utils.LogUtils;
import com.rs.macall.androidx.basemodel.utils.ToastUtil;
import com.ruansee.macall.testwebview.R;
import com.ruansee.macall.testwebview.databinding.ActivityRecordVideoBinding;
import com.ruansee.macall.testwebview.utils.FileUtils;
import com.ycgis.macall.jcamera.CameraInterface;
import com.ycgis.macall.jcamera.JCameraView;
import com.ycgis.macall.jcamera.listener.ErrorListener;
import com.ycgis.macall.jcamera.listener.JCameraListener;
import java.io.File;
public class RecordVideoActivity extends BaseViewBindActivity<ActivityRecordVideoBinding> {
private String fileDir;
@Override
protected ActivityRecordVideoBinding getViewBinding() {
View decorView = getWindow().getDecorView();
int option = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(option);
return ActivityRecordVideoBinding.inflate(getLayoutInflater());
}
@Override
protected void init() {
fileDir = FileUtils.VOID_DIR;
}
@Override
protected void readInstanceState(Bundle savedInstanceState) {
}
@Override
protected void start() {
//设置只能录像或只能拍照或两种都可以(默认两种都可以)
viewBinding.jCamera.setFeatures(JCameraView.BUTTON_STATE_BOTH);
//设置视频保存路径
viewBinding.jCamera.setSaveVideoPath(fileDir);
viewBinding.jCamera.setErrorLisenter(new ErrorListener() {
@Override
public void onError() {
LogUtils.e("打卡错误");
}
@Override
public void AudioPermissionError() {
LogUtils.e("没有录音权限");
}
});
viewBinding.jCamera.setCameraOpenOverCallback(new CameraInterface.CameraOpenOverCallback() {
@Override
public void cameraHasOpened() {
runOnUiThread(new Runnable() {
@Override
public void run() {
viewBinding.jCamera.cameraHasOpened();
}
});
}
@Override
public void cameraHasOpened(boolean isBackCamera) {
runOnUiThread(new Runnable() {
@Override
public void run() {
viewBinding.jCamera.cameraHasOpened(isBackCamera);
}
});
}
});
//JCameraView监听
viewBinding.jCamera.setJCameraLisenter(new JCameraListener() {
@Override
public void captureSuccess(Bitmap bitmap) {
//获取图片bitmap
LogUtils.d("拍照成功");
}
@Override
public void recordSuccess(String url, Bitmap firstFrame, long duration) {
LogUtils.d("视频保存成功", url);
// /storage/emulated/0/Android/data/com.ruansee.macall.synthesisfight/Void//video_1750677532408.mp4
File file = new File(url);
if (file.exists()) {
Intent intent = new Intent();
intent.putExtra("filePath", file.getAbsolutePath());
intent.putExtra("type", "video");
intent.putExtra("duration", duration);
setResult(Activity.RESULT_OK, intent);
finish();
} else {
ToastUtil.centered(getContext(), "视频保存失败!");
viewBinding.jCamera.againPreviewShooting();
}
}
});
}
public String getFileName() {
return System.currentTimeMillis() + ".mp4";
}
@Override
protected void onResume() {
super.onResume();
viewBinding.jCamera.onResume();
}
@Override
protected void onPause() {
super.onPause();
viewBinding.jCamera.onPause();
}
}

View File

@ -12,6 +12,8 @@ import com.rs.macall.androidx.basemodel.callback.PermissionListener;
import com.rs.macall.androidx.basemodel.utils.HandlerUtils;
import com.ruansee.macall.testwebview.app.RuanseeApp;
import com.ruansee.macall.testwebview.databinding.ActivityStartBinding;
import com.ruansee.macall.testwebview.db.DatabaseHelp;
import com.ruansee.macall.testwebview.utils.FileUtils;
import java.util.List;
@ -23,6 +25,7 @@ public class StartActivity extends BaseViewBindActivity<ActivityStartBinding> im
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.ACCESS_NETWORK_STATE};
@Override
@ -70,8 +73,11 @@ public class StartActivity extends BaseViewBindActivity<ActivityStartBinding> im
}
private void initPage() {
FileUtils.createFilDir();
DatabaseHelp.getInstance(getContext());
viewBinding.tvMsg.setText("权限通过,正在验证用户信息...");
myHandler.sendEmptyMessageDelayed(1, 1000);
}
@Override

View File

@ -0,0 +1,204 @@
package com.ruansee.macall.testwebview.activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.view.View;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.rs.macall.androidx.basemodel.base.BaseViewBindActivity;
import com.rs.macall.androidx.basemodel.callback.SimpleListClickListener;
import com.rs.macall.androidx.basemodel.utils.DateUitls;
import com.rs.macall.androidx.basemodel.utils.HandlerUtils;
import com.rs.macall.androidx.basemodel.utils.ToastUtil;
import com.ruansee.macall.testwebview.R;
import com.ruansee.macall.testwebview.adapter.VideoAdapter;
import com.ruansee.macall.testwebview.databinding.ActivityWorkbenchBinding;
import com.ruansee.macall.testwebview.db.CacheLogTable;
import com.ruansee.macall.testwebview.db.CacheLogTableDao;
import com.ruansee.macall.testwebview.db.VideoTable;
import com.ruansee.macall.testwebview.db.VideoTableDao;
import com.ruansee.macall.testwebview.model.SearchModel;
import com.ruansee.macall.testwebview.utils.FileUtils;
import com.ruansee.macall.testwebview.utils.UriUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class WorkbenchActivity extends BaseViewBindActivity<ActivityWorkbenchBinding> {
private SearchModel searchModel;
private String nowDate;
private static final int REQUEST_VIDEO_CAPTURE = 1201;
private File videoFile;
private List<String> videoList;
private VideoAdapter adapter;
private Handler myHandler;
private VideoTableDao videoTableDao;
@Override
protected ActivityWorkbenchBinding getViewBinding() {
return ActivityWorkbenchBinding.inflate(getLayoutInflater());
}
@Override
protected void init() {
viewBinding.rvList.setLayoutManager(new GridLayoutManager(getContext(),2));
searchModel = new SearchModel(viewBinding.searchContainer,viewBinding.searchEdit,viewBinding.searchClean);
myHandler = HandlerUtils.getActivity(this);
}
@Override
protected void readInstanceState(Bundle savedInstanceState) {
}
@Override
protected void start() {
viewBinding.include.contentTitle.setText("工作台");
viewBinding.include.leftImage.setImageDrawable(getDrawables(R.drawable.back_cliener));
viewBinding.include.titleleft.setOnClickListener(v -> finish());
searchModel.init("请输入搜索内容");
nowDate = "data"+DateUitls.date2Str(new Date(),"yyyyMMdd");
searchModel.setSearchContentListener(new SearchModel.SearchContentListener() {
@Override
public void onSearch(String content) {
if (nowDate.equals(content)){
visibleView(viewBinding.btnAdd);
getVideoList();
viewBinding.btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dispatchTakeVideoIntent();
}
});
}
}
@Override
public void onClean() {
}
@Override
public void onContentUpdate(String content) {
}
});
// CacheLogTableDao<CacheLogTable> cacheLogTableCacheLogTableDao = new CacheLogTableDao<>(getContext(), CacheLogTable.class);
// List<CacheLogTable> cacheLogTables = cacheLogTableCacheLogTableDao.queryAll();
}
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
if (videoList!=null&&!videoList.isEmpty()){
initData();
}
break;
case 2:
break;
}
}
private void getVideoList() {
new Thread(){
@Override
public void run() {
videoList = new ArrayList<>();
File file = new File(FileUtils.VOID_DIR);
if (file.exists()&&file.isDirectory()){
File[] files = file.listFiles();
if (files!=null){
for (int i = 0; i < files.length; i++) {
File file1 = files[i];
if (file1.getName().endsWith(".mp4")){
videoList.add(file1.getAbsolutePath());
}
}
}
}
myHandler.sendEmptyMessage(1);
}
}
.start();
}
private void initData() {
if (adapter == null){
adapter = new VideoAdapter(getContext(),videoList);
viewBinding.rvList.setAdapter(adapter);
adapter.setListClickListener(new SimpleListClickListener() {
@Override
public void onSingleClick(View v, int pointer) {
Intent intent = new Intent(getContext(),PlayVideoActivity.class);
intent.putExtra("filePath",adapter.getDataItem(pointer));
startActivity(intent);
}
});
}else {
adapter.upData(videoList);
}
}
// 处理返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
// Uri videoUri = data.getData();
// videoUri 就是拍摄后的视频文件
// String realPathFromUri = UriUtils.getRealPathFromUri(getContext(), videoUri);
ToastUtil.centered(getContext(),"保存成功!");
saveDatabase();
}
}
private void saveDatabase() {
VideoTable table = new VideoTable();
table.setFileNam(videoFile.getName());
table.setFilePath(videoFile.getAbsolutePath());
table.setCreateTime(DateUitls.date2Str());
if (videoTableDao == null){
videoTableDao = new VideoTableDao(getContext(), VideoTable.class);
}
videoTableDao.create(table);
if (adapter!=null){
adapter.addItem(0,videoFile.getAbsolutePath());
}else {
videoList = new ArrayList<>();
videoList.add(videoFile.getAbsolutePath());
initData();
}
}
private void dispatchTakeVideoIntent() {
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
videoFile = new File(FileUtils.VOID_DIR, System.currentTimeMillis() + ".mp4");
Uri uri = UriUtils.getUri(getContext(), videoFile);
takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
// 0: 后摄像头1: 前摄像头
takeVideoIntent.putExtra("android.intent.extras.CAMERA_FACING", 1);
takeVideoIntent.putExtra("android.intent.extras.LENS_FACING_FRONT", 1);
takeVideoIntent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true);
if (takeVideoIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
}
}
}

View File

@ -0,0 +1,115 @@
package com.ruansee.macall.testwebview.adapter;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.resource.bitmap.FitCenter;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.CustomViewTarget;
import com.bumptech.glide.request.transition.Transition;
import com.rs.macall.androidx.basemodel.base.BaseRecyclerAdapter;
import com.rs.macall.androidx.basemodel.utils.DimensionConvert;
import com.rs.macall.androidx.basemodel.utils.StringUtil;
import com.ruansee.macall.testwebview.R;
import com.ruansee.macall.testwebview.databinding.ItemVideoBinding;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.List;
/**
* created by: Macall
* create time: 2025/7/5 16:39
* copyright: @ruansee.com
* Describe:
*/
public class VideoAdapter extends BaseRecyclerAdapter<String,BaseRecyclerAdapter.ViewHolder> {
public VideoAdapter(Context context, List<String> dataList) {
super(context, dataList);
}
@NonNull
@NotNull
@Override
public BaseRecyclerAdapter.ViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) {
View inflate = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_video, parent, false);
ItemVideoBinding bind = ItemVideoBinding.bind(inflate);
return new ViewBindingHolder(bind);
}
@Override
public void onBindViewHolder(@NonNull @NotNull BaseRecyclerAdapter.ViewHolder viewHolder, int position) {
if (viewHolder instanceof ViewBindingHolder){
ViewBindingHolder<ItemVideoBinding> holder =(ViewBindingHolder<ItemVideoBinding>) viewHolder;
setChatVideo(holder.viewBind.chatVideo,getDataItem(position));
}
}
/**
*
*
* @param iv
* @param showPath
*/
private void setChatVideo(ImageView iv, String showPath) {
RoundedCorners roundedCorners = new RoundedCorners(10);
MultiTransformation multiTransformation = new MultiTransformation<>(new FitCenter(), roundedCorners);
RequestOptions requestOptions = RequestOptions.bitmapTransform(multiTransformation).frame(100000);
Glide.with(context)
.asBitmap()
.load(showPath)
.apply(requestOptions)
.into(new CustomViewTarget<ImageView, Bitmap>(iv) {
@Override
public void onLoadFailed(@Nullable @org.jetbrains.annotations.Nullable Drawable errorDrawable) {
ImageView imageView = getView();
Drawable resource = ContextCompat.getDrawable(context, R.drawable.ic_load_imag_eerror);
// 这里可以根据 resource 宽高动态设置 imageView 的宽高
imageView.setImageDrawable(resource);
// 例如,强制最小宽高
int minWidth = DimensionConvert.dip2px(context, 100); // px
int minHeight = DimensionConvert.dip2px(context, 100); // px
ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
layoutParams.width = Math.max(resource.getIntrinsicWidth(), minWidth);
layoutParams.height = Math.max(resource.getIntrinsicHeight(), minHeight);
imageView.setLayoutParams(layoutParams);
}
@Override
public void onResourceReady(@NonNull @NotNull Bitmap resource, @Nullable @org.jetbrains.annotations.Nullable Transition<? super Bitmap> transition) {
ImageView imageView = getView();
// 这里可以根据 resource 宽高动态设置 imageView 的宽高
imageView.setImageBitmap(resource);
// 例如,强制最小宽高
int minWidth = DimensionConvert.dip2px(context, 130); // px
ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
layoutParams.width = Math.max(resource.getWidth(), minWidth);
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
imageView.setLayoutParams(layoutParams);
}
@Override
protected void onResourceCleared(@Nullable @org.jetbrains.annotations.Nullable Drawable placeholder) {
}
});
}
}

View File

@ -0,0 +1,44 @@
package com.ruansee.macall.testwebview.app;
import android.view.View;
/**
* created by: Macall
* create time: 2025/7/4 17:54
* copyright: @ruansee.com
* Describe:
*/
public abstract class ContinuouslyClickListener implements View.OnClickListener {
private long mLastClickTime;
private long timeInterval = 1000L;
private int clickNum = 0;
private final int maxClickNum=10;
@Override
public void onClick(View v) {
long nowTime = System.currentTimeMillis();
// LogUtils.w("点击","nowTime="+nowTime+ " mLastClickTime = "+mLastClickTime+" ; 差值="+(nowTime - mLastClickTime));
if (nowTime - mLastClickTime > timeInterval) {
// 单次点击事件
onSingleClick(v);
clickNum=1;
mLastClickTime = nowTime;
} else {
mLastClickTime = nowTime;
// 快速点击事件
if (clickNum == maxClickNum){
clickNum = 0;
onFastClick(v);
}else {
clickNum++;
}
}
}
public void onSingleClick(View v){}
public void onFastClick(View v){}
}

View File

@ -0,0 +1,29 @@
package com.ruansee.macall.testwebview.app;
import android.text.Editable;
import android.text.TextWatcher;
/**
* created by: Macall
* create time: 2025/5/23 19:49
* copyright: @ruansee.com
* Describe:
*/
public abstract class SimpleTextWatcher implements TextWatcher {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
}
}

View File

@ -0,0 +1,140 @@
package com.ruansee.macall.testwebview.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
/**
* created by: Macall
* create time: 2025/7/5 9:55
* copyright: @ruansee.com
* Describe:
*/
@DatabaseTable(tableName = "T_CacheLog")
public class CacheLogTable {
/*因为库里只缓存最后一个人员的信息 ,故 id 固定为1 所有 插入均为 update */
@DatabaseField(generatedId = true)
private long id = 1;
@DatabaseField(columnName = "userName")
private String userName;
@DatabaseField(columnName = "userCode")
private String userCode;
@DatabaseField(columnName = "deptCode")
private String deptCode;
@DatabaseField(columnName = "idCardNum")
private String idCardNum;
@DatabaseField(columnName = "deptName")
private String deptName;
@DatabaseField(columnName = "appUrl")
private String appUrl;
@DatabaseField(columnName = "appName")
private String appName;
@DatabaseField(columnName = "clientId")
private String clientId;
@DatabaseField(columnName = "clientSecret")
private String clientSecret;
@DatabaseField(columnName = "operate")
private String operate;
@DatabaseField(columnName = "time")
private String time;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserCode() {
return userCode;
}
public void setUserCode(String userCode) {
this.userCode = userCode;
}
public String getDeptCode() {
return deptCode;
}
public void setDeptCode(String deptCode) {
this.deptCode = deptCode;
}
public String getIdCardNum() {
return idCardNum;
}
public void setIdCardNum(String idCardNum) {
this.idCardNum = idCardNum;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getAppUrl() {
return appUrl;
}
public void setAppUrl(String appUrl) {
this.appUrl = appUrl;
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientSecret() {
return clientSecret;
}
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getOperate() {
return operate;
}
public void setOperate(String operate) {
this.operate = operate;
}
}

View File

@ -0,0 +1,163 @@
package com.ruansee.macall.testwebview.db;
import android.content.Context;
import android.database.SQLException;
import com.j256.ormlite.dao.Dao;
import java.util.List;
/**
* created by: Macall
* create time: 2025/7/5 10:59
* copyright: @ruansee.com
* Describe:
*/
public class CacheLogTableDao {
// ORMLite提供的DAO类对象第一个泛型是要操作的数据表映射成的实体类第二个泛型是这个实体类中ID的数据类型
protected Dao<CacheLogTable, Integer> dao;
public CacheLogTableDao(Context context, Class<CacheLogTable> tClass) {
try {
this.dao = DatabaseHelp.getInstance(context).getDao(tClass);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
/**
*
*
* @param data
*/
public void create(CacheLogTable data) {
try {
dao.createOrUpdate(data);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
/**
*
*
* @param datas
*/
public void createList(List<CacheLogTable> datas) {
try {
dao.create(datas);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
/**
* user
* <p>
* create:
* <p>
* createIfNotExists:
* <p>
* createOrUpdate:id
*
* @param data
*/
public void insert(CacheLogTable data) {
try {
dao.createIfNotExists(data);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
// 通过id删除指定数据
public void delete(int id) {
try {
dao.deleteById(id);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
// 删除表中的一条数据
public void delete(CacheLogTable data) {
try {
dao.delete(data);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
// 删除数据集合
public void deleteList(List<CacheLogTable> datas) {
try {
dao.delete(datas);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
//清空数据
public void deleteAll() {
try {
dao.delete(dao.queryForAll());
} catch (Exception e) {
e.printStackTrace();
}
}
// 修改表中的一条数据
public void update(CacheLogTable data) {
try {
dao.update(data);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
// 查询表中的所有数据
public List<CacheLogTable> queryAll() {
List<CacheLogTable> users = null;
try {
users = dao.queryForAll();
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
return users;
}
// 根据ID取出用户信息
public CacheLogTable queryById(int id) {
CacheLogTable user = null;
try {
user = dao.queryForId(id);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
return user;
}
// 单纯分页查询
public List<CacheLogTable> queryList(long page, long pageSize) {
try {
long pages = (long) (page * pageSize - pageSize);
return dao.queryBuilder().offset(pages < 0 ? 0 : pages).limit(pageSize).query();
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
return null;
}
// 通过条件查询集合例如通过messageId和title
public long queryCount() {
try {
return dao.queryBuilder().countOf();
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
return -1;
}
}

View File

@ -0,0 +1,89 @@
package com.ruansee.macall.testwebview.db;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.ArrayMap;
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;
import com.ruansee.macall.testwebview.utils.FileUtils;
/**
* created by: Macall
* create time: 2025/7/5 10:02
* copyright: @ruansee.com
* Describe:
*/
public final class DatabaseHelp extends OrmLiteSqliteOpenHelper {
// 数据库名称
public static final String DATABASE_NAME = FileUtils.DB_DIR+"rcwhy.db";
// 本类的单例实例
private static DatabaseHelp instance;
// 存储APP中所有的DAO对象的Map集合
@SuppressLint("NewApi")
private ArrayMap<String, Dao> daos = new ArrayMap<>();
// 私有的构造方法
private DatabaseHelp(Context context) {
super(context, DATABASE_NAME, null, 1);
}
// 获取本类单例对象的方法
public static synchronized DatabaseHelp getInstance(Context context) {
if (instance == null) {
synchronized (DatabaseHelp.class) {
if (instance == null) {
instance = new DatabaseHelp(context);
}
}
}
return instance;
}
// 根据传入的DAO的路径获取到这个DAO的单例对象要么从daos这个Map中获取要么新创建一个并存入daos
public synchronized Dao getDao(Class clazz) throws SQLException, java.sql.SQLException {
Dao dao = null;
String className = clazz.getSimpleName();
if (daos.containsKey(className)) {
dao = daos.get(className);
}
if (dao == null) {
dao = super.getDao(clazz);
daos.put(className, dao);
}
return dao;
}
// 释放资源
@Override
public void close() {
super.close();
for (String key : daos.keySet()) {
Dao dao = daos.get(key);
dao = null;
}
}
@Override
public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
try {
TableUtils.createTable(connectionSource, CacheLogTable.class);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
@Override
public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
}
}

View File

@ -0,0 +1,58 @@
package com.ruansee.macall.testwebview.db;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
/**
* created by: Macall
* create time: 2025/7/5 16:16
* copyright: @ruansee.com
* Describe:
*/
@DatabaseTable(tableName = "T_Video")
public class VideoTable {
@DatabaseField(generatedId = true)
private long id;
@DatabaseField(columnName = "fileName")
private String fileNam;
@DatabaseField(columnName = "filePath")
private String filePath;
@DatabaseField(columnName = "createTime")
private String createTime;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFileNam() {
return fileNam;
}
public void setFileNam(String fileNam) {
this.fileNam = fileNam;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
}

View File

@ -0,0 +1,161 @@
package com.ruansee.macall.testwebview.db;
import android.content.Context;
import android.database.SQLException;
import com.j256.ormlite.dao.Dao;
import java.util.List;
/**
* created by: Macall
* create time: 2025/7/5 16:32
* copyright: @ruansee.com
* Describe:
*/
public class VideoTableDao {
// ORMLite提供的DAO类对象第一个泛型是要操作的数据表映射成的实体类第二个泛型是这个实体类中ID的数据类型
protected Dao<VideoTable, Integer> dao;
public VideoTableDao(Context context, Class<VideoTable> tClass) {
try {
this.dao = DatabaseHelp.getInstance(context).getDao(tClass);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
/**
*
*
* @param data
*/
public void create(VideoTable data) {
try {
dao.createOrUpdate(data);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
/**
*
*
* @param datas
*/
public void createList(List<VideoTable> datas) {
try {
dao.create(datas);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
/**
* user
* <p>
* create:
* <p>
* createIfNotExists:
* <p>
* createOrUpdate:id
*
* @param data
*/
public void insert(VideoTable data) {
try {
dao.createIfNotExists(data);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
// 通过id删除指定数据
public void delete(int id) {
try {
dao.deleteById(id);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
// 删除表中的一条数据
public void delete(VideoTable data) {
try {
dao.delete(data);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
// 删除数据集合
public void deleteList(List<VideoTable> datas) {
try {
dao.delete(datas);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
//清空数据
public void deleteAll() {
try {
dao.delete(dao.queryForAll());
} catch (Exception e) {
e.printStackTrace();
}
}
// 修改表中的一条数据
public void update(VideoTable data) {
try {
dao.update(data);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
}
// 查询表中的所有数据
public List<VideoTable> queryAll() {
List<VideoTable> users = null;
try {
users = dao.queryForAll();
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
return users;
}
// 根据ID取出用户信息
public VideoTable queryById(int id) {
VideoTable user = null;
try {
user = dao.queryForId(id);
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
return user;
}
// 单纯分页查询
public List<VideoTable> queryList(long page, long pageSize) {
try {
long pages = (long) (page * pageSize - pageSize);
return dao.queryBuilder().offset(pages < 0 ? 0 : pages).limit(pageSize).query();
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
return null;
}
// 通过条件查询集合例如通过messageId和title
public long queryCount() {
try {
return dao.queryBuilder().countOf();
} catch (SQLException | java.sql.SQLException e) {
e.printStackTrace();
}
return -1;
}
}

View File

@ -0,0 +1,203 @@
package com.ruansee.macall.testwebview.model;
import android.graphics.SurfaceTexture;
import android.media.AudioManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.view.Surface;
import java.io.IOException;
import cn.jzvd.JZMediaInterface;
import cn.jzvd.Jzvd;
import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
import tv.danmaku.ijk.media.player.IjkTimedText;
/**
*
* Created by Nathen on 2017/11/18.
*/
public class JZMediaIjk extends JZMediaInterface implements IMediaPlayer.OnPreparedListener, IMediaPlayer.OnVideoSizeChangedListener, IMediaPlayer.OnCompletionListener, IMediaPlayer.OnErrorListener, IMediaPlayer.OnInfoListener, IMediaPlayer.OnBufferingUpdateListener, IMediaPlayer.OnSeekCompleteListener, IMediaPlayer.OnTimedTextListener {
IjkMediaPlayer ijkMediaPlayer;
public JZMediaIjk(Jzvd jzvd) {
super(jzvd);
}
@Override
public void start() {
if (ijkMediaPlayer != null) ijkMediaPlayer.start();
}
@Override
public void prepare() {
release();
mMediaHandlerThread = new HandlerThread("JZVD");
mMediaHandlerThread.start();
mMediaHandler = new Handler(mMediaHandlerThread.getLooper());//主线程还是非主线程,就在这里
handler = new Handler();
mMediaHandler.post(() -> {
ijkMediaPlayer = new IjkMediaPlayer();
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "max-buffer-size", 1024 * 1024);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "enable-accurate-seek", 1);
ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
ijkMediaPlayer.setOnPreparedListener(JZMediaIjk.this);
ijkMediaPlayer.setOnVideoSizeChangedListener(JZMediaIjk.this);
ijkMediaPlayer.setOnCompletionListener(JZMediaIjk.this);
ijkMediaPlayer.setOnErrorListener(JZMediaIjk.this);
ijkMediaPlayer.setOnInfoListener(JZMediaIjk.this);
ijkMediaPlayer.setOnBufferingUpdateListener(JZMediaIjk.this);
ijkMediaPlayer.setOnSeekCompleteListener(JZMediaIjk.this);
ijkMediaPlayer.setOnTimedTextListener(JZMediaIjk.this);
try {
ijkMediaPlayer.setDataSource(jzvd.jzDataSource.getCurrentUrl().toString());
ijkMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
ijkMediaPlayer.setScreenOnWhilePlaying(true);
ijkMediaPlayer.prepareAsync();
ijkMediaPlayer.setSurface(new Surface(jzvd.textureView.getSurfaceTexture()));
} catch (IOException e) {
e.printStackTrace();
}
});
}
@Override
public void pause() {
ijkMediaPlayer.pause();
}
@Override
public boolean isPlaying() {
return ijkMediaPlayer.isPlaying();
}
@Override
public void seekTo(long time) {
ijkMediaPlayer.seekTo(time);
}
@Override
public void release() {
if (mMediaHandler != null && mMediaHandlerThread != null && ijkMediaPlayer != null) {//不知道有没有妖孽
HandlerThread tmpHandlerThread = mMediaHandlerThread;
IjkMediaPlayer tmpMediaPlayer = ijkMediaPlayer;
JZMediaInterface.SAVED_SURFACE = null;
mMediaHandler.post(() -> {
tmpMediaPlayer.setSurface(null);
tmpMediaPlayer.release();
tmpHandlerThread.quit();
});
ijkMediaPlayer = null;
}
}
@Override
public long getCurrentPosition() {
return ijkMediaPlayer.getCurrentPosition();
}
@Override
public long getDuration() {
return ijkMediaPlayer.getDuration();
}
@Override
public void setVolume(float leftVolume, float rightVolume) {
ijkMediaPlayer.setVolume(leftVolume, rightVolume);
}
@Override
public void setSpeed(float speed) {
ijkMediaPlayer.setSpeed(speed);
}
@Override
public void onPrepared(IMediaPlayer iMediaPlayer) {
handler.post(() -> jzvd.onPrepared());
}
@Override
public void onVideoSizeChanged(IMediaPlayer iMediaPlayer, int i, int i1, int i2, int i3) {
handler.post(() -> jzvd.onVideoSizeChanged(iMediaPlayer.getVideoWidth(), iMediaPlayer.getVideoHeight()));
}
@Override
public boolean onError(IMediaPlayer iMediaPlayer, final int what, final int extra) {
handler.post(() -> jzvd.onError(what, extra));
return true;
}
@Override
public boolean onInfo(IMediaPlayer iMediaPlayer, final int what, final int extra) {
handler.post(() -> jzvd.onInfo(what, extra));
return false;
}
@Override
public void onBufferingUpdate(IMediaPlayer iMediaPlayer, final int percent) {
handler.post(() -> jzvd.setBufferProgress(percent));
}
@Override
public void onSeekComplete(IMediaPlayer iMediaPlayer) {
handler.post(() -> jzvd.onSeekComplete());
}
@Override
public void onTimedText(IMediaPlayer iMediaPlayer, IjkTimedText ijkTimedText) {
}
@Override
public void setSurface(Surface surface) {
ijkMediaPlayer.setSurface(surface);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
if (SAVED_SURFACE == null) {
SAVED_SURFACE = surface;
prepare();
} else {
jzvd.textureView.setSurfaceTexture(SAVED_SURFACE);
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
@Override
public void onCompletion(IMediaPlayer iMediaPlayer) {
handler.post(() -> jzvd.onAutoCompletion());
}
}

View File

@ -0,0 +1,194 @@
package com.ruansee.macall.testwebview.model;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.SeekBar;
import com.ruansee.macall.testwebview.R;
import cn.jzvd.JzvdStd;
import tv.danmaku.ijk.media.player.IMediaPlayer;
/**
*
*
* Created by Nathen on 2017/7/2.
*/
public class MyJzvdStd extends JzvdStd {
public MyJzvdStd(Context context) {
super(context);
}
public MyJzvdStd(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void init(Context context) {
super.init(context);
backButton.setVisibility(GONE);
}
@Override
public void onClick(View v) {
super.onClick(v);
int i = v.getId();
if (i == R.id.fullscreen) {
Log.i(TAG, "onClick: fullscreen button");
} else if (i == R.id.start) {
Log.i(TAG, "onClick: start button");
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
super.onTouch(v, event);
int id = v.getId();
if (id == R.id.surface_container) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (mChangePosition) {
Log.i(TAG, "Touch screen seek position");
}
if (mChangeVolume) {
Log.i(TAG, "Touch screen change volume");
}
break;
}
}
return false;
}
@Override
public int getLayoutId() {
return R.layout.jz_layout_std;
}
@Override
public void startVideo() {
super.startVideo();
Log.i(TAG, "startVideo");
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
super.onStopTrackingTouch(seekBar);
Log.i(TAG, "Seek position ");
}
@Override
public void gotoScreenFullscreen() {
super.gotoScreenFullscreen();
Log.i(TAG, "goto Fullscreen");
}
@Override
public void gotoScreenNormal() {
super.gotoScreenNormal();
Log.i(TAG, "quit Fullscreen");
}
@Override
public void autoFullscreen(float x) {
super.autoFullscreen(x);
Log.i(TAG, "auto Fullscreen");
}
@Override
public void onClickUiToggle() {
super.onClickUiToggle();
Log.i(TAG, "click blank");
}
//onState 代表了播放器引擎的回调,播放视频各个过程的状态的回调
@Override
public void onStateNormal() {
super.onStateNormal();
}
@Override
public void onStatePreparing() {
super.onStatePreparing();
}
@Override
public void onStatePlaying() {
super.onStatePlaying();
}
@Override
public void onStatePause() {
super.onStatePause();
}
@Override
public void onStateError() {
super.onStateError();
}
@Override
public void onStateAutoComplete() {
super.onStateAutoComplete();
Log.i(TAG, "Auto complete");
}
//changeUiTo 真能能修改ui的方法
@Override
public void changeUiToNormal() {
super.changeUiToNormal();
}
@Override
public void changeUiToPreparing() {
super.changeUiToPreparing();
}
@Override
public void changeUiToPlayingShow() {
super.changeUiToPlayingShow();
}
@Override
public void changeUiToPlayingClear() {
super.changeUiToPlayingClear();
}
@Override
public void changeUiToPauseShow() {
super.changeUiToPauseShow();
}
@Override
public void changeUiToPauseClear() {
super.changeUiToPauseClear();
}
@Override
public void changeUiToComplete() {
super.changeUiToComplete();
}
@Override
public void changeUiToError() {
super.changeUiToError();
}
@Override
public void onInfo(int what, int extra) {
super.onInfo(what, extra);
if(what==IMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED){
//这里返回了视频的旋转角度,根据角度旋转视频到正确角度
textureView.setRotation(extra);
}
}
@Override
public void onError(int what, int extra) {
super.onError(what, extra);
}
}

View File

@ -0,0 +1,122 @@
package com.ruansee.macall.testwebview.model;
import android.text.Editable;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import com.rs.macall.androidx.basemodel.callback.CustomClickListener;
import com.rs.macall.androidx.basemodel.utils.StringUtil;
import com.ruansee.macall.testwebview.app.SimpleTextWatcher;
/**
* created by: Macall
* create time: 2025/5/21 14:28
* copyright: @ruansee.com
* Describe:
*/
public class SearchModel {
private LinearLayout search_container;
private EditText search_edit;
private ImageView search_clean;
private SearchContentListener searchContentListener;
public void setSearchContentListener(SearchContentListener searchContentListener) {
this.searchContentListener = searchContentListener;
}
public SearchModel(LinearLayout search_container, EditText search_edit, ImageView search_clean) {
this.search_container = search_container;
this.search_edit = search_edit;
this.search_clean = search_clean;
}
/**
*
* @param layoutBackground
*/
public void layoutBackground(@DrawableRes int layoutBackground){
search_container.setBackgroundResource(layoutBackground);
}
public void init(String hintStr) {
search_clean.setVisibility(View.GONE);
search_clean.setOnClickListener(new CustomClickListener() {
@Override
public void onSingleClick(View v) {
search_edit.setText("");
if (searchContentListener != null) {
searchContentListener.onClean();
}
}
});
search_edit.setHint(StringUtil.get(hintStr, "搜索"));
search_edit.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
search_edit.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
if (searchContentListener != null) {
searchContentListener.onSearch(search_edit.getText().toString());
}
}
return false;
}
});
search_edit.addTextChangedListener(new SimpleTextWatcher() {
@Override
public void afterTextChanged(Editable s) {
if (s.length() >= 1) {
search_clean.setVisibility(View.VISIBLE);
} else {
search_clean.setVisibility(View.GONE);
if (searchContentListener != null) {
searchContentListener.onClean();
}
}
if (searchContentListener != null) {
searchContentListener.onContentUpdate(s.toString());
}
}
});
}
/**
*
*
* @param hintStr
*/
public void updateHint(String hintStr) {
search_edit.setHint(StringUtil.get(hintStr, "搜索"));
}
public interface SearchContentListener {
/**
*
*
* @param content
*/
void onSearch(String content);
/**
*
*/
void onClean();
/**
*
*
* @param content
*/
void onContentUpdate(String content);
}
}

View File

@ -88,6 +88,36 @@ public class FileUtils {
return filePath;
}
public static void createFilDir(){
File file = new File(filePath);
if (!file.exists()){
file.mkdirs();
}
file = new File(DOWNLOADS_DIR);
if (!file.exists()){
file.mkdirs();
}
file = new File(IMAGE_DIR);
if (!file.exists()){
file.mkdirs();
}
file = new File(VOID_DIR);
if (!file.exists()){
file.mkdirs();
}
file = new File(FILE_DIR);
if (!file.exists()){
file.mkdirs();
}
file = new File(DB_DIR);
if (!file.exists()){
file.mkdirs();
}file = new File(LOG_DIR);
if (!file.exists()){
file.mkdirs();
}
}
public static String getPhotoName() {
return System.currentTimeMillis() + ".jpg";
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9,3L7.17,5L4,5c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,7c0,-1.1 -0.9,-2 -2,-2h-3.17L15,3L9,3zM12,18c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,17l1.25,-2.75L16,13l-2.75,-1.25L12,9l-1.25,2.75L8,13l2.75,1.25z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
<shape android:shape="rectangle">
<solid android:color="@color/colorGrey1" />
<stroke android:width="1dp" android:color="@color/colorBluen2" />
<corners android:radius="@dimen/dp5" />
</shape>
</item>
<item android:state_focused="false">
<shape android:shape="rectangle">
<solid android:color="@color/colorWhite" />
<stroke android:width="1dp" android:color="@color/colorGrey2" />
<corners android:radius="@dimen/dp5" />
</shape>
</item>
</selector>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/icon_add_def" android:state_pressed="false"/>
<item android:drawable="@drawable/icon_add_sel" android:state_pressed="true"/>
</selector>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorGrey2"
tools:context=".activity.PlayVideoActivity">
<com.ruansee.macall.testwebview.model.MyJzvdStd
android:id="@+id/jz_video"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="48dp"
android:layout_marginBottom="48dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.RecordVideoActivity">
<com.ycgis.macall.jcamera.JCameraView
android:id="@+id/j_camera"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:duration_max="300000"
app:camera_position="rearMounted"
app:camera_switching="true"
app:iconMargin="20dp"
app:iconSize="30dp"
app:iconSrc="@drawable/ic_camera_enhance_black_24dp"
/>
</FrameLayout>

View File

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.WorkbenchActivity">
<include
android:id="@+id/app_title"
layout="@layout/app_base_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="@dimen/dp42"
android:layout_marginHorizontal="@dimen/dp15"
android:layout_marginVertical="@dimen/dp8"
android:layout_marginStart="15dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="15dp"
android:background="@drawable/edit_background"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/app_title">
<ImageView
android:id="@+id/search_icon"
android:layout_width="@dimen/dp25"
android:layout_height="@dimen/dp25"
android:layout_marginStart="@dimen/dp5"
android:src="@drawable/icon_search" />
<EditText
android:id="@+id/search_edit"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginHorizontal="@dimen/dp5"
android:layout_weight="1"
android:background="@null"
android:hint="搜索"
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1"
android:textColor="@color/colorGrey8"
android:textColorHint="@color/colorGrey6"
android:textSize="@dimen/sp16" />
<ImageView
android:id="@+id/search_clean"
android:layout_width="@dimen/dp30"
android:layout_height="@dimen/dp25"
android:paddingEnd="@dimen/dp5"
android:src="@drawable/icon_search_delete" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/search_container" />
<ImageButton
android:id="@+id/btn_add"
android:layout_width="@dimen/dp68"
android:layout_height="@dimen/dp68"
android:background="@null"
android:src="@drawable/icon_add"
android:layout_marginEnd="@dimen/dp60"
android:layout_marginBottom="@dimen/dp60"
android:scaleType="fitXY"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/dp180"
android:layout_height="@dimen/dp200"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:id="@+id/chat_video"
android:layout_width="@dimen/dp100"
android:layout_height="@dimen/dp100"
android:adjustViewBounds="true"
android:gravity="left|center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/icon_login2" />
<ImageView
android:id="@+id/chat_play"
android:layout_width="@dimen/dp38"
android:layout_height="@dimen/dp38"
android:src="@drawable/icon_play"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/chat_video_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginBottom="5dp"
android:text="0:32"
android:textColor="@color/colorGrey4"
android:textSize="@dimen/sp10"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="@dimen/dp42"
android:layout_marginHorizontal="@dimen/dp15"
android:layout_marginVertical="@dimen/dp8"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:background="@drawable/edit_background"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/search_icon"
android:layout_width="@dimen/dp25"
android:layout_height="@dimen/dp25"
android:layout_marginStart="@dimen/dp5"
android:src="@drawable/icon_search" />
<EditText
android:id="@+id/search_edit"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginHorizontal="@dimen/dp5"
android:layout_weight="1"
android:background="@null"
android:hint="搜索"
android:inputType="text"
android:imeOptions="actionSearch"
android:maxLines="1"
android:textColor="@color/colorGrey8"
android:textColorHint="@color/colorGrey6"
android:textSize="@dimen/sp16" />
<ImageView
android:id="@+id/search_clean"
android:layout_width="@dimen/dp30"
android:layout_height="@dimen/dp25"
android:paddingEnd="@dimen/dp5"
android:src="@drawable/icon_search_delete" />
</LinearLayout>