Compare commits
67 Commits
20adea0533
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 3365972f83 | |||
| 2f8f958a6a | |||
| f91790d046 | |||
| 038c96fbe0 | |||
| 210d599ce0 | |||
| b9897fa0c6 | |||
| 16281e386d | |||
| 55e624111d | |||
| 588f378a40 | |||
| 55cd99687b | |||
| c3e3d6de61 | |||
| bc8142c157 | |||
| 46b6b43a0f | |||
| d949619023 | |||
| 1e3c32eb2e | |||
| c5579771d9 | |||
| 2d43980458 | |||
| 0800e0eaf0 | |||
| ce30c6cf7b | |||
| cdc07256ee | |||
| 47715f0fd6 | |||
| 59c228f36c | |||
| 5769b7670b | |||
| 12c928f059 | |||
| 724e691188 | |||
| e24a8955a2 | |||
| ec798944ad | |||
| 57094bfbd4 | |||
| 4af4aac1e5 | |||
| 23df4da1ff | |||
| 5f9b5cd2e5 | |||
| 3e4af1c2d1 | |||
| 2a13c1a886 | |||
| 832b0e3368 | |||
| bcfb6155d2 | |||
| 10fdade4da | |||
| 17a0889e08 | |||
| 483cce8fd5 | |||
| 46199cda0f | |||
| 3bc08317d0 | |||
| 40c330795c | |||
| 0a19e1f587 | |||
| e2a34d76a6 | |||
| 4aa71457fe | |||
| 3613dd6a21 | |||
| 26e9ad63f5 | |||
| 2485332d77 | |||
| 27216aa2af | |||
| 2c72ce04f6 | |||
| f80dd211f1 | |||
| 5199147f58 | |||
| d80325553d | |||
| 0f435a565d | |||
| 0cb5922557 | |||
| d63d7ecee3 | |||
| 6786cf2908 | |||
| a56e76f552 | |||
| 9cad5923d8 | |||
| 6fb1768a1b | |||
| b4e1d2c06f | |||
| f1137bfbf2 | |||
| 4bd42b98d5 | |||
| 8ce4133e50 | |||
| 05b8ddf0fd | |||
| 61a9adab5e | |||
| 50a191f675 | |||
| bbd9a7e85c |
2
.idea/compiler.xml
generated
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="1.8" />
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/encodings.xml
generated
@ -7,8 +7,6 @@
|
||||
<file url="file://$PROJECT_DIR$/app/jni/gen_SerialPort_h.sh" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/app/jni/rockchip.c" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/app/libs/armeabi" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/app/libs/armeabi-v7a" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/app/libs/armeabi-v7a/libmsc.so" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/app/libs/armeabi/librockchip.so" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/app/libs/x86" charset="GBK" />
|
||||
<file url="file://$PROJECT_DIR$/app/src/main/java/chaoran/business/adapter/librockchip.so" charset="GBK" />
|
||||
|
||||
10
.idea/jarRepositories.xml
generated
@ -31,5 +31,15 @@
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://maven.aliyun.com/repository/jcenter/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/misc.xml
generated
@ -10,7 +10,7 @@
|
||||
</option>
|
||||
</component>
|
||||
<component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" interpreter_name="PHP-5.6.25" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
||||
@ -3,17 +3,62 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "30.0.2"
|
||||
compileSdk 28
|
||||
buildToolsVersion '30.0.3'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "chaoran.business.pda"
|
||||
minSdkVersion 22
|
||||
targetSdkVersion 29
|
||||
minSdk 28
|
||||
targetSdk 28
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
versionName "2.18"
|
||||
|
||||
// 1.0 IDATA广播模式处理
|
||||
// 1.1 霍尼韦尔的监听修改(扫描网站二维码跳出程序,监听失效,调整)、斑马PDA广播模式设置
|
||||
// 1.2 霍尼韦尔EDA56、jdk11,gradle7.3、海信PDA广播支持
|
||||
// 1.3 东集 pda的支持
|
||||
// 1.4 联新 pda的支持 已经 adapter 关闭的判断
|
||||
// 1.5 urovo DT50 Lite pda的支持
|
||||
// 1.6 瑞星平板扫描,线程读取一半就返回处理
|
||||
// 1.7 暴露一个方法,跳转到index初始化页面
|
||||
// 1.8 霍尼韦尔EDA50p,在返回桌面,点击了新的扫描之后,出现再进入程序(新打开一样)无法扫描,从而导致问题,添加了一个stop2的方法,针对霍尼韦尔eda50p,不进行销毁,在真正销毁的方法关闭服务,还是存在程序返回桌面无法扫描问题,但是退出程序之后,新打开程序可以扫描
|
||||
// 1.9 海康威视 mv-idp5102 适配广播模式
|
||||
// 1.10 bug 代码判断没有结束
|
||||
// 1.11 霍尼韦尔EDA52
|
||||
// 1.12 屏幕旋转,采取配置化模式(只能竖屏、横屏);取消旋转屏幕就重置activity生命周期
|
||||
// 1.13 新大陆pda 兼容广播模式;NLS-NFT10
|
||||
// 1.14 瑞芯 rk3566_r 添加引用 librockchip.so; 新加一个方法,返回当前PDA的厂家和型号
|
||||
// 1.15 系统状态栏根据配置进行设置
|
||||
// 1.16 idata pda 不设置模式
|
||||
// 1.17 霍尼韦尔EDA51、EDA50P,调用扫描枪的方法,在关闭的时候停止调用扫描枪
|
||||
// 1.18 瑞兴平板,读取扫描结果,使用同步加锁模式
|
||||
// 1.19 index页面接入初始化数据
|
||||
// 2.1 注册PDA的信息存储到文件内部,采取mac+固定加密串的MD5加密校验
|
||||
// 2.2 安卓14以上,无法获取mac地址,修改成获取唯一id作为mac地址
|
||||
// 2.3 适配IOT_Device:sc55g PDA 广播模式
|
||||
// 2.4 适配 qualcomm:mc50 PDA 广播模式
|
||||
// 2.5 mac地址存储文件(mac获取失败就随机一个);监听返回按键,提示是否退出程序的提示窗口
|
||||
// 2.6 1、打开程序的时候清空缓存(为了程序更新的时候,不被缓存影响,不用手动清除、出现了用户手动清除的时候吧存储空间清除了);
|
||||
// 2、判断是否初始化成功(webview成功),如果已经加载完毕,那么apk不在拦截,调用js的方法让BS进行处理提示
|
||||
// 3、根据官方文档,将code的判断进行修改,添加了一个网络错误的页面进行提示(并且添加了一个重新加载的按钮,执行webview重新加载)
|
||||
// 2.7 海康威视 mv-idp5204 适配广播模式;和之前的idp5102厂家code不一样 宿州市立医院-李德
|
||||
// 2.8 编写一个通用的广播模式,action:chaoran.crtech.cn.pda.scan key:barcode
|
||||
// 2.9 初始化屏幕方向
|
||||
// 2.10 再次添加了init.json文件,进行初始化ip等参数
|
||||
// 2.11 优化了保存配置的时候,重新加载页面方法,去设置初始化屏幕方向,已经init.json中添加了字段备注信息
|
||||
// 2.12 群创科技接入广播模式 中山市古镇人民医院 蒋凡
|
||||
// 2.13 取消监听旋转角度,使用系统自带的旋转(根据配置初始化,旋转方向:横、竖、随意)
|
||||
// 瑞芯适配器 接入 新的型号,使用的是 ttyS8;而不是ttyS1;并且只有一个接口。
|
||||
// 2.14 适配 AIFUU 陈安良:陆军特色中心医院
|
||||
// 2.15 添加文件选择和相机拍照功能
|
||||
// 2.16 暴露了一个直接调用相机的方法,非http input调用会出现默认的弹出窗口进行选择(相机、文件)
|
||||
// 2.17 支持原生相机,默认压缩;支持霍尼韦尔eda52服务扫描
|
||||
// 2.18 瑞兴平板,rk3568_r,存在两个ttyS8、ttyS1,2G内存之前是ttyS8才可以接收,4G内存的ttyS8直接报错,导致打不开,需要缓存ttyS1,改成兼容模式
|
||||
// 支持霍尼韦尔eda52服务扫描修改成广播模式,医院那边不要所谓的服务连续扫描
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a'
|
||||
}
|
||||
}
|
||||
|
||||
//签名配置
|
||||
@ -54,12 +99,22 @@ android {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
/* repositories {
|
||||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
}*/
|
||||
}
|
||||
dependencies {
|
||||
compileOnly 'com.symbol:emdk:9.1.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
implementation 'com.google.code.gson:gson:2.6.2'
|
||||
//加载jar包
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
//implementation fileTree(include: ['*.aar'], dir: 'libs')
|
||||
// 全屏,没有状态栏
|
||||
api 'com.readystatesoftware.systembartint:systembartint:1.0.3'
|
||||
implementation files('libs/armeabi-v7a/librockchip.so')
|
||||
}
|
||||
BIN
app/libs/DataCollection.jar
Normal file
BIN
app/libs/Msc.jar
Normal file
BIN
app/libs/arm64-v8a/libmsc.so
Normal file
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="chaoran.business">
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
@ -10,23 +10,40 @@
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="com.symbol.emdk.permission.EMDK"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="com.honeywell.decode.permission.DECODE" />
|
||||
<uses-permission android:name="android.permission.STOP_SERVICE" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:fitsSystemWindows="true"
|
||||
android:name=".application.InitApplication"
|
||||
android:theme="@style/Theme.PdaWeb"
|
||||
android:usesCleartextTraffic="true">
|
||||
android:usesCleartextTraffic="true"
|
||||
>
|
||||
<uses-library android:name="com.symbol.emdk" android:required="false"/>
|
||||
<activity
|
||||
android:name=".activity.NetworkSettingActivity"
|
||||
android:label="@string/title_activity_setting_network" />
|
||||
<activity
|
||||
android:name=".activity.VoiceSettingActivity"
|
||||
android:label="@string/title_activity_setting_voice" />
|
||||
<activity
|
||||
android:name=".activity.FileTestActivity"
|
||||
android:label="@string/title_activity_file_test" />
|
||||
<activity
|
||||
android:name=".activity.MainActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@ -34,6 +51,27 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service android:name=".service.ScanServiceEDA50P" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.example.chaoran.ScanServiceEDA50P"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name=".service.ScanServiceZEBRA">
|
||||
<intent-filter>
|
||||
<action android:name="com.example.chaoran.ScanServiceZEBRA"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
175
app/src/main/assets/demo/file_test.html
Normal file
@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>文件选择测试</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; padding: 20px; max-width: 600px; margin: 0 auto; }
|
||||
.section { margin: 20px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }
|
||||
h2 { color: #333; margin-top: 0; }
|
||||
input[type="file"] { display: block; margin: 10px 0; padding: 10px; width: 100%; box-sizing: border-box; }
|
||||
.preview { margin-top: 15px; max-width: 100%; }
|
||||
.preview img { max-width: 100%; height: auto; border: 1px solid #ddd; border-radius: 5px; }
|
||||
.info { margin-top: 10px; padding: 10px; background-color: #f5f5f5; border-radius: 5px; font-size: 14px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>文件选择和相机测试</h1>
|
||||
|
||||
<!-- 测试1:选择任意文件 -->
|
||||
<div class="section">
|
||||
<h2>1. 选择任意文件</h2>
|
||||
<input type="file" id="fileInput" onchange="handleFileSelect(this)">
|
||||
<div id="fileInfo" class="info" style="display:none;"></div>
|
||||
</div>
|
||||
|
||||
<!-- 测试2:选择图片(支持相机和文件) -->
|
||||
<div class="section">
|
||||
<h2>2. 选择图片(支持相机)</h2>
|
||||
<!-- accept="image/*": 只接受图片, capture="environment": 启用相机 -->
|
||||
<input type="file" id="imageInput" accept="image/*" capture="environment" onchange="handleImageSelect(this)">
|
||||
<div id="imageInfo" class="info" style="display:none;"></div>
|
||||
<div id="imagePreview" class="preview"></div>
|
||||
</div>
|
||||
|
||||
<!-- 测试3:直接打开相机 -->
|
||||
<div class="section">
|
||||
<h2>3. 仅使用相机拍照</h2>
|
||||
<!-- 通过JavaScript接口直接调用相机,不显示选择器 -->
|
||||
<button onclick="openCameraDirectly()" style="padding: 10px 20px; font-size: 16px; cursor: pointer;">打开相机</button>
|
||||
<div id="cameraInfo" class="info" style="display:none;"></div>
|
||||
<div id="cameraPreview" class="preview"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 处理文件选择 - 显示文件信息
|
||||
*/
|
||||
function handleFileSelect(input) {
|
||||
var file = input.files[0]; // 获取选择的文件
|
||||
var infoDiv = document.getElementById('fileInfo'); // 获取信息显示区域
|
||||
|
||||
if (file) {
|
||||
infoDiv.style.display = 'block'; // 显示信息区域
|
||||
infoDiv.innerHTML = '<strong>文件信息:</strong><br>文件名: ' + file.name + '<br>文件大小: ' + formatFileSize(file.size) + '<br>文件类型: ' + (file.type || '未知');
|
||||
} else {
|
||||
infoDiv.style.display = 'none'; // 隐藏信息区域
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理图片选择 - 显示信息和预览
|
||||
*/
|
||||
function handleImageSelect(input) {
|
||||
var file = input.files[0]; // 获取选择的文件
|
||||
var infoDiv = document.getElementById('imageInfo');
|
||||
var previewDiv = document.getElementById('imagePreview');
|
||||
|
||||
if (file) {
|
||||
infoDiv.style.display = 'block';
|
||||
infoDiv.innerHTML = '<strong>图片信息:</strong><br>文件名: ' + file.name + '<br>文件大小: ' + formatFileSize(file.size) + '<br>文件类型: ' + file.type;
|
||||
|
||||
// 使用FileReader读取图片并显示预览
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
// e.target.result 是图片的Base64数据
|
||||
previewDiv.innerHTML = '<img src="' + e.target.result + '" alt="图片预览">';
|
||||
};
|
||||
reader.readAsDataURL(file); // 读取为DataURL格式
|
||||
} else {
|
||||
infoDiv.style.display = 'none';
|
||||
previewDiv.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接打开相机 - 通过Android接口
|
||||
*/
|
||||
function openCameraDirectly() {
|
||||
// CameraHelper是Android注入的JavaScript接口
|
||||
if (typeof CameraHelper !== 'undefined') {
|
||||
CameraHelper.openCamera(); // 调用Android方法打开相机
|
||||
} else {
|
||||
alert('相机功能不可用');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 相机拍照结果回调 - 由Android调用
|
||||
* @param uri - 照片URI
|
||||
* @param path - 照片路径
|
||||
*/
|
||||
function onCameraResult(uri, path) {
|
||||
var infoDiv = document.getElementById('cameraInfo');
|
||||
var previewDiv = document.getElementById('cameraPreview');
|
||||
|
||||
if (uri && path) {
|
||||
// 拍照成功
|
||||
infoDiv.style.display = 'block';
|
||||
infoDiv.innerHTML = '<strong>拍照成功:</strong><br>URI: ' + uri + '<br>路径: ' + path;
|
||||
previewDiv.innerHTML = '<img src="' + uri + '" alt="照片预览">';
|
||||
} else {
|
||||
// 拍照取消
|
||||
infoDiv.style.display = 'block';
|
||||
infoDiv.innerHTML = '<strong>拍照已取消</strong>';
|
||||
previewDiv.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文件大小 - 字节转换为KB/MB/GB
|
||||
*/
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
var k = 1024; // 换算基数
|
||||
var sizes = ['Bytes', 'KB', 'MB', 'GB']; // 单位数组
|
||||
var i = Math.floor(Math.log(bytes) / Math.log(k)); // 计算单位索引
|
||||
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i]; // 计算并返回
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<!--
|
||||
其他地方接入
|
||||
<input type="file" accept="image/*" capture="environment" onchange="handlePhoto(this)">
|
||||
// 处理照片选择
|
||||
function handlePhoto(input) {
|
||||
var file = input.files[0];
|
||||
|
||||
if (file) {
|
||||
// 读取文件
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
var base64Data = e.target.result;
|
||||
|
||||
// 显示预览
|
||||
document.getElementById('preview').innerHTML =
|
||||
'<img src="' + base64Data + '" style="max-width: 100%;">';
|
||||
|
||||
// 上传到服务器
|
||||
uploadPhoto(base64Data);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
|
||||
// 上传照片
|
||||
function uploadPhoto(base64Data) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', '/api/upload', true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
|
||||
xhr.onload = function() {
|
||||
if (xhr.status === 200) {
|
||||
console.log('上传成功');
|
||||
}
|
||||
};
|
||||
|
||||
xhr.send(JSON.stringify({
|
||||
image: base64Data
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
-->
|
||||
@ -96,21 +96,29 @@
|
||||
outline: -webkit-focus-ring-color auto 0px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
<script>
|
||||
function saveSetting(){
|
||||
var data=JSON.stringify({
|
||||
"address":document.getElementById('address').value,
|
||||
"port":document.getElementById('port').value,
|
||||
"path":document.getElementById('path').value
|
||||
});
|
||||
window.NetworkSettingEngine.save(data);
|
||||
window.View.reload();
|
||||
.radio-group {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
}
|
||||
.radio-group>span {
|
||||
display: inline-block;
|
||||
width: 110px;
|
||||
min-width: 110px;
|
||||
}
|
||||
.radio-group .radio-group-box {
|
||||
display: flex;
|
||||
flex-wrap: wrap; /* 允许换行 */
|
||||
gap: 10px 20px; /* 垂直和水平间距 */
|
||||
width: 100%;
|
||||
}
|
||||
.radio-group .radio-group-box .radio-item {
|
||||
width: calc(50% - 10px);
|
||||
}
|
||||
.radio-group .radio-group-box .radio-item.full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
</script>
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
@ -130,6 +138,56 @@
|
||||
<label>访问子路径</label>
|
||||
<input id="path" name="path" placeholder="访问子路径">
|
||||
</div>
|
||||
<div class="radio-group">
|
||||
<span>屏幕方向</span>
|
||||
<div class="radio-group-box">
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="screen_rotation" value="5" checked>
|
||||
正竖
|
||||
</label>
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="screen_rotation" value="6" checked>
|
||||
倒竖
|
||||
</label>
|
||||
<label class="radio-item full">
|
||||
<input type="radio" name="screen_rotation" value="1" checked>
|
||||
竖屏(系统可能不支持)
|
||||
</label>
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="screen_rotation" value="7">
|
||||
正横
|
||||
</label>
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="screen_rotation" value="8">
|
||||
倒横
|
||||
</label>
|
||||
<label class="radio-item full">
|
||||
<input type="radio" name="screen_rotation" value="2">
|
||||
横屏
|
||||
</label>
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="screen_rotation" value="3">
|
||||
横竖
|
||||
</label>
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="screen_rotation" value="4">
|
||||
禁止
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="radio-group">
|
||||
<span>隐藏状态栏</span>
|
||||
<div class="radio-group-box">
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="hide_bar" value="1" checked>
|
||||
隐藏
|
||||
</label>
|
||||
<label class="radio-item">
|
||||
<input type="radio" name="hide_bar" value="2">
|
||||
显示
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="operation">
|
||||
<button style="background: #1989fa;" onclick="saveSetting()">保存</button>
|
||||
@ -138,4 +196,35 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
|
||||
function init() {
|
||||
var dstr = window.NetworkSettingEngine.getStringSetting();
|
||||
if (dstr.length > 0) {
|
||||
var d = JSON.parse(dstr);
|
||||
document.getElementById('address').value = d.address;
|
||||
document.getElementById('port').value = d.port;
|
||||
document.getElementById('path').value = d.path;
|
||||
document.querySelector('input[name="screen_rotation"][value="'+d.screen_rotation+'"]').checked = true;
|
||||
document.querySelector('input[name="hide_bar"][value="'+d.hide_bar+'"]').checked = true;
|
||||
console.log("d_data_end_=========================");
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
function saveSetting(){
|
||||
var data=JSON.stringify({
|
||||
"address":document.getElementById('address').value,
|
||||
"port":document.getElementById('port').value,
|
||||
"path":document.getElementById('path').value,
|
||||
"screen_rotation":document.querySelector('input[name="screen_rotation"]:checked').value,
|
||||
"hide_bar":document.querySelector('input[name="hide_bar"]:checked').value
|
||||
});
|
||||
window.NetworkSettingEngine.saveSetting(data);
|
||||
window.View.reload();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</html>
|
||||
|
||||
14
app/src/main/assets/error/netError.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!-- 手动添加了一个网络错误提示 -->
|
||||
<html lang="zh-CN">
|
||||
<body>
|
||||
<p>网络错误,无法连接到服务器,请检查网络</p>
|
||||
<button onclick="reLoadWebView()">重新加载</button>
|
||||
</body>
|
||||
<script>
|
||||
|
||||
function reLoadWebView(){
|
||||
window.View.reload();
|
||||
}
|
||||
|
||||
</script>
|
||||
</html>
|
||||
8
app/src/main/assets/init.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"备注": "下面所有的字段,删除前面的_就是配置的字段,在没有手动配置的情况下,会读取字段中的信息,从而实现默认配置",
|
||||
"_ip":"ip地址",
|
||||
"_port":"端口号",
|
||||
"_path":"访问路径",
|
||||
"_screen_rotation":"屏幕方向:5正竖;6倒竖;7正横;8倒横;1竖;2横;3横竖;4禁止",
|
||||
"_hide_bar":"状态拦:1隐藏、2显示"
|
||||
}
|
||||
@ -10,11 +10,25 @@ package chaoran.business;
|
||||
|
||||
public enum BrandEnum {
|
||||
//枚举名即为valueOf()
|
||||
AIFUU("AIFUU", "AIFUU"),
|
||||
HORIEMTECH("群创科技", "Horiemtech"),
|
||||
QUALCOMM("qualcomm", "qualcomm"),
|
||||
IOT_DEVICE("新大陆", "iot_device"),
|
||||
NEW_LAND("新大陆", "newland"),
|
||||
HISENSE("海信", "hisense"),
|
||||
UROVO("DT50 Lite", "urovo"),
|
||||
LACHESIS("联新", "lachesis"),
|
||||
UROBO("优博讯", "urobo"),
|
||||
ROCKCHIP("瑞芯微电子", "rockchip"),
|
||||
TEST("测试设备", "test"),
|
||||
IDATA("匿名设备", "idata"),
|
||||
ALPS("阿尔卑斯", "alps");
|
||||
HONEY_WELL_EDA50P("霍尼维尔EDA50P", "mobiwire"),
|
||||
HONEY_WELL_EDA51("霍尼维尔EDA51", "honeywell"),
|
||||
ZEBRA_TECHNOLOGIES("斑马TP26CK", "zebra technologies"),
|
||||
SEUIC("东集", "seuic"),
|
||||
ALPS("阿尔卑斯", "alps"),
|
||||
HKWS("海康威视", "mv-idp5102"),
|
||||
HKWS2("海康威视", "droi"); // mv-idp5204 宿州市立医院
|
||||
|
||||
private String name;
|
||||
private String code;
|
||||
@ -35,7 +49,7 @@ public enum BrandEnum {
|
||||
code = new String();
|
||||
}
|
||||
for (BrandEnum brandEnum : values()) {
|
||||
if (brandEnum.code.equals(code.toLowerCase())) {
|
||||
if (brandEnum.code.equalsIgnoreCase(code)) {
|
||||
return brandEnum;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,113 @@
|
||||
package chaoran.business.activity;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import chaoran.business.R;
|
||||
import chaoran.business.utils.FileChooserHelper;
|
||||
import chaoran.business.utils.CameraHelper;
|
||||
|
||||
/**
|
||||
* 文件选择测试Activity
|
||||
*/
|
||||
public class FileTestActivity extends AppCompatActivity {
|
||||
|
||||
private WebView webView;
|
||||
private FileChooserHelper fileChooserHelper;
|
||||
private CameraHelper cameraHelper;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_file_test);
|
||||
|
||||
fileChooserHelper = new FileChooserHelper(this);
|
||||
|
||||
webView = findViewById(R.id.webViewFileTest);
|
||||
cameraHelper = new CameraHelper(this, webView);
|
||||
initWebView();
|
||||
|
||||
// 加载测试页面
|
||||
webView.loadUrl("file:///android_asset/demo/file_test.html");
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
private void initWebView() {
|
||||
WebSettings settings = webView.getSettings();
|
||||
settings.setJavaScriptEnabled(true);
|
||||
settings.setDomStorageEnabled(true);
|
||||
|
||||
// 添加JavaScript接口
|
||||
webView.addJavascriptInterface(cameraHelper, "CameraHelper");
|
||||
|
||||
webView.setWebViewClient(new WebViewClient());
|
||||
webView.setWebChromeClient(new WebChromeClient() {
|
||||
@Override
|
||||
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
|
||||
FileChooserParams fileChooserParams) {
|
||||
// 检查是否接受图片
|
||||
String[] acceptTypes = fileChooserParams.getAcceptTypes();
|
||||
boolean acceptImage = false;
|
||||
boolean acceptCamera = false;
|
||||
boolean cameraOnly = false;
|
||||
|
||||
if (acceptTypes != null && acceptTypes.length > 0) {
|
||||
for (String type : acceptTypes) {
|
||||
if (type.contains("image")) {
|
||||
acceptImage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查capture模式
|
||||
if (fileChooserParams.isCaptureEnabled()) {
|
||||
acceptCamera = true;
|
||||
|
||||
// 注意:Android WebView中,capture="user"或capture="environment"都会返回true
|
||||
// 我们通过简单的方式判断:如果是图片且启用capture,默认显示选择器
|
||||
// 只有在特定情况下才直接打开相机
|
||||
|
||||
// 这里我们不设置cameraOnly=true,让所有capture都显示选择器
|
||||
// 如果需要仅相机模式,可以通过其他方式(如URL参数)来控制
|
||||
}
|
||||
|
||||
fileChooserHelper.openFileChooser(filePathCallback, acceptImage, acceptCamera, cameraOnly);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (!fileChooserHelper.onActivityResult(requestCode, resultCode, data)) {
|
||||
cameraHelper.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
fileChooserHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (webView.canGoBack()) {
|
||||
webView.goBack();
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +1,33 @@
|
||||
package chaoran.business.activity;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Vibrator;
|
||||
import android.util.JsonReader;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.OrientationEventListener;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.*;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
@ -17,13 +35,31 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import chaoran.business.BrandEnum;
|
||||
import chaoran.business.R;
|
||||
import chaoran.business.adapter.*;
|
||||
import chaoran.business.engine.entity.NetworkSetting;
|
||||
import chaoran.business.engine.impl.NetworkSettingEngine;
|
||||
import chaoran.business.engine.SettingEngine;
|
||||
import chaoran.business.engine.impl.TekVoiceEngine;
|
||||
import chaoran.business.engine.VoiceEngine;
|
||||
import chaoran.business.service.ScanServiceEDA50P;
|
||||
import chaoran.business.service.ScanServiceZEBRA;
|
||||
import chaoran.business.utils.DataCleanManager;
|
||||
import chaoran.business.utils.LocalAddressUtil;
|
||||
import chaoran.business.utils.StatusBarUtil;
|
||||
import chaoran.business.utils.FileChooserHelper;
|
||||
|
||||
/**
|
||||
* 流程:联网认证设备型号,验证通过,查找设备品牌进行调用驱动操作
|
||||
@ -34,25 +70,81 @@ import chaoran.business.engine.VoiceEngine;
|
||||
*/
|
||||
public class MainActivity extends AppCompatActivity implements ResultListener{
|
||||
|
||||
public static int SCREEN_ROTATION = 3; // 屏幕旋转的设置
|
||||
public static int hideBar = 0; // 屏幕旋转的设置
|
||||
|
||||
private WebView webView;
|
||||
private Adapter adapter;
|
||||
private VoiceEngine voiceEngine;
|
||||
private SettingEngine settingEngine;
|
||||
private ProgressBar progressBar;
|
||||
private ActionBar actionBar;
|
||||
|
||||
private FileChooserHelper fileChooserHelper;
|
||||
private LocalAddressUtil localAddressUtil;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
try {
|
||||
DataCleanManager.clearAllCache(this); // 清空缓存
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
initView();
|
||||
initData();
|
||||
//SCREEN_ORIENTATION_USER,不能旋转180,0、90、270都可以旋转
|
||||
//SCREEN_ORIENTATION_FULL_SENSOR 都可以旋转,但是在不打开旋转的情况下,一样可以旋转
|
||||
//SCREEN_ORIENTATION_FULL_USER 关闭旋转则不会旋转了
|
||||
// 取消监听屏幕方向,使用用户的,等出现了问题再来调整;之前有一款pda系统旋转有bug
|
||||
// this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
|
||||
if (SCREEN_ROTATION == 1) {
|
||||
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT);//竖
|
||||
}else if (SCREEN_ROTATION == 2) {
|
||||
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);//横
|
||||
}else if (SCREEN_ROTATION == 3){
|
||||
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);//随便
|
||||
}else if (SCREEN_ROTATION == 5) { // 正竖
|
||||
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
}else if (SCREEN_ROTATION == 6) {// 倒竖
|
||||
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
||||
}else if (SCREEN_ROTATION == 7) {// 正横
|
||||
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
||||
}else if (SCREEN_ROTATION == 8) {// 倒横
|
||||
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
}else {
|
||||
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR); // 禁止
|
||||
}
|
||||
// myOrientationDetector = new MyOrientationDetector(this, this);
|
||||
// myOrientationDetector.enable();
|
||||
|
||||
}
|
||||
|
||||
public static String readInitFile(Context context) {
|
||||
StringBuffer init = new StringBuffer();
|
||||
try {
|
||||
AssetManager assetManager = context.getAssets();
|
||||
// 打开文件输入流
|
||||
InputStream inputStream = assetManager.open("init.json");
|
||||
// 使用BufferedReader进行逐行读取
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
init.append(line);
|
||||
}
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
Log.e("AssetError", "Failed to read asset file: init.json", e);
|
||||
}
|
||||
return init.toString();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
BrandEnum brand = BrandEnum.code(Build.MANUFACTURER);
|
||||
Toast.makeText(this, Build.MANUFACTURER, Toast.LENGTH_LONG).show();
|
||||
Log.i("brand===",brand.toString());
|
||||
switch (brand) {
|
||||
case UROBO:
|
||||
adapter = new UroBoAdapter(this, this);
|
||||
@ -66,22 +158,78 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
case ALPS:
|
||||
adapter = new AlpsAdapter(this, this);
|
||||
break;
|
||||
case SEUIC:
|
||||
adapter = new SeuicAdapter(this, this);
|
||||
break;
|
||||
case HONEY_WELL_EDA50P:
|
||||
// 51、56都是同一个code
|
||||
case HONEY_WELL_EDA51:
|
||||
if (
|
||||
"eda50p".equals(Build.MODEL.toLowerCase())
|
||||
|| "eda51".equals(Build.MODEL.toLowerCase())
|
||||
// || "eda52".equals(Build.MODEL.toLowerCase()) // todo
|
||||
|| "tc26".equals(Build.MODEL.toLowerCase())
|
||||
) {
|
||||
// 走服务模式
|
||||
adapter = new HoneywellAdapter(this, this);
|
||||
}else {
|
||||
// 走广播模式
|
||||
adapter = new HoneywellEda56Adapter(this, this);
|
||||
}
|
||||
break;
|
||||
case ZEBRA_TECHNOLOGIES:
|
||||
adapter = new ZebraAdapter(this, this);
|
||||
break;
|
||||
case HISENSE:
|
||||
adapter = new HisenseAdapter(this, this);
|
||||
break;
|
||||
case LACHESIS:
|
||||
adapter = new LachesisAdapter(this, this);
|
||||
break;
|
||||
case UROVO:
|
||||
adapter = new UrovoAdapter(this, this);
|
||||
break;
|
||||
case HKWS:
|
||||
case HKWS2:
|
||||
adapter = new HkwsAdapter(this, this);
|
||||
break;
|
||||
case NEW_LAND:
|
||||
adapter = new NewlandAdapter(this, this);
|
||||
break;
|
||||
case IOT_DEVICE:
|
||||
adapter = new IOT_DeviceAdapter(this, this);
|
||||
break;
|
||||
case QUALCOMM:
|
||||
adapter = new QualcommAdapter(this, this);
|
||||
break;
|
||||
case HORIEMTECH:
|
||||
adapter = new HoriemtechAdapter(this, this);
|
||||
break;
|
||||
case AIFUU:
|
||||
adapter = new AifuuAdapter(this, this);
|
||||
break;
|
||||
default:
|
||||
adapter = new DefaultAdapter(this, this);
|
||||
}
|
||||
if (null != adapter) {
|
||||
adapter.start();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
private void initView() {
|
||||
actionBar = getSupportActionBar();
|
||||
voiceEngine = new TekVoiceEngine(this);
|
||||
settingEngine = new NetworkSettingEngine(this);
|
||||
fileChooserHelper = new FileChooserHelper(this);
|
||||
webView = findViewById(R.id.webView);
|
||||
progressBar = findViewById(R.id.loading);
|
||||
webView.setWebViewClient(disposeView());
|
||||
webView.setWebChromeClient(createWebChromeClient());
|
||||
WebSettings settings = webView.getSettings();
|
||||
settings.setJavaScriptEnabled(true);
|
||||
|
||||
|
||||
|
||||
//设置接口进行windows暴露
|
||||
settings.setDomStorageEnabled(true);
|
||||
//语音引擎
|
||||
@ -90,7 +238,57 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
webView.addJavascriptInterface(settingEngine, "NetworkSettingEngine");
|
||||
//重新加载页面
|
||||
webView.addJavascriptInterface(this, "View");
|
||||
localAddressUtil = new LocalAddressUtil(this, this, webView);
|
||||
webView.addJavascriptInterface(localAddressUtil, "Localpda");
|
||||
webView.loadUrl(url());
|
||||
// StatusBarUtil.transparencyBar( this); // 设置全部透明,需要在页面设置一个参数进行布局的样式跳转,不同的手机端,状态栏高度不一样(apk设置状态栏高度无效,这个是安卓9的一个bug),所以在此采取隐藏状态栏
|
||||
if (hideBar == 1) {
|
||||
StatusBarUtil.hideStatusBar( this); // 设置全部透明
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPageFinished = false; // 新增标志位
|
||||
|
||||
/**
|
||||
* 创建WebChromeClient以支持文件选择
|
||||
*/
|
||||
private WebChromeClient createWebChromeClient() {
|
||||
return new WebChromeClient() {
|
||||
// For Android 5.0+
|
||||
@Override
|
||||
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback,
|
||||
FileChooserParams fileChooserParams) {
|
||||
// 检查是否接受图片
|
||||
String[] acceptTypes = fileChooserParams.getAcceptTypes();
|
||||
boolean acceptImage = false;
|
||||
boolean acceptCamera = false;
|
||||
boolean cameraOnly = false;
|
||||
|
||||
if (acceptTypes != null && acceptTypes.length > 0) {
|
||||
for (String type : acceptTypes) {
|
||||
if (type.contains("image")) {
|
||||
acceptImage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查capture模式
|
||||
if (fileChooserParams.isCaptureEnabled()) {
|
||||
acceptCamera = true;
|
||||
|
||||
// 注意:Android WebView中,capture="user"或capture="environment"都会返回true
|
||||
// 我们通过简单的方式判断:如果是图片且启用capture,默认显示选择器
|
||||
// 只有在特定情况下才直接打开相机
|
||||
|
||||
// 这里我们不设置cameraOnly=true,让所有capture都显示选择器
|
||||
// 如果需要仅相机模式,可以通过其他方式(如URL参数)来控制
|
||||
}
|
||||
|
||||
fileChooserHelper.openFileChooser(filePathCallback, acceptImage, acceptCamera, cameraOnly);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//配置客户端
|
||||
@ -101,6 +299,7 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
isPageFinished = false;
|
||||
}
|
||||
|
||||
//页面加载完成时
|
||||
@ -112,33 +311,31 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
actionBar.show();
|
||||
super.onPageFinished(view, url);
|
||||
progressBar.setVisibility(View.INVISIBLE);
|
||||
isPageFinished = true;
|
||||
}
|
||||
|
||||
//网络发生错误时,先展示错误界面,然后关闭加载条
|
||||
@Override
|
||||
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
|
||||
switch (errorCode) {
|
||||
case 404:
|
||||
webView.loadUrl("file:///android_asset/error/404.html");
|
||||
break;
|
||||
case 500:
|
||||
webView.loadUrl("file:///android_asset/error/500.html");
|
||||
break;
|
||||
default:
|
||||
webView.loadUrl("file:///android_asset/error/index.html");
|
||||
}
|
||||
setHtml(webView, errorCode);
|
||||
actionBar.show();
|
||||
actionBar.setTitle(R.string.title_activity_main);
|
||||
super.onReceivedError(view, errorCode, description, failingUrl);
|
||||
progressBar.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
//安卓6.0以上发生错误时回调
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
switch (error.getErrorCode()) {
|
||||
private void setHtml(WebView view, int errorCode) {
|
||||
switch (errorCode) {
|
||||
// https://www.apiref.com/android-zh/android/webkit/WebViewClient.html;根据这个code进行的设置
|
||||
// -数的都是有
|
||||
case -2:
|
||||
case -6:
|
||||
case -8:
|
||||
webView.loadUrl("file:///android_asset/error/netError.html");
|
||||
break;
|
||||
case 404:
|
||||
case -14:
|
||||
case -12:
|
||||
webView.loadUrl("file:///android_asset/error/404.html");
|
||||
break;
|
||||
case 500:
|
||||
@ -148,10 +345,27 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
webView.loadUrl("file:///android_asset/error/index.html");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
if (isPageFinished) {
|
||||
// 页面已加载完成,交由 JS 处理错误
|
||||
String jsError = String.format("javascript:handleWebError(%d, '%s')", error.getErrorCode(), error.getDescription());
|
||||
view.loadUrl(jsError);
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
setHtml(webView, error.getErrorCode());
|
||||
}
|
||||
actionBar.show();
|
||||
actionBar.setTitle(R.string.title_activity_main);
|
||||
super.onReceivedError(view, request, error);
|
||||
}
|
||||
progressBar.setVisibility(View.INVISIBLE);
|
||||
super.onReceivedError(view, request, error);
|
||||
}
|
||||
|
||||
//安卓6.0以上发生错误时回调
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
handleReceivedError(view, request, error);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -160,9 +374,24 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
@Override
|
||||
protected void onResume() {
|
||||
//再次唤醒该页面时,重新加载页面和语音配置
|
||||
webView.loadUrl(url());
|
||||
voiceEngine.reload();
|
||||
//webView.loadUrl(url());
|
||||
// voiceEngine.reload();
|
||||
super.onResume();
|
||||
if (adapter != null) {
|
||||
adapter.stop2();
|
||||
adapter.start();
|
||||
}
|
||||
// int rotate = 1;
|
||||
// if (startDirection == 1) {
|
||||
// rotate = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; // 正竖屏
|
||||
// }else if (startDirection == 2) {
|
||||
// rotate = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; // 倒竖屏
|
||||
// }else if (startDirection == 3) {
|
||||
// rotate = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; // 正横屏
|
||||
// }else if (startDirection == 4) {
|
||||
// rotate = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; // 倒横屏
|
||||
// }
|
||||
// this.setRequestedOrientation(rotate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -170,11 +399,31 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
public void result(String result) {
|
||||
runOnUiThread(() -> webView.loadUrl("javascript:render(\'" + result + "\')"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (adapter != null) {
|
||||
adapter.stop();
|
||||
}
|
||||
super.onDestroy();
|
||||
if (diPlayer != null) {
|
||||
diPlayer.stop();
|
||||
diPlayer.release();
|
||||
diPlayer = null;
|
||||
}
|
||||
if (duPlayer != null) {
|
||||
duPlayer.stop();
|
||||
duPlayer.release();
|
||||
duPlayer = null;
|
||||
}
|
||||
if (dingPlayer != null) {
|
||||
dingPlayer.stop();
|
||||
dingPlayer.release();
|
||||
dingPlayer = null;
|
||||
}
|
||||
if (vibrator != null) {
|
||||
vibrator.cancel();
|
||||
}
|
||||
completionListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -192,6 +441,9 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
case R.id.action_setting_voice:
|
||||
startActivity(new Intent(this, VoiceSettingActivity.class));
|
||||
break;
|
||||
case R.id.action_file_test:
|
||||
startActivity(new Intent(this, FileTestActivity.class));
|
||||
break;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
@ -200,12 +452,42 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
private String url() {
|
||||
SharedPreferences spf = this.getSharedPreferences("crtech", Context.MODE_PRIVATE);
|
||||
Integer port = spf.getInt("port", -1);
|
||||
Map<String, Object> map = null;
|
||||
if (port == -1) {
|
||||
try {
|
||||
String init = readInitFile(this);
|
||||
// String init = null;
|
||||
if (init != null && init.length() > 0) {
|
||||
Gson gson = new Gson();
|
||||
map = gson.fromJson(init, new TypeToken<Map<String, Object>>(){}.getType());
|
||||
// 说明采取了配置,并且存在ip才认为是一个合法的json配置
|
||||
if (map.containsKey("ip") && map.get("ip").toString().length() > 0) {
|
||||
NetworkSetting initData = new NetworkSetting();
|
||||
initData.setAddress(map.get("ip").toString());
|
||||
initData.setPort(Integer.parseInt(map.get("port").toString()));
|
||||
initData.setPath(map.get("path").toString());
|
||||
initData.setScreen_rotation(Integer.parseInt(map.getOrDefault("screen_rotation", "3").toString()));
|
||||
initData.setHide_bar(Integer.parseInt(map.getOrDefault("hide_bar", "0").toString()));
|
||||
settingEngine.saveSetting(initData);
|
||||
spf = this.getSharedPreferences("crtech", Context.MODE_PRIVATE);
|
||||
port = initData.getPort();
|
||||
}else {
|
||||
map = null;
|
||||
}
|
||||
}
|
||||
}catch (Exception e) {
|
||||
Log.e("MainActivity", "get init file error");
|
||||
return "file:///android_asset/demo/index.html";
|
||||
}
|
||||
if (map == null) {
|
||||
return "file:///android_asset/demo/index.html";
|
||||
}
|
||||
}
|
||||
String address = spf.getString("address", "").replaceAll(" ", "");
|
||||
String path = spf.getString("path", "").replaceAll(" ", "");
|
||||
String link = address.concat(":").concat(String.valueOf(port)).concat(path);
|
||||
SCREEN_ROTATION = spf.getInt("screen_rotation", 3);
|
||||
hideBar = spf.getInt("hide_bar", 0);
|
||||
return link.startsWith("http://") ? link : "http://".concat(link);
|
||||
}
|
||||
|
||||
@ -215,4 +497,107 @@ public class MainActivity extends AppCompatActivity implements ResultListener {
|
||||
webView.loadUrl(url());
|
||||
});
|
||||
}
|
||||
private MediaPlayer diPlayer = null;
|
||||
private MediaPlayer duPlayer = null;
|
||||
private MediaPlayer dingPlayer = null;
|
||||
private String ttsNr;
|
||||
public Vibrator vibrator;
|
||||
|
||||
@JavascriptInterface
|
||||
public void play(String msg, String type, int isZd) throws IOException {
|
||||
ttsNr = msg;
|
||||
if ("1".equals(type)) {
|
||||
if (diPlayer == null) {
|
||||
diPlayer = MediaPlayer.create(this, R.raw.didi);
|
||||
diPlayer.setOnCompletionListener(completionListener);
|
||||
}
|
||||
diPlayer.start();
|
||||
} else if ("2".equals(type)) {
|
||||
if (duPlayer == null) {
|
||||
duPlayer = MediaPlayer.create(this, R.raw.dudu);
|
||||
duPlayer.setOnCompletionListener(completionListener);
|
||||
}
|
||||
duPlayer.start();
|
||||
} else if ("10".equals(type)) {
|
||||
if (dingPlayer == null) {
|
||||
dingPlayer = MediaPlayer.create(this, R.raw.ding);
|
||||
dingPlayer.setOnCompletionListener(completionListener);
|
||||
}
|
||||
dingPlayer.start();
|
||||
} else {
|
||||
//isZd = 1;
|
||||
if (voiceEngine != null) {
|
||||
voiceEngine.startSpeaking(msg);
|
||||
}
|
||||
}
|
||||
if (isZd == 1) {
|
||||
if (vibrator == null) {
|
||||
vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
|
||||
}
|
||||
vibrator.vibrate(2000);
|
||||
}
|
||||
}
|
||||
|
||||
private MediaPlayer.OnCompletionListener completionListener = new MediaPlayer.OnCompletionListener() {
|
||||
// @Override
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
if (ttsNr != null) {
|
||||
if (voiceEngine != null) {
|
||||
voiceEngine.startSpeaking(ttsNr);
|
||||
}
|
||||
ttsNr = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public void openIndex() throws IOException {
|
||||
runOnUiThread(() -> {
|
||||
webView.loadUrl("file:///android_asset/demo/index.html");
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
// 创建退出确认对话框
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("提示")
|
||||
.setMessage("是否退出程序?")
|
||||
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
finish(); // 关闭当前 Activity
|
||||
// 如果需要彻底退出应用(适用于多任务场景),可以添加:
|
||||
// System.exit(0);
|
||||
}
|
||||
})
|
||||
.setNegativeButton("取消", null)
|
||||
.show();
|
||||
// 不调用 super.onBackPressed(),避免直接退出
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (!fileChooserHelper.onActivityResult(requestCode, resultCode, data)
|
||||
&& (localAddressUtil == null || !localAddressUtil.onActivityResult(requestCode, resultCode, data))) {
|
||||
// 如果不是文件选择器的结果,可以在这里处理其他结果
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (!fileChooserHelper.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
||||
&& (localAddressUtil == null || !localAddressUtil.onRequestPermissionsResult(requestCode, permissions, grantResults))) {
|
||||
// 如果不是文件选择器的权限请求,可以在这里处理其他权限请求
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@ import chaoran.business.R;
|
||||
|
||||
public class NetworkSettingActivity extends AppCompatActivity {
|
||||
|
||||
private EditText address, path, port;
|
||||
private EditText address, path, port, screen_rotation, hide_bar;
|
||||
private Button save, cancel;
|
||||
|
||||
@Override
|
||||
@ -35,12 +35,16 @@ public class NetworkSettingActivity extends AppCompatActivity {
|
||||
address = findViewById(R.id.address);
|
||||
path = findViewById(R.id.path);
|
||||
port = findViewById(R.id.port);
|
||||
screen_rotation = findViewById(R.id.screen_rotation);
|
||||
hide_bar = findViewById(R.id.hide_bar);
|
||||
save = findViewById(R.id.save);
|
||||
cancel = findViewById(R.id.cancel);
|
||||
SharedPreferences sharedPreferences = this.getSharedPreferences("crtech", Context.MODE_PRIVATE);
|
||||
address.setText(sharedPreferences.getString("address", ""));
|
||||
path.setText(sharedPreferences.getString("path", ""));
|
||||
port.setText(String.valueOf(sharedPreferences.getInt("port", -1)));
|
||||
screen_rotation.setText(String.valueOf(sharedPreferences.getInt("screen_rotation", 3)));
|
||||
hide_bar.setText(String.valueOf(sharedPreferences.getInt("hide_bar", 0)));
|
||||
cancel.setOnClickListener((e) -> this.finish());
|
||||
save.setOnClickListener((e) -> saveSetting());
|
||||
}
|
||||
@ -50,6 +54,8 @@ public class NetworkSettingActivity extends AppCompatActivity {
|
||||
editor.putString("address", address.getText().toString().trim());
|
||||
editor.putString("path", path.getText().toString().trim());
|
||||
editor.putInt("port", Integer.parseInt(port.getText().toString().trim()));
|
||||
editor.putInt("screen_rotation", Integer.parseInt(screen_rotation.getText().toString().trim()));
|
||||
editor.putInt("hide_bar", Integer.parseInt(hide_bar.getText().toString().trim()));
|
||||
editor.commit();
|
||||
this.finish();
|
||||
}
|
||||
|
||||
@ -29,4 +29,8 @@ public interface Adapter{
|
||||
*/
|
||||
public void stop();
|
||||
|
||||
public default void stop2() {
|
||||
stop();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
54
app/src/main/java/chaoran/business/adapter/AifuuAdapter.java
Normal file
@ -0,0 +1,54 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
/**
|
||||
* AIFUU 陆军特色中心医院 陈安良
|
||||
*/
|
||||
public class AifuuAdapter implements Adapter {
|
||||
private Context context;
|
||||
private Strategy strategy;
|
||||
private ResultListener resultListener;
|
||||
|
||||
public AifuuAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("code"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("com.kte.scan.result");
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ import chaoran.business.strategy.Strategy;
|
||||
|
||||
/**
|
||||
* 阿尔卑斯适配器
|
||||
* CR-5W适用
|
||||
* CR-5W适用;Android Handheld Terminal
|
||||
*/
|
||||
public class AlpsAdapter implements Adapter {
|
||||
private Context context;
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
public class DefaultAdapter implements Adapter {
|
||||
private Context context;
|
||||
private Strategy strategy;
|
||||
private ResultListener resultListener;
|
||||
|
||||
public DefaultAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new DefaultAdapter.Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("barcode"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("chaoran.crtech.cn.pda.scan");
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
public class HisenseAdapter implements Adapter {
|
||||
private Context context;
|
||||
private ResultListener resultListener;
|
||||
private Strategy strategy;
|
||||
|
||||
|
||||
public HisenseAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("msg"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("chaoran");
|
||||
filter.setPriority(2);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
app/src/main/java/chaoran/business/adapter/HkwsAdapter.java
Normal file
@ -0,0 +1,53 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
public class HkwsAdapter implements Adapter {
|
||||
private Context context;
|
||||
private ResultListener resultListener;
|
||||
private Strategy strategy;
|
||||
|
||||
|
||||
public HkwsAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("barcode"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("android.intent.ACTION_SCAN_OUTPUT");
|
||||
filter.setPriority(2);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
118
app/src/main/java/chaoran/business/adapter/HoneywellAdapter.java
Normal file
@ -0,0 +1,118 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.service.ScanServiceEDA50P;
|
||||
import chaoran.business.service.ScanServiceZEBRA;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
|
||||
public class HoneywellAdapter implements Adapter {
|
||||
private Context context;
|
||||
private Strategy strategy;
|
||||
private ResultListener resultListener;
|
||||
private Intent intent = null;
|
||||
|
||||
public HoneywellAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
openContinueScan();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop2() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
new ScanServiceEDA50P().onDestroy();
|
||||
strategy.exclusiveStrategy();
|
||||
this.stopContinueScan();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("data"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("com.honeywell.scan.broadcast");
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopContinueScan() {
|
||||
Class clazz = null;
|
||||
if("eda50p".equals(Build.MODEL.toLowerCase())){ // 扫描正常
|
||||
intent = new Intent(context, ScanServiceEDA50P.class);
|
||||
clazz = ScanServiceEDA50P.class;
|
||||
}else if("eda51".equals(Build.MODEL.toLowerCase())){ // 扫描正常
|
||||
intent = new Intent(context, ScanServiceEDA50P.class);
|
||||
clazz = ScanServiceEDA50P.class;
|
||||
}
|
||||
else if("tc26".equals(Build.MODEL.toLowerCase())){
|
||||
intent = new Intent(context, ScanServiceZEBRA.class);
|
||||
clazz = ScanServiceZEBRA.class;
|
||||
}
|
||||
if (clazz != null && isServiceRunning(clazz)) {
|
||||
context.stopService(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isServiceRunning(Class<?> serviceClass) {
|
||||
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<ActivityManager.RunningServiceInfo> runningServices = manager.getRunningServices(Integer.MAX_VALUE);
|
||||
|
||||
for (ActivityManager.RunningServiceInfo service : runningServices) {
|
||||
if (serviceClass.getName().equals(service.service.getClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void openContinueScan(){
|
||||
|
||||
if("eda50p".equals(Build.MODEL.toLowerCase()) || "eda51".equals(Build.MODEL.toLowerCase()) || "eda52".equals(Build.MODEL.toLowerCase())){ // 扫描正常
|
||||
intent = new Intent(context, ScanServiceEDA50P.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.getApplicationContext().startForegroundService(intent);
|
||||
}else {
|
||||
context.getApplicationContext().startService(intent);
|
||||
}
|
||||
}
|
||||
else if("tc26".equals(Build.MODEL.toLowerCase())){
|
||||
intent = new Intent(context, ScanServiceZEBRA.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.getApplicationContext().startForegroundService(intent);
|
||||
}else {
|
||||
context.getApplicationContext().startService(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
/**
|
||||
* 23-6-13 霍尼韦尔EDA56使用
|
||||
* 25-1-14 兰陵县人民医院 测试可以使用(唐圆圆)
|
||||
*/
|
||||
public class HoneywellEda56Adapter implements Adapter {
|
||||
private Context context;
|
||||
private ResultListener resultListener;
|
||||
private Strategy strategy;
|
||||
|
||||
|
||||
public HoneywellEda56Adapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new HoneywellEda56Adapter.Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("data"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("chaoran");
|
||||
filter.setPriority(2);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
/*
|
||||
**********************************************
|
||||
* DATE PERSON REASON
|
||||
* 2021-02-03 FXY Created
|
||||
**********************************************
|
||||
*/
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
/**
|
||||
* 群创科技
|
||||
*/
|
||||
public class HoriemtechAdapter implements Adapter {
|
||||
private Context context;
|
||||
private Strategy strategy;
|
||||
private ResultListener resultListener;
|
||||
|
||||
public HoriemtechAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("value"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("mmi.scan.mode.notify");
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,5 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
/*
|
||||
**********************************************
|
||||
* DATE PERSON REASON
|
||||
* 2021-02-02 FXY Created
|
||||
**********************************************
|
||||
*/
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@ -45,7 +39,7 @@ public class IDataAdapter implements Adapter {
|
||||
|
||||
public Receiver() {
|
||||
scannerInerface = new ScannerInerface(context);
|
||||
scannerInerface.setOutputMode(1);
|
||||
// scannerInerface.setOutputMode(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,7 +49,7 @@ public class IDataAdapter implements Adapter {
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
scannerInerface.open();
|
||||
// scannerInerface.open();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("android.intent.action.SCANRESULT");
|
||||
context.registerReceiver(this, filter);
|
||||
@ -64,7 +58,7 @@ public class IDataAdapter implements Adapter {
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
scannerInerface.close();
|
||||
// scannerInerface.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
/**
|
||||
* 适配 sc55g
|
||||
*/
|
||||
public class IOT_DeviceAdapter implements Adapter {
|
||||
private Context context;
|
||||
private ResultListener resultListener;
|
||||
private Strategy strategy;
|
||||
|
||||
|
||||
public IOT_DeviceAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("message"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("com.speedata.showdecodedata");
|
||||
filter.setPriority(2);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
public class LachesisAdapter implements Adapter {
|
||||
private Context context;
|
||||
private ResultListener resultListener;
|
||||
private Strategy strategy;
|
||||
|
||||
|
||||
public LachesisAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("data"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("chaoran");
|
||||
filter.setPriority(2);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
public class NewlandAdapter implements Adapter {
|
||||
private Context context;
|
||||
private ResultListener resultListener;
|
||||
private Strategy strategy;
|
||||
|
||||
|
||||
public NewlandAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("SCAN_BARCODE1"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("nlscan.action.SCANNER_RESULT");
|
||||
filter.setPriority(2);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
/**
|
||||
* 适配 mc50
|
||||
*/
|
||||
public class QualcommAdapter implements Adapter {
|
||||
private Context context;
|
||||
private ResultListener resultListener;
|
||||
private Strategy strategy;
|
||||
|
||||
|
||||
public QualcommAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("data"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("com.scanner.broadcast");
|
||||
filter.setPriority(2);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,10 +9,8 @@ package chaoran.business.adapter;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.media.SoundPool;
|
||||
import android.os.Vibrator;
|
||||
import chaoran.business.R;
|
||||
import android.os.Build;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
@ -29,6 +27,8 @@ public class RockChipAdapter implements Adapter {
|
||||
|
||||
private Context context;
|
||||
|
||||
public static final String[] barcode = {""};
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
@ -42,7 +42,11 @@ public class RockChipAdapter implements Adapter {
|
||||
public RockChipAdapter(Context context, ResultListener resultListener) {
|
||||
this.resultListener = resultListener;
|
||||
this.context = context;
|
||||
this.strategy = new Reader(new File("/dev/ttyS1"), 115200, 0);
|
||||
String fileName = "/dev/ttyS1";
|
||||
if (Build.MODEL.equalsIgnoreCase("rk3568_r")) {
|
||||
fileName = "/dev/ttyS8";
|
||||
}
|
||||
this.strategy = new Reader(new File(fileName), 115200, 0, fileName);
|
||||
}
|
||||
|
||||
public class Reader implements Strategy {
|
||||
@ -50,7 +54,7 @@ public class RockChipAdapter implements Adapter {
|
||||
private FileInputStream mFileInputStream;
|
||||
private boolean running = true;
|
||||
|
||||
public Reader(File device, int baudrate, int flags) {
|
||||
public Reader(File device, int baudrate, int flags, String fileName) {
|
||||
|
||||
if (!device.canRead() || !device.canWrite()) {
|
||||
try {
|
||||
@ -69,6 +73,10 @@ public class RockChipAdapter implements Adapter {
|
||||
}
|
||||
mFd = open(device.getAbsolutePath(), baudrate, flags);
|
||||
if (mFd == null) {
|
||||
if (!"/dev/ttyS1".equals(fileName)) {
|
||||
strategy = new Reader(new File("/dev/ttyS1"), 115200, 0, "/dev/ttyS1");
|
||||
return;
|
||||
}
|
||||
System.out.println("获取文件描述符失败!");
|
||||
}
|
||||
mFileInputStream = new FileInputStream(mFd);
|
||||
@ -76,11 +84,26 @@ public class RockChipAdapter implements Adapter {
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
running = true;
|
||||
new Thread(() -> {
|
||||
while (running) {
|
||||
String data = data();
|
||||
if (!data.equals("")) {
|
||||
resultListener.result(data);
|
||||
synchronized (RockChipAdapter.class) {
|
||||
barcode[0] = barcode[0] + data;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
synchronized (RockChipAdapter.class) {
|
||||
if (!"".equals(barcode[0])) {
|
||||
// Log.i("listen", "Thread result data: \t\t" + barcode[0] + "\t\t" + System.currentTimeMillis());
|
||||
resultListener.result(barcode[0]);
|
||||
barcode[0] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
@ -88,22 +111,27 @@ public class RockChipAdapter implements Adapter {
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
running = false;
|
||||
close();
|
||||
// running = false;
|
||||
// close();
|
||||
}
|
||||
|
||||
private String data() {
|
||||
if (mFileInputStream == null) return "";
|
||||
if (mFileInputStream == null) {
|
||||
return "";
|
||||
}
|
||||
synchronized (RockChipAdapter.class) {
|
||||
try {
|
||||
int size = mFileInputStream.available();
|
||||
byte[] buffer = new byte[size];
|
||||
size = mFileInputStream.read(buffer);
|
||||
if (size > 0) {
|
||||
return new String(buffer);
|
||||
String data = new String(buffer);
|
||||
return data;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
61
app/src/main/java/chaoran/business/adapter/SeuicAdapter.java
Normal file
@ -0,0 +1,61 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
/*
|
||||
**********************************************
|
||||
* DATE PERSON REASON
|
||||
* 2021-02-03 FXY Created
|
||||
**********************************************
|
||||
*/
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
/**
|
||||
* 东集 pda
|
||||
*/
|
||||
public class SeuicAdapter implements Adapter {
|
||||
private Context context;
|
||||
private Strategy strategy;
|
||||
private ResultListener resultListener;
|
||||
|
||||
public SeuicAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("scannerdata"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("com.android.server.scannerservice.broadcast");
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
app/src/main/java/chaoran/business/adapter/UrovoAdapter.java
Normal file
@ -0,0 +1,53 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
public class UrovoAdapter implements Adapter {
|
||||
private Context context;
|
||||
private ResultListener resultListener;
|
||||
private Strategy strategy;
|
||||
|
||||
|
||||
public UrovoAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("barcode_string"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("android.intent.ACTION_DECODE_DATA");
|
||||
filter.setPriority(2);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
app/src/main/java/chaoran/business/adapter/ZebraAdapter.java
Normal file
@ -0,0 +1,53 @@
|
||||
package chaoran.business.adapter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import chaoran.business.activity.ResultListener;
|
||||
import chaoran.business.strategy.Strategy;
|
||||
|
||||
public class ZebraAdapter implements Adapter {
|
||||
private Context context;
|
||||
private ResultListener resultListener;
|
||||
private Strategy strategy;
|
||||
|
||||
|
||||
public ZebraAdapter(Context context, ResultListener resultListener) {
|
||||
this.context = context;
|
||||
this.resultListener = resultListener;
|
||||
strategy = new ZebraAdapter.Receiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
strategy.executeStrategy(resultListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
strategy.exclusiveStrategy();
|
||||
}
|
||||
|
||||
public class Receiver extends BroadcastReceiver implements Strategy {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
resultListener.result(intent.getStringExtra("com.motorolasolutions.emdk.datawedge.data_string"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeStrategy(ResultListener resultListener) {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction("chaoran");
|
||||
filter.setPriority(2);
|
||||
context.registerReceiver(this, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exclusiveStrategy() {
|
||||
context.unregisterReceiver(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,10 @@ public class NetworkSetting extends Setting {
|
||||
private Integer port;
|
||||
private String path;
|
||||
|
||||
private Integer screen_rotation;
|
||||
|
||||
private Integer hide_bar;
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
@ -35,4 +39,21 @@ public class NetworkSetting extends Setting {
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public Integer getScreen_rotation() {
|
||||
return screen_rotation;
|
||||
}
|
||||
|
||||
public void setScreen_rotation(Integer screen_rotation) {
|
||||
this.screen_rotation = screen_rotation;
|
||||
}
|
||||
|
||||
public Integer getHide_bar() {
|
||||
return hide_bar;
|
||||
}
|
||||
|
||||
public void setHide_bar(Integer hide_bar) {
|
||||
this.hide_bar = hide_bar;
|
||||
}
|
||||
|
||||
}
|
||||
@ -11,6 +11,8 @@ package chaoran.business.engine.impl;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.webkit.JavascriptInterface;
|
||||
|
||||
import chaoran.business.activity.MainActivity;
|
||||
import chaoran.business.engine.SettingEngine;
|
||||
import chaoran.business.engine.entity.NetworkSetting;
|
||||
import chaoran.business.engine.entity.Setting;
|
||||
@ -35,12 +37,15 @@ public class NetworkSettingEngine implements SettingEngine {
|
||||
public Setting getSetting() {
|
||||
SharedPreferences spf = context.getSharedPreferences("crtech", Context.MODE_PRIVATE);
|
||||
Integer port = spf.getInt("port", -1);
|
||||
Integer screen_rotation = spf.getInt("screen_rotation", 3);
|
||||
String address = spf.getString("address", "").replaceAll(" ", "");
|
||||
String path = spf.getString("path", "").replaceAll(" ", "");
|
||||
NetworkSetting networkSetting = new NetworkSetting();
|
||||
networkSetting.setAddress(address);
|
||||
networkSetting.setPort(port);
|
||||
networkSetting.setPath(path);
|
||||
networkSetting.setScreen_rotation(screen_rotation);
|
||||
networkSetting.setHide_bar(spf.getInt("hide_bar", 0));
|
||||
return networkSetting;
|
||||
}
|
||||
|
||||
@ -51,7 +56,12 @@ public class NetworkSettingEngine implements SettingEngine {
|
||||
editor.putString("address", networkSetting.getAddress());
|
||||
editor.putString("path", networkSetting.getPath());
|
||||
editor.putInt("port", networkSetting.getPort());
|
||||
editor.putInt("screen_rotation", networkSetting.getScreen_rotation());
|
||||
editor.putInt("hide_bar", networkSetting.getHide_bar());
|
||||
editor.commit();
|
||||
MainActivity.SCREEN_ROTATION = networkSetting.getScreen_rotation();
|
||||
MainActivity.hideBar = networkSetting.getHide_bar();
|
||||
// MainActivity.startDirection = networkSetting.getStart_direction();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -109,22 +109,22 @@ public class TekVoiceEngine extends OfflineVoiceEngine {
|
||||
String info) {
|
||||
// 合成进度
|
||||
mPercentForBuffering = percent;
|
||||
showTip(String.format(context.getString(R.string.tts_toast_format),
|
||||
mPercentForBuffering, mPercentForPlaying));
|
||||
// showTip(String.format(context.getString(R.string.tts_toast_format),
|
||||
// mPercentForBuffering, mPercentForPlaying));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpeakProgress(int percent, int beginPos, int endPos) {
|
||||
// 播放进度
|
||||
mPercentForPlaying = percent;
|
||||
showTip(String.format(context.getString(R.string.tts_toast_format),
|
||||
mPercentForBuffering, mPercentForPlaying));
|
||||
// showTip(String.format(context.getString(R.string.tts_toast_format),
|
||||
// mPercentForBuffering, mPercentForPlaying));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted(SpeechError error) {
|
||||
if (error == null) {
|
||||
showTip("播放完成");
|
||||
// showTip("播放完成");
|
||||
} else if (error != null) {
|
||||
showTip(error.getPlainDescription(true));
|
||||
}
|
||||
|
||||
@ -0,0 +1,261 @@
|
||||
package chaoran.business.service;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.honeywell.aidc.AidcManager;
|
||||
import com.honeywell.aidc.BarcodeDeviceConnectionEvent;
|
||||
import com.honeywell.aidc.BarcodeFailureEvent;
|
||||
import com.honeywell.aidc.BarcodeReadEvent;
|
||||
import com.honeywell.aidc.BarcodeReader;
|
||||
import com.honeywell.aidc.BarcodeReaderInfo;
|
||||
import com.honeywell.aidc.ScannerNotClaimedException;
|
||||
import com.honeywell.aidc.ScannerUnavailableException;
|
||||
import com.honeywell.aidc.TriggerStateChangeEvent;
|
||||
import com.honeywell.aidc.UnsupportedPropertyException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
||||
public class ScanServiceEDA50P extends Service
|
||||
implements BarcodeReader.BarcodeListener, BarcodeReader.TriggerListener, AidcManager.BarcodeDeviceListener{
|
||||
private final String TAG = "TestScanService";
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private String notificationId = "channelId";
|
||||
private String notificationName = "channelName";
|
||||
|
||||
private String _Suffix = "\n";
|
||||
|
||||
|
||||
private AidcManager mAidcManager;
|
||||
private BarcodeReader mBarcodeReader;
|
||||
private BarcodeReader mInternalScannerReader;
|
||||
private boolean mKeyPressed = false;
|
||||
private boolean isContinue = true;
|
||||
|
||||
//必须要实现的方法
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
// Log.i(TAG, "onBind方法被调用!");
|
||||
return null;
|
||||
}
|
||||
|
||||
//Service被创建时调用
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// Log.i(TAG, "onCreate方法被调用!");
|
||||
super.onCreate();
|
||||
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
NotificationChannel channel = null;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { //适配9.0service
|
||||
// if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { //适配9.0service
|
||||
channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
Notification notification = new Notification.Builder(getApplicationContext(), notificationId).build();
|
||||
//startForeground(1,getNotification());
|
||||
startForeground(1, notification);
|
||||
}
|
||||
|
||||
AidcManager.create(this, new MyCreatedCallback());
|
||||
}
|
||||
|
||||
//Service被启动时调用
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Log.i(TAG, "onStartCommand方法被调用!");
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
//Service被关闭之前回调
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log.i(TAG, "onDestroy方法被调用!");
|
||||
super.onDestroy();
|
||||
if (mBarcodeReader != null) {
|
||||
mBarcodeReader.release();
|
||||
}
|
||||
if (this.mInternalScannerReader != null) {
|
||||
this.mInternalScannerReader.removeBarcodeListener(this);
|
||||
this.mInternalScannerReader.removeTriggerListener(this);
|
||||
this.mInternalScannerReader.close();
|
||||
this.mInternalScannerReader = null;
|
||||
Log.d(TAG, "Close internal scanner");
|
||||
}
|
||||
if (this.mAidcManager != null) {
|
||||
this.mAidcManager.removeBarcodeDeviceListener(this);
|
||||
this.mAidcManager.close();
|
||||
}
|
||||
|
||||
}
|
||||
class MyCreatedCallback implements AidcManager.CreatedCallback {
|
||||
MyCreatedCallback() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreated(AidcManager aidcManager) {
|
||||
Log.d(TAG, "MyCreatedCallback onCreate !!!");
|
||||
mAidcManager = aidcManager;
|
||||
mAidcManager.addBarcodeDeviceListener(ScanServiceEDA50P.this);
|
||||
initAllBarcodeReaderAndSetDefault();
|
||||
}
|
||||
}
|
||||
void initAllBarcodeReaderAndSetDefault() {
|
||||
List<BarcodeReaderInfo> readerList = mAidcManager.listBarcodeDevices();
|
||||
Log.d(TAG, "initAllBarcodeReaderAndSetDefault readerList = "+readerList);
|
||||
mInternalScannerReader = null;
|
||||
for (BarcodeReaderInfo reader : readerList) {
|
||||
if ("dcs.scanner.imager".equals(reader.getName())) {
|
||||
mInternalScannerReader = initBarcodeReader(mInternalScannerReader, reader.getName());
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "initAllBarcodeReaderAndSetDefault mInternalScannerReader = "+mInternalScannerReader);
|
||||
|
||||
if (mInternalScannerReader != null) {
|
||||
mBarcodeReader = mInternalScannerReader;
|
||||
}
|
||||
else {
|
||||
Log.d(TAG, "No reader find");
|
||||
}
|
||||
if (mBarcodeReader != null) {
|
||||
try {
|
||||
mBarcodeReader.addBarcodeListener(this);
|
||||
mBarcodeReader.addTriggerListener(this);
|
||||
}
|
||||
catch (Throwable e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
try {
|
||||
mBarcodeReader.setProperty(BarcodeReader.PROPERTY_NOTIFICATION_GOOD_READ_ENABLED, true);
|
||||
mBarcodeReader.setProperty(BarcodeReader.PROPERTY_EAN_13_CHECK_DIGIT_TRANSMIT_ENABLED, true);
|
||||
|
||||
} catch (UnsupportedPropertyException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
BarcodeReader initBarcodeReader(BarcodeReader mReader, String mReaderName) {
|
||||
if (mReader == null) {
|
||||
try {
|
||||
if (mReaderName == null) {
|
||||
mReader = mAidcManager.createBarcodeReader();
|
||||
} else {
|
||||
mReader = mAidcManager.createBarcodeReader(mReaderName);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(TAG, "error", e);
|
||||
}
|
||||
try {
|
||||
mReader.claim();
|
||||
Log.d(TAG, "Call DCS interface claim() " + mReaderName);
|
||||
} catch (ScannerUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
mReader.setProperty(BarcodeReader.PROPERTY_TRIGGER_CONTROL_MODE, BarcodeReader.TRIGGER_CONTROL_MODE_CLIENT_CONTROL);
|
||||
mReader.setProperty(BarcodeReader.PROPERTY_DATA_PROCESSOR_LAUNCH_EZ_CONFIG, false);
|
||||
mReader.setProperty(BarcodeReader.PROPERTY_TRIGGER_AUTO_MODE_TIMEOUT, 300);
|
||||
|
||||
} catch (UnsupportedPropertyException e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
return mReader;
|
||||
}
|
||||
|
||||
public void onBarcodeDeviceConnectionEvent(BarcodeDeviceConnectionEvent event) {
|
||||
Log.d(TAG, event.getBarcodeReaderInfo() + " Connection status: " + event.getConnectionStatus());
|
||||
}
|
||||
|
||||
public void onBarcodeEvent(final BarcodeReadEvent event) {
|
||||
String barcodeDate = new String(event.getBarcodeData().getBytes(event.getCharset()));
|
||||
Intent intent2 = new Intent("com.honeywell.scan.broadcast");
|
||||
intent2.putExtra("data",barcodeDate);
|
||||
sendBroadcast(intent2);
|
||||
if(isContinue) {
|
||||
executorService.execute(new MyThread(mBarcodeReader));
|
||||
}
|
||||
}
|
||||
ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
class MyThread implements Runnable{
|
||||
private BarcodeReader mBarcodeReader;
|
||||
public MyThread(BarcodeReader mBarcodeReader){
|
||||
this.mBarcodeReader = mBarcodeReader;
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
{
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
mBarcodeReader.decode(true);
|
||||
} catch (ScannerNotClaimedException e) {
|
||||
Log.e(TAG, "catch ScannerNotClaimedException",e);
|
||||
e.printStackTrace();
|
||||
} catch (ScannerUnavailableException e2) {
|
||||
Log.e(TAG, "catch ScannerUnavailableException",e2);
|
||||
e2.printStackTrace();
|
||||
} catch (Exception e3) {
|
||||
e3.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
public void onFailureEvent(final BarcodeFailureEvent event) {
|
||||
//Log.d(TAG, "Enter onFailureEvent ===> " + event.getTimestamp());
|
||||
if(isContinue) {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
// doScan(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void onTriggerEvent(TriggerStateChangeEvent event) {
|
||||
if (event.getState()) {
|
||||
if (!mKeyPressed) {
|
||||
mKeyPressed = true;
|
||||
doScan(true);
|
||||
}else{
|
||||
mKeyPressed = false;
|
||||
doScan(false);
|
||||
}
|
||||
} else {
|
||||
//mKeyPressed = false;
|
||||
// doScan(false);
|
||||
}
|
||||
// Log.d(TAG, "OnTriggerEvent status: " + event.getState());
|
||||
}
|
||||
void doScan(boolean do_scan) {
|
||||
try {
|
||||
if (do_scan) {
|
||||
// Log.d(TAG, "Start a new Scan!");
|
||||
} else {
|
||||
// Log.d(TAG, "Cancel last Scan!");
|
||||
}
|
||||
mBarcodeReader.decode(do_scan);
|
||||
} catch (ScannerNotClaimedException e) {
|
||||
Log.e(TAG, "catch ScannerNotClaimedException",e);
|
||||
e.printStackTrace();
|
||||
} catch (ScannerUnavailableException e2) {
|
||||
Log.e(TAG, "catch ScannerUnavailableException",e2);
|
||||
e2.printStackTrace();
|
||||
} catch (Exception e3) {
|
||||
e3.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
333
app/src/main/java/chaoran/business/service/ScanServiceZEBRA.java
Normal file
@ -0,0 +1,333 @@
|
||||
package chaoran.business.service;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.symbol.emdk.EMDKManager;
|
||||
import com.symbol.emdk.EMDKResults;
|
||||
import com.symbol.emdk.barcode.BarcodeManager;
|
||||
import com.symbol.emdk.barcode.ScanDataCollection;
|
||||
import com.symbol.emdk.barcode.Scanner;
|
||||
import com.symbol.emdk.barcode.ScannerConfig;
|
||||
import com.symbol.emdk.barcode.ScannerException;
|
||||
import com.symbol.emdk.barcode.ScannerResults;
|
||||
import com.symbol.emdk.barcode.StatusData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ScanServiceZEBRA extends Service implements EMDKManager.EMDKListener, Scanner.DataListener, Scanner.StatusListener {
|
||||
private final String TAG = "ScanService";
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private String notificationId = "ScanServiceId";
|
||||
private String notificationName = "ScanServiceName";
|
||||
|
||||
private EMDKManager emdkManager = null;
|
||||
private BarcodeManager barcodeManager = null;
|
||||
private Scanner scanner = null;
|
||||
|
||||
private String statusString = "";
|
||||
|
||||
private boolean bSoftTriggerSelected = true;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
Log.i(TAG, "onBind方法被调用!");
|
||||
return null;
|
||||
}
|
||||
|
||||
//Service被创建时调用
|
||||
@Override
|
||||
public void onCreate() {
|
||||
Log.i(TAG, "onCreate方法被调用!");
|
||||
super.onCreate();
|
||||
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
NotificationChannel channel = null;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { //适配8.0service
|
||||
channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
Notification notification = new Notification.Builder(getApplicationContext(), notificationId).build();
|
||||
//startForeground(1,getNotification());
|
||||
startForeground(1, notification);
|
||||
}
|
||||
EMDKResults results = EMDKManager.getEMDKManager(getApplicationContext(), this);
|
||||
final IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction("com.pda.scan.trigger");
|
||||
registerReceiver(myCodeReceiver, intentFilter);
|
||||
}
|
||||
private MyCodeReceiver myCodeReceiver = new MyCodeReceiver();
|
||||
|
||||
public class MyCodeReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
int keyCode = intent.getIntExtra("data",0);
|
||||
if(keyCode == 103 || keyCode == 10036){
|
||||
if(bSoftTriggerSelected){
|
||||
bSoftTriggerSelected = false;
|
||||
}else{
|
||||
bSoftTriggerSelected = true;
|
||||
cancelRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* private Notification getNotification() {
|
||||
Notification.Builder builder = new Notification.Builder(this)
|
||||
.setContentTitle("连续扫描服务")
|
||||
.setContentText("正在运行");
|
||||
builder.setChannelId(notificationId);
|
||||
Notification notification = builder.build();
|
||||
return notification;
|
||||
}*/
|
||||
|
||||
//Service被启动时调用
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Log.i(TAG, "onStartCommand方法被调用!");
|
||||
|
||||
//setconfig();
|
||||
initScanner();
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
public void setconfig(){
|
||||
Intent i = new Intent();
|
||||
i.setAction("com.symbol.datawedge.api.ACTION");
|
||||
i.putExtra("com.symbol.datawedge.api.SET_DEFAULT_PROFILE", "myProfile");
|
||||
sendBroadcast(i);
|
||||
}
|
||||
@Override
|
||||
public void onOpened(EMDKManager emdkManager) {
|
||||
updateStatus("EMDK open success!");
|
||||
this.emdkManager = emdkManager;
|
||||
// Acquire the barcode manager resources
|
||||
initBarcodeManager();
|
||||
// Enumerate scanner devices
|
||||
// enumerateScannerDevices();
|
||||
initScanner();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed() {
|
||||
// Release all the resources
|
||||
if (emdkManager != null) {
|
||||
emdkManager.release();
|
||||
emdkManager = null;
|
||||
}
|
||||
updateStatus("EMDK closed unexpectedly! Please close and restart the application.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
// Release all the resources
|
||||
if (emdkManager != null) {
|
||||
emdkManager.release();
|
||||
emdkManager = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onData(ScanDataCollection scanDataCollection) {
|
||||
if ((scanDataCollection != null) && (scanDataCollection.getResult() == ScannerResults.SUCCESS)) {
|
||||
ArrayList<ScanDataCollection.ScanData> scanData = scanDataCollection.getScanData();
|
||||
for (ScanDataCollection.ScanData data : scanData) {
|
||||
updateData(data.getData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatus(StatusData statusData) {
|
||||
StatusData.ScannerStates state = statusData.getState();
|
||||
switch (state) {
|
||||
case IDLE:
|
||||
statusString = statusData.getFriendlyName() + " is enabled and idle...";
|
||||
updateStatus(statusString);
|
||||
// set trigger type
|
||||
if(bSoftTriggerSelected) {
|
||||
scanner.triggerType = Scanner.TriggerType.SOFT_ALWAYS;
|
||||
setDecoders();
|
||||
} else {
|
||||
scanner.triggerType = Scanner.TriggerType.HARD;
|
||||
cancelRead();
|
||||
}
|
||||
// submit read
|
||||
if (!scanner.isReadPending()) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
Log.i("jqtest:", "scan");
|
||||
scanner.read();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
updateStatus(e.getMessage());
|
||||
try {
|
||||
deInitScanner();
|
||||
Thread.sleep(200);
|
||||
}catch (Exception e1){
|
||||
e1.printStackTrace();
|
||||
}
|
||||
initScanner();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WAITING:
|
||||
statusString = "Scanner is waiting for trigger press...";
|
||||
updateStatus(statusString);
|
||||
break;
|
||||
case SCANNING:
|
||||
statusString = "Scanning...";
|
||||
updateStatus(statusString);
|
||||
break;
|
||||
case DISABLED:
|
||||
statusString = statusData.getFriendlyName() + " is disabled.";
|
||||
updateStatus(statusString);
|
||||
break;
|
||||
case ERROR:
|
||||
statusString = "An error has occurred.";
|
||||
updateStatus(statusString);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void initScanner() {
|
||||
if (scanner == null) {
|
||||
if (barcodeManager != null) {
|
||||
scanner = barcodeManager.getDevice(BarcodeManager.DeviceIdentifier.DEFAULT);
|
||||
} else {
|
||||
updateStatus("Failed to get the specified scanner device! Please close and restart the application.");
|
||||
return;
|
||||
}
|
||||
if (scanner != null) {
|
||||
scanner.addDataListener(this);
|
||||
scanner.addStatusListener(this);
|
||||
try {
|
||||
scanner.enable();
|
||||
} catch (ScannerException e) {
|
||||
updateStatus(e.getMessage());
|
||||
deInitScanner();
|
||||
}
|
||||
} else {
|
||||
updateStatus("Failed to initialize the scanner device.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deInitScanner() {
|
||||
if (scanner != null) {
|
||||
try {
|
||||
scanner.disable();
|
||||
} catch (Exception e) {
|
||||
updateStatus(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
scanner.removeDataListener(this);
|
||||
scanner.removeStatusListener(this);
|
||||
} catch (Exception e) {
|
||||
updateStatus(e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
scanner.release();
|
||||
} catch (Exception e) {
|
||||
updateStatus(e.getMessage());
|
||||
}
|
||||
scanner = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void initBarcodeManager() {
|
||||
barcodeManager = (BarcodeManager) emdkManager.getInstance(EMDKManager.FEATURE_TYPE.BARCODE);
|
||||
|
||||
}
|
||||
|
||||
private void deInitBarcodeManager() {
|
||||
if (emdkManager != null) {
|
||||
emdkManager.release(EMDKManager.FEATURE_TYPE.BARCODE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* private void enumerateScannerDevices() {
|
||||
if (barcodeManager != null) {
|
||||
List<ScannerInfo> deviceList = barcodeManager.getSupportedDevicesInfo();
|
||||
if ((deviceList != null) && (deviceList.size() != 0)) {
|
||||
Iterator<ScannerInfo> it = deviceList.iterator();
|
||||
while (it.hasNext()) {
|
||||
ScannerInfo scnInfo = it.next();
|
||||
if (scnInfo.isDefaultScanner()) {
|
||||
scannerInfo = scnInfo;
|
||||
Log.i("scannerInfo", scannerInfo.getFriendlyName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
private void setDecoders() {
|
||||
if (scanner != null) {
|
||||
try {
|
||||
ScannerConfig config = scanner.getConfig();
|
||||
// Set EAN8
|
||||
config.decoderParams.ean8.enabled = true;
|
||||
// Set EAN13
|
||||
config.decoderParams.ean13.enabled = true;
|
||||
// Set Code39
|
||||
config.decoderParams.code39.enabled = true;
|
||||
//Set Code128
|
||||
config.decoderParams.code128.enabled = true;
|
||||
// config.readerParams.readerSpecific.imagerSpecific.aimType = ScannerConfig.AimType.PRESENTATION;
|
||||
scanner.setConfig(config);
|
||||
} catch (ScannerException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelRead() {
|
||||
if (scanner != null) {
|
||||
if (scanner.isReadPending()) {
|
||||
try {
|
||||
scanner.cancelRead();
|
||||
} catch (ScannerException e) {
|
||||
updateStatus(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStatus(final String status) {
|
||||
//Log.i("status",status);
|
||||
// runOnUiThread(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// textViewStatus.setText("" + status);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
private void updateData(final String result) {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
super.run();
|
||||
Intent intent2 = new Intent("com.pda.scan.result");
|
||||
intent2.putExtra("data", result);
|
||||
sendBroadcast(intent2);
|
||||
Log.i(TAG, result);
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
97
app/src/main/java/chaoran/business/utils/CameraHelper.java
Normal file
@ -0,0 +1,97 @@
|
||||
package chaoran.business.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 相机辅助类 - 通过JavaScript接口直接调用相机
|
||||
*/
|
||||
public class CameraHelper {
|
||||
|
||||
private static final int REQUEST_CODE_CAMERA_DIRECT = 1003;
|
||||
private Activity activity;
|
||||
private WebView webView;
|
||||
private Uri cameraPhotoUri;
|
||||
private String currentPhotoPath;
|
||||
|
||||
public CameraHelper(Activity activity, WebView webView) {
|
||||
this.activity = activity;
|
||||
this.webView = webView;
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接打开相机拍照
|
||||
*/
|
||||
@JavascriptInterface
|
||||
public void openCamera() {
|
||||
activity.runOnUiThread(() -> {
|
||||
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if (cameraIntent.resolveActivity(activity.getPackageManager()) != null) {
|
||||
File photoFile = createImageFile();
|
||||
if (photoFile != null) {
|
||||
currentPhotoPath = photoFile.getAbsolutePath();
|
||||
cameraPhotoUri = FileProvider.getUriForFile(
|
||||
activity,
|
||||
activity.getPackageName() + ".fileprovider",
|
||||
photoFile
|
||||
);
|
||||
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPhotoUri);
|
||||
cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
activity.startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA_DIRECT);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建图片文件
|
||||
*/
|
||||
private File createImageFile() {
|
||||
try {
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||
String imageFileName = "JPEG_" + timeStamp + "_";
|
||||
File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
if (storageDir != null && !storageDir.exists()) {
|
||||
storageDir.mkdirs();
|
||||
}
|
||||
return File.createTempFile(imageFileName, ".jpg", storageDir);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理Activity结果
|
||||
*/
|
||||
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == REQUEST_CODE_CAMERA_DIRECT) {
|
||||
if (resultCode == Activity.RESULT_OK && cameraPhotoUri != null) {
|
||||
// 通知JavaScript照片已拍摄
|
||||
String jsCode = "javascript:onCameraResult('" + cameraPhotoUri.toString() + "', '" + currentPhotoPath + "')";
|
||||
webView.post(() -> webView.loadUrl(jsCode));
|
||||
} else {
|
||||
// 取消拍照
|
||||
String jsCode = "javascript:onCameraResult(null, null)";
|
||||
webView.post(() -> webView.loadUrl(jsCode));
|
||||
}
|
||||
cameraPhotoUri = null;
|
||||
currentPhotoPath = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
package chaoran.business.utils;
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import java.io.File;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class DataCleanManager {
|
||||
|
||||
/**
|
||||
* 获取缓存总大小
|
||||
*/
|
||||
public static String getTotalCacheSize(Context context) throws Exception {
|
||||
long cacheSize = getFolderSize(context.getCacheDir());
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
cacheSize += getFolderSize(context.getExternalCacheDir());
|
||||
}
|
||||
return getFormatSize(cacheSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有缓存
|
||||
*/
|
||||
public static void clearAllCache(Context context) {
|
||||
deleteDir(context.getCacheDir());
|
||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||
deleteDir(context.getExternalCacheDir());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean deleteDir(File dir) {
|
||||
if (dir != null && dir.isDirectory()) {
|
||||
String[] children = dir.list();
|
||||
for (String child : children) {
|
||||
boolean success = deleteDir(new File(dir, child));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dir.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件夹大小
|
||||
*/
|
||||
private static long getFolderSize(File file) throws Exception {
|
||||
long size = 0;
|
||||
try {
|
||||
File[] fileList = file.listFiles();
|
||||
for (File aFileList : fileList) {
|
||||
if (aFileList.isDirectory()) {
|
||||
size += getFolderSize(aFileList);
|
||||
} else {
|
||||
size += aFileList.length();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文件大小
|
||||
*/
|
||||
private static String getFormatSize(double size) {
|
||||
double kiloByte = size / 1024;
|
||||
if (kiloByte < 1) {
|
||||
return size + "Byte";
|
||||
}
|
||||
double megaByte = kiloByte / 1024;
|
||||
if (megaByte < 1) {
|
||||
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
|
||||
return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB";
|
||||
}
|
||||
double gigaByte = megaByte / 1024;
|
||||
if (gigaByte < 1) {
|
||||
BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
|
||||
return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB";
|
||||
}
|
||||
double teraBytes = gigaByte / 1024;
|
||||
if (teraBytes < 1) {
|
||||
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
|
||||
return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB";
|
||||
}
|
||||
BigDecimal result4 = new BigDecimal(teraBytes);
|
||||
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB";
|
||||
}
|
||||
}
|
||||
378
app/src/main/java/chaoran/business/utils/FileChooserHelper.java
Normal file
@ -0,0 +1,378 @@
|
||||
package chaoran.business.utils;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 文件选择和相机拍照辅助类
|
||||
*/
|
||||
public class FileChooserHelper {
|
||||
|
||||
private static final String TAG = "FileChooserHelper";
|
||||
private static final int REQUEST_CODE_CAMERA = 1001;
|
||||
private static final int REQUEST_CODE_FILE_CHOOSER = 1002;
|
||||
private static final int REQUEST_CODE_PERMISSION_CAMERA = 2001;
|
||||
private static final int REQUEST_CODE_PERMISSION_STORAGE = 2002;
|
||||
|
||||
private Activity activity;
|
||||
private ValueCallback<Uri[]> filePathCallback;
|
||||
private Uri cameraPhotoUri;
|
||||
private boolean pendingAcceptImage = false;
|
||||
private boolean pendingAcceptCamera = false;
|
||||
private boolean pendingCameraOnly = false;
|
||||
|
||||
public FileChooserHelper(Activity activity) {
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开文件选择器(支持相机和图片选择)
|
||||
*/
|
||||
public void openFileChooser(ValueCallback<Uri[]> callback, boolean acceptImage, boolean acceptCamera) {
|
||||
openFileChooser(callback, acceptImage, acceptCamera, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开文件选择器(支持相机和图片选择)
|
||||
* @param callback 文件选择回调
|
||||
* @param acceptImage 是否只接受图片
|
||||
* @param acceptCamera 是否支持相机
|
||||
* @param cameraOnly 是否仅使用相机(不显示文件选择器)
|
||||
*/
|
||||
public void openFileChooser(ValueCallback<Uri[]> callback, boolean acceptImage, boolean acceptCamera, boolean cameraOnly) {
|
||||
this.filePathCallback = callback;
|
||||
this.pendingAcceptImage = acceptImage;
|
||||
this.pendingAcceptCamera = acceptCamera;
|
||||
this.pendingCameraOnly = cameraOnly;
|
||||
|
||||
// 检查权限
|
||||
if (acceptCamera && !checkCameraPermission()) {
|
||||
requestCameraPermission();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cameraOnly && !checkStoragePermission()) {
|
||||
requestStoragePermission();
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建选择器
|
||||
showFileChooser();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示文件选择器
|
||||
*/
|
||||
private void showFileChooser() {
|
||||
Intent chooserIntent = createChooserIntent(pendingAcceptImage, pendingAcceptCamera);
|
||||
if (chooserIntent != null) {
|
||||
try {
|
||||
activity.startActivityForResult(chooserIntent, REQUEST_CODE_FILE_CHOOSER);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "打开文件选择器失败", e);
|
||||
Toast.makeText(activity, "打开文件选择器失败", Toast.LENGTH_SHORT).show();
|
||||
if (filePathCallback != null) {
|
||||
filePathCallback.onReceiveValue(null);
|
||||
filePathCallback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建选择器Intent
|
||||
*/
|
||||
private Intent createChooserIntent(boolean acceptImage, boolean acceptCamera) {
|
||||
// 如果只需要相机,直接返回相机Intent
|
||||
if (acceptCamera && pendingCameraOnly) {
|
||||
return createCameraIntent();
|
||||
}
|
||||
|
||||
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
|
||||
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
|
||||
if (acceptImage) {
|
||||
contentSelectionIntent.setType("image/*");
|
||||
} else {
|
||||
contentSelectionIntent.setType("*/*");
|
||||
}
|
||||
|
||||
Intent[] intentArray;
|
||||
if (acceptCamera) {
|
||||
Intent cameraIntent = createCameraIntent();
|
||||
if (cameraIntent != null) {
|
||||
intentArray = new Intent[]{cameraIntent};
|
||||
} else {
|
||||
intentArray = new Intent[0];
|
||||
}
|
||||
} else {
|
||||
intentArray = new Intent[0];
|
||||
}
|
||||
|
||||
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
|
||||
chooserIntent.putExtra(Intent.EXTRA_TITLE, "选择文件");
|
||||
|
||||
return chooserIntent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建相机Intent
|
||||
*/
|
||||
private Intent createCameraIntent() {
|
||||
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if (cameraIntent.resolveActivity(activity.getPackageManager()) != null) {
|
||||
File photoFile = createImageFile();
|
||||
if (photoFile != null) {
|
||||
cameraPhotoUri = FileProvider.getUriForFile(
|
||||
activity,
|
||||
activity.getPackageName() + ".fileprovider",
|
||||
photoFile
|
||||
);
|
||||
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraPhotoUri);
|
||||
cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
return cameraIntent;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建图片文件
|
||||
*/
|
||||
private File createImageFile() {
|
||||
try {
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||
String imageFileName = "JPEG_" + timeStamp + "_";
|
||||
File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
if (storageDir != null && !storageDir.exists()) {
|
||||
storageDir.mkdirs();
|
||||
}
|
||||
return File.createTempFile(imageFileName, ".jpg", storageDir);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "创建图片文件失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理Activity结果
|
||||
*/
|
||||
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == REQUEST_CODE_FILE_CHOOSER) {
|
||||
if (filePathCallback == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Uri[] results = null;
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (data != null && data.getData() != null) {
|
||||
// 从文件选择器选择的文件
|
||||
results = new Uri[]{data.getData()};
|
||||
} else if (cameraPhotoUri != null) {
|
||||
// 从相机拍摄的照片
|
||||
results = new Uri[]{cameraPhotoUri};
|
||||
}
|
||||
}
|
||||
|
||||
filePathCallback.onReceiveValue(results);
|
||||
filePathCallback = null;
|
||||
cameraPhotoUri = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理权限请求结果
|
||||
*/
|
||||
public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (requestCode == REQUEST_CODE_PERMISSION_CAMERA) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
Toast.makeText(activity, "相机权限已授予", Toast.LENGTH_SHORT).show();
|
||||
// 权限授予后,检查存储权限
|
||||
if (!checkStoragePermission()) {
|
||||
requestStoragePermission();
|
||||
} else {
|
||||
// 权限都已授予,重新打开文件选择器
|
||||
showFileChooser();
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(activity, "相机权限被拒绝", Toast.LENGTH_SHORT).show();
|
||||
if (filePathCallback != null) {
|
||||
filePathCallback.onReceiveValue(null);
|
||||
filePathCallback = null;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (requestCode == REQUEST_CODE_PERMISSION_STORAGE) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
Toast.makeText(activity, "存储权限已授予", Toast.LENGTH_SHORT).show();
|
||||
// 权限授予后,重新打开文件选择器
|
||||
showFileChooser();
|
||||
} else {
|
||||
Toast.makeText(activity, "存储权限被拒绝", Toast.LENGTH_SHORT).show();
|
||||
if (filePathCallback != null) {
|
||||
filePathCallback.onReceiveValue(null);
|
||||
filePathCallback = null;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查相机权限
|
||||
*/
|
||||
private boolean checkCameraPermission() {
|
||||
return ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求相机权限
|
||||
*/
|
||||
private void requestCameraPermission() {
|
||||
ActivityCompat.requestPermissions(activity,
|
||||
new String[]{Manifest.permission.CAMERA},
|
||||
REQUEST_CODE_PERMISSION_CAMERA);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查存储权限
|
||||
* Android 10+ 使用分区存储,不需要READ_EXTERNAL_STORAGE权限来访问通过文件选择器选择的文件
|
||||
*/
|
||||
private boolean checkStoragePermission() {
|
||||
if (Build.VERSION.SDK_INT >= 33) { // Android 13 (TIRAMISU)
|
||||
// Android 13+ 使用新的媒体权限
|
||||
return ContextCompat.checkSelfPermission(activity, "android.permission.READ_MEDIA_IMAGES")
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
} else if (Build.VERSION.SDK_INT >= 29) { // Android 10 (Q)
|
||||
// Android 10-12 使用分区存储,通过文件选择器不需要权限
|
||||
return true;
|
||||
} else {
|
||||
// Android 9 需要存储权限
|
||||
return ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求存储权限
|
||||
*/
|
||||
private void requestStoragePermission() {
|
||||
if (Build.VERSION.SDK_INT >= 33) { // Android 13 (TIRAMISU)
|
||||
// Android 13+ 请求新的媒体权限
|
||||
ActivityCompat.requestPermissions(activity,
|
||||
new String[]{"android.permission.READ_MEDIA_IMAGES"},
|
||||
REQUEST_CODE_PERMISSION_STORAGE);
|
||||
} else if (Build.VERSION.SDK_INT >= 29) { // Android 10 (Q)
|
||||
// Android 10-12 不需要请求权限
|
||||
Toast.makeText(activity, "存储权限已授予", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
// Android 9 请求存储权限
|
||||
ActivityCompat.requestPermissions(activity,
|
||||
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||
REQUEST_CODE_PERMISSION_STORAGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名
|
||||
*/
|
||||
public static String getFileName(Context context, Uri uri) {
|
||||
String result = null;
|
||||
if (uri.getScheme().equals("content")) {
|
||||
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
if (nameIndex >= 0) {
|
||||
result = cursor.getString(nameIndex);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "获取文件名失败", e);
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
result = uri.getPath();
|
||||
int cut = result.lastIndexOf('/');
|
||||
if (cut != -1) {
|
||||
result = result.substring(cut + 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件转换为Base64字符串
|
||||
*/
|
||||
public static String fileToBase64(Context context, Uri uri) {
|
||||
try {
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(uri);
|
||||
if (inputStream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
byteArrayOutputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
inputStream.close();
|
||||
|
||||
byte[] fileBytes = byteArrayOutputStream.toByteArray();
|
||||
return Base64.encodeToString(fileBytes, Base64.NO_WRAP);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "文件转Base64失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件大小
|
||||
*/
|
||||
public static long getFileSize(Context context, Uri uri) {
|
||||
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
|
||||
if (sizeIndex >= 0) {
|
||||
return cursor.getLong(sizeIndex);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "获取文件大小失败", e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
725
app/src/main/java/chaoran/business/utils/LocalAddressUtil.java
Normal file
@ -0,0 +1,725 @@
|
||||
package chaoran.business.utils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.media.ExifInterface;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.Settings;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
|
||||
import chaoran.business.BuildConfig;
|
||||
|
||||
public class LocalAddressUtil {
|
||||
|
||||
public final static String SSO_KEY = "!~CROP@CRTECH@PDA~!";
|
||||
|
||||
private Context context;
|
||||
|
||||
private Activity activity;
|
||||
|
||||
private View view;
|
||||
|
||||
private int[] heights;
|
||||
|
||||
private static final String TAG = "LocalAddressUtil";
|
||||
private static final int REQUEST_CODE_NATIVE_CAMERA = 31002;
|
||||
private static final int REQUEST_CODE_PERMISSION_CAMERA = 31001;
|
||||
private static final String DEFAULT_CAMERA_CALLBACK = "onNativeCameraResult";
|
||||
|
||||
// Base64 settings for camera callback
|
||||
private static final int CAMERA_IMAGE_DECODE_MAX_DIMENSION = 3200;
|
||||
private static final int CAMERA_OUTPUT_JPEG_QUALITY = 90;
|
||||
private static final int CAMERA_OUTPUT_JPEG_MIN_QUALITY = 55;
|
||||
private static final int CAMERA_OUTPUT_BASE64_MAX_BYTES = 500 * 1024;
|
||||
private static final int CAMERA_OUTPUT_IMAGE_MAX_BYTES = CAMERA_OUTPUT_BASE64_MAX_BYTES / 4 * 3;
|
||||
private static final String CAMERA_RAW_DATA_URL_PREFIX = "data:image/jpeg;base64,";
|
||||
private static final String CAMERA_WATERMARK_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
private Uri nativeCameraPhotoUri;
|
||||
private String pendingCameraCallback = null;
|
||||
private boolean pendingCameraCompress = true;
|
||||
private boolean pendingCameraWatermark = false;
|
||||
|
||||
public LocalAddressUtil(Context context, Activity activity, View view) {
|
||||
this.context = context;
|
||||
this.activity = activity;
|
||||
this.view = view;
|
||||
this.heights = StatusBarUtil.getStatusBarHeight(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接调用原生相机(默认回调:window.onNativeCameraResult(base64OrDataUrl, error))
|
||||
*/
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public void openNativeCamera() {
|
||||
openNativeCamera(DEFAULT_CAMERA_CALLBACK, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接调用原生相机(自定义回调函数名:window[callback](base64OrDataUrl, error))
|
||||
* @param callback JS 回调函数名(不需要传 window. 前缀)
|
||||
*/
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public void openNativeCamera(String callback) {
|
||||
openNativeCamera(callback, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接调用原生相机(自定义回调函数名:window[callback](base64OrDataUrl, error))
|
||||
* @param callback JS 回调函数名(不需要传 window. 前缀)
|
||||
* @param needCompress 是否压缩,默认压缩到约 500KB base64
|
||||
* @param addWatermark 是否添加拍照时间水印
|
||||
*/
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public void openNativeCamera(String callback, boolean needCompress, boolean addWatermark) {
|
||||
this.pendingCameraCallback = (callback == null || callback.trim().isEmpty())
|
||||
? DEFAULT_CAMERA_CALLBACK
|
||||
: callback.trim();
|
||||
this.pendingCameraCompress = needCompress;
|
||||
this.pendingCameraWatermark = addWatermark;
|
||||
|
||||
if (!checkCameraPermission()) {
|
||||
ActivityCompat.requestPermissions(activity,
|
||||
new String[]{android.Manifest.permission.CAMERA},
|
||||
REQUEST_CODE_PERMISSION_CAMERA);
|
||||
return;
|
||||
}
|
||||
|
||||
Intent cameraIntent = createNativeCameraIntent();
|
||||
if (cameraIntent == null) {
|
||||
dispatchCameraResultToJs(null, "create_intent_failed");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
activity.startActivityForResult(cameraIntent, REQUEST_CODE_NATIVE_CAMERA);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "启动相机失败", e);
|
||||
dispatchCameraResultToJs(null, "start_failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 由宿主 Activity 转发调用
|
||||
*/
|
||||
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode != REQUEST_CODE_NATIVE_CAMERA) {
|
||||
return false;
|
||||
}
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
String dataUrl = buildCameraPhotoDataUrl(nativeCameraPhotoUri, pendingCameraCompress, pendingCameraWatermark);
|
||||
if (dataUrl == null || dataUrl.trim().isEmpty()) {
|
||||
dispatchCameraResultToJs(null, "encode_failed");
|
||||
} else {
|
||||
dispatchCameraResultToJs(dataUrl, null);
|
||||
}
|
||||
} else {
|
||||
dispatchCameraResultToJs(null, "cancelled");
|
||||
}
|
||||
nativeCameraPhotoUri = null;
|
||||
pendingCameraCompress = true;
|
||||
pendingCameraWatermark = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 由宿主 Activity 转发调用
|
||||
*/
|
||||
public boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (requestCode != REQUEST_CODE_PERMISSION_CAMERA) {
|
||||
return false;
|
||||
}
|
||||
boolean granted = grantResults != null && grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED;
|
||||
if (granted) {
|
||||
openNativeCamera(pendingCameraCallback, pendingCameraCompress, pendingCameraWatermark);
|
||||
} else {
|
||||
dispatchCameraResultToJs(null, "permission_denied");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkCameraPermission() {
|
||||
return ContextCompat.checkSelfPermission(activity, android.Manifest.permission.CAMERA)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
private Intent createNativeCameraIntent() {
|
||||
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if (cameraIntent.resolveActivity(activity.getPackageManager()) == null) {
|
||||
return null;
|
||||
}
|
||||
File photoFile = createImageFile();
|
||||
if (photoFile == null) {
|
||||
return null;
|
||||
}
|
||||
nativeCameraPhotoUri = FileProvider.getUriForFile(
|
||||
activity,
|
||||
activity.getPackageName() + ".fileprovider",
|
||||
photoFile
|
||||
);
|
||||
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, nativeCameraPhotoUri);
|
||||
cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
return cameraIntent;
|
||||
}
|
||||
|
||||
private File createImageFile() {
|
||||
try {
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||
String imageFileName = "JPEG_" + timeStamp + "_";
|
||||
File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
if (storageDir != null && !storageDir.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
storageDir.mkdirs();
|
||||
}
|
||||
return File.createTempFile(imageFileName, ".jpg", storageDir);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "创建图片文件失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将拍照结果转为 dataUrl(base64)
|
||||
*/
|
||||
private String buildCameraPhotoDataUrl(Uri uri, boolean needCompress, boolean addWatermark) {
|
||||
if (uri == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] rawBytes;
|
||||
try {
|
||||
rawBytes = readBytesFromUri(uri);
|
||||
if (rawBytes == null || rawBytes.length == 0) {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "读取原图失败", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!addWatermark && (!needCompress || rawBytes.length <= CAMERA_OUTPUT_IMAGE_MAX_BYTES)) {
|
||||
String base64 = Base64.encodeToString(rawBytes, Base64.NO_WRAP);
|
||||
String dataUrl = CAMERA_RAW_DATA_URL_PREFIX + base64;
|
||||
Log.i(TAG, "camera_base64_size rawBytes=" + rawBytes.length
|
||||
+ " rawKb=" + String.format(Locale.getDefault(), "%.2f", rawBytes.length / 1024f)
|
||||
+ " resultBytes=" + rawBytes.length
|
||||
+ " resultKb=" + String.format(Locale.getDefault(), "%.2f", rawBytes.length / 1024f)
|
||||
+ " base64Chars=" + base64.length()
|
||||
+ " base64Kb=" + String.format(Locale.getDefault(), "%.2f", base64.length() / 1024f)
|
||||
+ " dataUrlChars=" + dataUrl.length()
|
||||
+ " needCompress=" + needCompress
|
||||
+ " addWatermark=" + addWatermark
|
||||
+ " outputWidth=raw"
|
||||
+ " outputHeight=raw"
|
||||
+ " outputFormat=jpeg_raw");
|
||||
return dataUrl;
|
||||
}
|
||||
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = context.getContentResolver().openInputStream(uri);
|
||||
if (inputStream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
if (needCompress) {
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeStream(inputStream, null, options);
|
||||
safeClose(inputStream);
|
||||
inputStream = context.getContentResolver().openInputStream(uri);
|
||||
if (inputStream == null) {
|
||||
return null;
|
||||
}
|
||||
options.inSampleSize = calculateInSampleSize(options.outWidth, options.outHeight, CAMERA_IMAGE_DECODE_MAX_DIMENSION);
|
||||
options.inJustDecodeBounds = false;
|
||||
}
|
||||
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, options);
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int rotateDegree = readImageRotateDegree(uri);
|
||||
if (rotateDegree != 0) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postRotate(rotateDegree);
|
||||
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
if (rotatedBitmap != bitmap) {
|
||||
bitmap.recycle();
|
||||
bitmap = rotatedBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
if (addWatermark) {
|
||||
Bitmap.Config config = bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888;
|
||||
if (!bitmap.isMutable()) {
|
||||
Bitmap watermarkBitmap = bitmap.copy(config, true);
|
||||
if (watermarkBitmap == null) {
|
||||
return null;
|
||||
}
|
||||
if (watermarkBitmap != bitmap) {
|
||||
bitmap.recycle();
|
||||
bitmap = watermarkBitmap;
|
||||
}
|
||||
}
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
String watermark = new SimpleDateFormat(CAMERA_WATERMARK_TIME_PATTERN, Locale.getDefault()).format(new Date());
|
||||
float textSize = Math.max(28f, bitmap.getWidth() / 16f);
|
||||
float padding = Math.max(18f, textSize * 0.45f);
|
||||
Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
textPaint.setColor(Color.WHITE);
|
||||
textPaint.setTextSize(textSize);
|
||||
textPaint.setFakeBoldText(true);
|
||||
textPaint.setShadowLayer(4f, 0f, 1f, 0x66000000);
|
||||
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
|
||||
Rect textBounds = new Rect();
|
||||
textPaint.getTextBounds(watermark, 0, watermark.length(), textBounds);
|
||||
float left = padding;
|
||||
float bottom = bitmap.getHeight() - padding;
|
||||
float top = bottom - (fontMetrics.descent - fontMetrics.ascent) - padding * 1.6f;
|
||||
float right = left + textBounds.width() + padding * 2f;
|
||||
Paint bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
bgPaint.setColor(0xB3000000);
|
||||
canvas.drawRoundRect(left, top, right, bottom, padding, padding, bgPaint);
|
||||
Paint borderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
borderPaint.setColor(0x66FFFFFF);
|
||||
borderPaint.setStyle(Paint.Style.STROKE);
|
||||
borderPaint.setStrokeWidth(Math.max(2f, textSize / 14f));
|
||||
canvas.drawRoundRect(left, top, right, bottom, padding, padding, borderPaint);
|
||||
float textY = bottom - padding - fontMetrics.descent;
|
||||
canvas.drawText(watermark, left + padding, textY, textPaint);
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
int quality = CAMERA_OUTPUT_JPEG_QUALITY;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
|
||||
bytes = baos.toByteArray();
|
||||
int outputWidth = bitmap.getWidth();
|
||||
int outputHeight = bitmap.getHeight();
|
||||
|
||||
if (needCompress && bytes.length > CAMERA_OUTPUT_IMAGE_MAX_BYTES) {
|
||||
int guard = 0;
|
||||
while (bytes.length > CAMERA_OUTPUT_IMAGE_MAX_BYTES && guard < 12) {
|
||||
guard++;
|
||||
while (bytes.length > CAMERA_OUTPUT_IMAGE_MAX_BYTES && quality > CAMERA_OUTPUT_JPEG_MIN_QUALITY) {
|
||||
quality = Math.max(CAMERA_OUTPUT_JPEG_MIN_QUALITY, quality - 5);
|
||||
baos.reset();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
|
||||
bytes = baos.toByteArray();
|
||||
}
|
||||
if (bytes.length <= CAMERA_OUTPUT_IMAGE_MAX_BYTES) {
|
||||
break;
|
||||
}
|
||||
|
||||
int nextWidth = Math.max(1, Math.round(bitmap.getWidth() * 0.85f));
|
||||
int nextHeight = Math.max(1, Math.round(bitmap.getHeight() * 0.85f));
|
||||
if (nextWidth == bitmap.getWidth() && nextHeight == bitmap.getHeight()) {
|
||||
break;
|
||||
}
|
||||
|
||||
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, nextWidth, nextHeight, true);
|
||||
if (scaledBitmap != bitmap) {
|
||||
bitmap.recycle();
|
||||
bitmap = scaledBitmap;
|
||||
}
|
||||
outputWidth = bitmap.getWidth();
|
||||
outputHeight = bitmap.getHeight();
|
||||
quality = CAMERA_OUTPUT_JPEG_QUALITY;
|
||||
baos.reset();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
|
||||
bytes = baos.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.recycle();
|
||||
if (bytes == null || bytes.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String base64 = Base64.encodeToString(bytes, Base64.NO_WRAP);
|
||||
String dataUrl = CAMERA_RAW_DATA_URL_PREFIX + base64;
|
||||
Log.i(TAG, "camera_base64_size rawBytes=" + rawBytes.length
|
||||
+ " rawKb=" + String.format(Locale.getDefault(), "%.2f", rawBytes.length / 1024f)
|
||||
+ " resultBytes=" + bytes.length
|
||||
+ " resultKb=" + String.format(Locale.getDefault(), "%.2f", bytes.length / 1024f)
|
||||
+ " base64Chars=" + base64.length()
|
||||
+ " base64Kb=" + String.format(Locale.getDefault(), "%.2f", base64.length() / 1024f)
|
||||
+ " dataUrlChars=" + dataUrl.length()
|
||||
+ " needCompress=" + needCompress
|
||||
+ " addWatermark=" + addWatermark
|
||||
+ " outputWidth=" + outputWidth
|
||||
+ " outputHeight=" + outputHeight
|
||||
+ " jpegQuality=" + quality
|
||||
+ " targetBytes=" + (needCompress ? CAMERA_OUTPUT_IMAGE_MAX_BYTES : -1)
|
||||
+ " outputFormat=jpeg");
|
||||
return dataUrl;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "图片转base64失败", e);
|
||||
return null;
|
||||
} finally {
|
||||
safeClose(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] readBytesFromUri(Uri uri) throws IOException {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = context.getContentResolver().openInputStream(uri);
|
||||
if (inputStream == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[8192];
|
||||
int len;
|
||||
while ((len = inputStream.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, len);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
} finally {
|
||||
safeClose(inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
private int readImageRotateDegree(Uri uri) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = context.getContentResolver().openInputStream(uri);
|
||||
if (inputStream == null) {
|
||||
return 0;
|
||||
}
|
||||
ExifInterface exifInterface = new ExifInterface(inputStream);
|
||||
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
|
||||
return 90;
|
||||
}
|
||||
if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
|
||||
return 180;
|
||||
}
|
||||
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
|
||||
return 270;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "读取图片方向失败", e);
|
||||
} finally {
|
||||
safeClose(inputStream);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int calculateInSampleSize(int srcW, int srcH, int maxDim) {
|
||||
if (srcW <= 0 || srcH <= 0 || maxDim <= 0) {
|
||||
return 1;
|
||||
}
|
||||
int maxSrc = Math.max(srcW, srcH);
|
||||
int inSampleSize = 1;
|
||||
while (maxSrc / inSampleSize > maxDim) {
|
||||
inSampleSize *= 2;
|
||||
}
|
||||
return Math.max(1, inSampleSize);
|
||||
}
|
||||
|
||||
private void safeClose(InputStream is) {
|
||||
try {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchCameraResultToJs(String dataUrl, String error) {
|
||||
if (!(view instanceof WebView)) {
|
||||
return;
|
||||
}
|
||||
WebView webView = (WebView) view;
|
||||
String cb = (pendingCameraCallback == null || pendingCameraCallback.trim().isEmpty())
|
||||
? DEFAULT_CAMERA_CALLBACK
|
||||
: pendingCameraCallback.trim();
|
||||
|
||||
String js = "try{" +
|
||||
"var cb=window[" + JSONObject.quote(cb) + "];" +
|
||||
"if(typeof cb==='function'){cb(" + JSONObject.quote(dataUrl) + "," + JSONObject.quote(error) + ");}" +
|
||||
"}catch(e){}";
|
||||
|
||||
webView.post(() -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
webView.evaluateJavascript(js, null);
|
||||
} else {
|
||||
webView.loadUrl("javascript:" + js);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public String getIpAddress() {
|
||||
try {
|
||||
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
|
||||
NetworkInterface intf = en.nextElement();
|
||||
// if(!intf.getDisplayName().equals("eth0")) continue;
|
||||
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
|
||||
InetAddress inetAddress = enumIpAddr.nextElement();
|
||||
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
|
||||
return inetAddress.getHostAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SocketException ex) {
|
||||
Log.e("address: local", ex.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public String getMacAddress(){//可以兼容安卓7以下
|
||||
SharedPreferences spf = context.getSharedPreferences("chaoran_mac", Context.MODE_PRIVATE);
|
||||
String saveMac = spf.getString("chaoran_mac", "");
|
||||
if (!"".equalsIgnoreCase(saveMac)) {
|
||||
return saveMac;
|
||||
}
|
||||
SharedPreferences.Editor editor = spf.edit();
|
||||
String androidMac = getAndroidMac();
|
||||
editor.putString("chaoran_mac", androidMac);
|
||||
editor.apply();
|
||||
return androidMac;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取安卓的mac
|
||||
* @return
|
||||
*/
|
||||
private String getAndroidMac() {
|
||||
if (Build.VERSION.SDK_INT >= 34) { // Android 14 is code-named Tiramisu
|
||||
try {
|
||||
return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||
}catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return generateRandomMacAddress();
|
||||
}
|
||||
}
|
||||
String macAddress = null;
|
||||
StringBuffer buf = new StringBuffer();
|
||||
NetworkInterface networkInterface = null;
|
||||
try {
|
||||
networkInterface = NetworkInterface.getByName("eth1");
|
||||
if (networkInterface == null) {
|
||||
networkInterface = NetworkInterface.getByName("wlan0");
|
||||
}
|
||||
if (networkInterface == null) {
|
||||
return generateRandomMacAddress();
|
||||
}
|
||||
byte[] addr = networkInterface.getHardwareAddress();
|
||||
for (byte b : addr) {
|
||||
buf.append(String.format("%02X:", b));
|
||||
}
|
||||
if (buf.length() > 0) {
|
||||
buf.deleteCharAt(buf.length() - 1);
|
||||
}
|
||||
macAddress = buf.toString();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
macAddress = generateRandomMacAddress();
|
||||
}
|
||||
if (macAddress.length() < 4) {
|
||||
macAddress = generateRandomMacAddress();
|
||||
}
|
||||
return macAddress;
|
||||
}
|
||||
|
||||
private static String generateRandomMacAddress() {
|
||||
Random rand = new Random();
|
||||
byte[] macBytes = new byte[6];
|
||||
rand.nextBytes(macBytes);
|
||||
macBytes[0] = (byte) (macBytes[0] & 0xfe | 0x02);
|
||||
StringBuilder macAddress = new StringBuilder();
|
||||
for (int i = 0; i < macBytes.length; i++) {
|
||||
macAddress.append(String.format("%02X%s", macBytes[i], (i < macBytes.length - 1) ? ":" : ""));
|
||||
}
|
||||
return macAddress.toString();
|
||||
}
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public String getInfo(int type){
|
||||
String info;
|
||||
switch (type) {
|
||||
case 1: info = Build.BRAND;break;//品牌
|
||||
case 2: info = Build.MODEL;break;//型号
|
||||
case 3: info = Build.MANUFACTURER;break;//厂商
|
||||
case 4: info = Build.DEVICE;break;//设备名
|
||||
case 5: info = Build.ID;break;//设备硬件id
|
||||
// case 6: info = Build.SERIAL;break;//序列号,可能获取不到
|
||||
default: info = "";break;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public String getHeight(int type) {
|
||||
String info = "";
|
||||
switch (type) {
|
||||
case 1 : info = String.valueOf(this.heights[0]); break;
|
||||
case 2 : info = String.valueOf(this.heights[1]); break;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public void test(){
|
||||
Log.e("test", "MANUFACTURER=" + Build.MANUFACTURER);
|
||||
Log.e("test", "BRAND=" + Build.BRAND);
|
||||
Log.e("test", "MODEL=" + Build.MODEL);
|
||||
Log.e("test", "VERSION.RELEASE=" + Build.VERSION.RELEASE);
|
||||
Log.e("test", "VERSION.SDK_INT=" + Build.VERSION.SDK_INT);
|
||||
Log.e("test", "DEVICE=" + Build.DEVICE);
|
||||
Log.e("test", "HOST=" + Build.HOST);
|
||||
Log.e("test", "ID=" + Build.ID);
|
||||
Log.e("test", "TIME=" + Build.TIME);
|
||||
Log.e("test", "TYPE=" + Build.TYPE);
|
||||
Log.e("test", "PRODUCT=" + Build.PRODUCT);
|
||||
Log.e("test", "BOARD=" + Build.BOARD);
|
||||
Log.e("test", "DISPLAY=" + Build.DISPLAY);
|
||||
Log.e("test", "FINGERPRINT=" + Build.FINGERPRINT);
|
||||
Log.e("test", "HARDWARE=" + Build.HARDWARE);
|
||||
Log.e("test", "BOOTLOADER=" + Build.BOOTLOADER);
|
||||
Log.e("test", "TAGS=" + Build.TAGS);
|
||||
Log.e("test", "UNKNOWN=" + Build.UNKNOWN);
|
||||
Log.e("test", "USER=" + Build.USER);
|
||||
}
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public void rotateScreen() {
|
||||
int angle = ((WindowManager)activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
|
||||
|
||||
switch (angle) {
|
||||
case Surface.ROTATION_0:
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
||||
break;
|
||||
case Surface.ROTATION_180:
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public String registerMac(String applyMac) {
|
||||
try {
|
||||
String mac = this.getMacAddress();
|
||||
String md5Hash = MD5.md5(mac + SSO_KEY);
|
||||
if ("Crtech!register@PDA#APK".equals(applyMac) || (md5Hash != null && md5Hash.equals(applyMac))) {
|
||||
// 将允许注册适配的mac写入文件中
|
||||
SharedPreferences.Editor editor = context.getSharedPreferences("CrtechPdaConfig", Context.MODE_PRIVATE).edit();
|
||||
editor.putString("checkMac", "success");
|
||||
if ("Crtech!register@PDA#APK".equals(applyMac)) {
|
||||
editor.putString("checkMacTime", String.valueOf(System.currentTimeMillis()));
|
||||
editor.putString("checkMacType", "1");
|
||||
}else {
|
||||
editor.putString("checkMacType", "0");
|
||||
}
|
||||
editor.commit();
|
||||
return "success";
|
||||
}
|
||||
}catch (Exception ignored) {
|
||||
|
||||
}
|
||||
return "error";
|
||||
}
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public String checkMacRegister() {
|
||||
SharedPreferences sharedPreferences = context.getSharedPreferences("CrtechPdaConfig", Context.MODE_PRIVATE);
|
||||
String checkMac = sharedPreferences.getString("checkMac", "error");
|
||||
if (!"success".equals(checkMac)) {
|
||||
return "error";
|
||||
}
|
||||
if ("1".equals(sharedPreferences.getString("checkMacType", "0"))) {
|
||||
// 判断是否是强行注册的,强行注册的只允许使用一个小时;一但判断到,就取消注册
|
||||
Long aLong = Long.valueOf(sharedPreferences.getString("checkMacTime", String.valueOf(System.currentTimeMillis())));
|
||||
if ((aLong + 1 * 60 * 60 * 1000) < System.currentTimeMillis()) {
|
||||
SharedPreferences.Editor edit = sharedPreferences.edit();
|
||||
edit.putString("checkMac", "error");
|
||||
edit.commit();
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
return "success";
|
||||
}
|
||||
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public String getApkVersion() {
|
||||
return BuildConfig.VERSION_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* 暴露PDA的厂家和型号
|
||||
* @return String 格式:厂家:型号
|
||||
*/
|
||||
@SuppressLint("JavascriptInterface")
|
||||
@JavascriptInterface
|
||||
public String getPdaInfo() {
|
||||
return Build.MANUFACTURER + ":" + Build.MODEL.toLowerCase();
|
||||
}
|
||||
}
|
||||
34
app/src/main/java/chaoran/business/utils/MD5.java
Normal file
@ -0,0 +1,34 @@
|
||||
package chaoran.business.utils;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
// 从框架的MD5加密类拷贝过来的
|
||||
public class MD5 {
|
||||
private static final String key = "aa";
|
||||
private static final char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
||||
public static final String md5(String s) {
|
||||
return s == null ? null : md5(s.getBytes());
|
||||
}
|
||||
|
||||
public static final String md5(byte[] bytes) {
|
||||
try {
|
||||
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
|
||||
mdTemp.update(bytes);
|
||||
byte[] md = mdTemp.digest();
|
||||
int j = md.length;
|
||||
char[] str = new char[j * 2];
|
||||
int k = 0;
|
||||
|
||||
for(int i = 0; i < j; ++i) {
|
||||
byte byte0 = md[i];
|
||||
str[k++] = hexDigits[byte0 >>> 4 & 15];
|
||||
str[k++] = hexDigits[byte0 & 15];
|
||||
}
|
||||
|
||||
return new String(str);
|
||||
} catch (Exception var8) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
217
app/src/main/java/chaoran/business/utils/StatusBarUtil.java
Normal file
@ -0,0 +1,217 @@
|
||||
package chaoran.business.utils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.readystatesoftware.systembartint.SystemBarTintManager;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 状态栏工具类
|
||||
*/
|
||||
public class StatusBarUtil {
|
||||
/**
|
||||
* 修改状态栏为全透明
|
||||
*
|
||||
* @param activity
|
||||
*/
|
||||
@TargetApi(19)
|
||||
public static void transparencyBar(Activity activity) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = activity.getWindow();
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
window.setStatusBarColor(Color.TRANSPARENT);
|
||||
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
Window window = activity.getWindow();
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
|
||||
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取屏幕的高度和状态栏高度
|
||||
* @param context
|
||||
* @return 第一个是屏幕,第二个是状态栏
|
||||
*/
|
||||
public static int[] getStatusBarHeight(Context context) {
|
||||
int[] result = new int[]{0,0};
|
||||
int resourceld = context.getResources().getIdentifier(
|
||||
"status_bar_height", "dimen", "android"
|
||||
);
|
||||
if (resourceld > 0) {
|
||||
result[0] = context.getResources().getDisplayMetrics().heightPixels;
|
||||
result[1] = context.getResources().getDimensionPixelSize(resourceld);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//隐藏状态栏
|
||||
public static void hideStatusBar(Activity activity){
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
activity.getWindow()
|
||||
.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改状态栏颜色,支持4.4以上版本
|
||||
*
|
||||
* @param activity
|
||||
* @param colorId
|
||||
*/
|
||||
public static void setStatusBarColor(Activity activity, int colorId) {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = activity.getWindow();
|
||||
window.setStatusBarColor(activity.getResources().getColor(colorId));
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
//使用SystemBarTint库使4.4版本状态栏变色,需要先将状态栏设置为透明
|
||||
transparencyBar(activity);
|
||||
SystemBarTintManager tintManager = new SystemBarTintManager(activity);
|
||||
tintManager.setStatusBarTintEnabled(true);
|
||||
tintManager.setStatusBarTintResource(colorId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态栏亮色模式,设置状态栏黑色文字、图标,
|
||||
* 适配4.4以上版本MIUIV、Flyme和6.0以上版本其他Android
|
||||
*
|
||||
* @param activity
|
||||
* @return 1:MIUUI 2:Flyme 3:android6.0
|
||||
*/
|
||||
public static int StatusBarLightMode(Activity activity) {
|
||||
int result = 0;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
if (MIUISetStatusBarLightMode(activity, true)) {
|
||||
result = 1;
|
||||
} else if (FlymeSetStatusBarLightMode(activity.getWindow(), true)) {
|
||||
result = 2;
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
result = 3;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 已知系统类型时,设置状态栏黑色文字、图标。
|
||||
* 适配4.4以上版本MIUIV、Flyme和6.0以上版本其他Android
|
||||
*
|
||||
* @param activity
|
||||
* @param type 1:MIUUI 2:Flyme 3:android6.0
|
||||
*/
|
||||
public static void StatusBarLightMode(Activity activity, int type) {
|
||||
if (type == 1) {
|
||||
MIUISetStatusBarLightMode(activity, true);
|
||||
} else if (type == 2) {
|
||||
FlymeSetStatusBarLightMode(activity.getWindow(), true);
|
||||
} else if (type == 3) {
|
||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态栏暗色模式,清除MIUI、flyme或6.0以上版本状态栏黑色文字、图标
|
||||
*/
|
||||
public static void StatusBarDarkMode(Activity activity, int type) {
|
||||
if (type == 1) {
|
||||
MIUISetStatusBarLightMode(activity, false);
|
||||
} else if (type == 2) {
|
||||
FlymeSetStatusBarLightMode(activity.getWindow(), false);
|
||||
} else if (type == 3) {
|
||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 设置状态栏图标为深色和魅族特定的文字风格
|
||||
* 可以用来判断是否为Flyme用户
|
||||
*
|
||||
* @param window 需要设置的窗口
|
||||
* @param dark 是否把状态栏文字及图标颜色设置为深色
|
||||
* @return boolean 成功执行返回true
|
||||
*/
|
||||
public static boolean FlymeSetStatusBarLightMode(Window window, boolean dark) {
|
||||
boolean result = false;
|
||||
if (window != null) {
|
||||
try {
|
||||
WindowManager.LayoutParams lp = window.getAttributes();
|
||||
Field darkFlag = WindowManager.LayoutParams.class
|
||||
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
|
||||
Field meizuFlags = WindowManager.LayoutParams.class
|
||||
.getDeclaredField("meizuFlags");
|
||||
darkFlag.setAccessible(true);
|
||||
meizuFlags.setAccessible(true);
|
||||
int bit = darkFlag.getInt(null);
|
||||
int value = meizuFlags.getInt(lp);
|
||||
if (dark) {
|
||||
value |= bit;
|
||||
} else {
|
||||
value &= ~bit;
|
||||
}
|
||||
meizuFlags.setInt(lp, value);
|
||||
window.setAttributes(lp);
|
||||
result = true;
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 需要MIUIV6以上
|
||||
*
|
||||
* @param activity
|
||||
* @param dark 是否把状态栏文字及图标颜色设置为深色
|
||||
* @return boolean 成功执行返回true
|
||||
*/
|
||||
public static boolean MIUISetStatusBarLightMode(Activity activity, boolean dark) {
|
||||
boolean result = false;
|
||||
Window window = activity.getWindow();
|
||||
if (window != null) {
|
||||
Class clazz = window.getClass();
|
||||
try {
|
||||
int darkModeFlag = 0;
|
||||
Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
|
||||
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
|
||||
darkModeFlag = field.getInt(layoutParams);
|
||||
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
|
||||
if (dark) {
|
||||
extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
|
||||
} else {
|
||||
extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
|
||||
}
|
||||
result = true;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
//开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上
|
||||
if (dark) {
|
||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
} else {
|
||||
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 26 KiB |
11
app/src/main/res/layout/activity_file_test.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webViewFileTest"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</RelativeLayout>
|
||||
@ -7,6 +7,7 @@
|
||||
android:id="@+id/table">
|
||||
|
||||
|
||||
|
||||
<TableRow>
|
||||
|
||||
<TextView />
|
||||
@ -42,6 +43,7 @@
|
||||
android:minWidth="150dp"
|
||||
android:id="@+id/port"
|
||||
android:singleLine="true"
|
||||
android:inputType="number"
|
||||
android:hint="介于1024-65535之间的数字" />
|
||||
|
||||
<TextView />
|
||||
@ -68,6 +70,56 @@
|
||||
</TableRow>
|
||||
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="隐藏状态栏:" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/hide_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="1:隐藏;0显示"
|
||||
android:minWidth="150dp"
|
||||
android:inputType="number"
|
||||
android:digits="01"
|
||||
android:singleLine="true" />
|
||||
|
||||
<TextView />
|
||||
</TableRow>
|
||||
|
||||
<TableRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="屏幕方向:" />
|
||||
|
||||
<EditText
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="150dp"
|
||||
android:id="@+id/screen_rotation"
|
||||
android:singleLine="true"
|
||||
android:inputType="number"
|
||||
android:digits="12345678"
|
||||
android:hint="5正竖;6倒竖;7正横;8倒横;1竖;2横;3横竖;4禁止" />
|
||||
|
||||
<TextView />
|
||||
</TableRow>
|
||||
|
||||
|
||||
|
||||
<TableRow>
|
||||
|
||||
<TextView />
|
||||
|
||||
@ -113,7 +113,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:max="200"
|
||||
android:min="100"
|
||||
android:min="0"
|
||||
android:id="@+id/voice_speed" />
|
||||
|
||||
<TextView />
|
||||
|
||||
@ -14,4 +14,10 @@
|
||||
android:orderInCategory="100"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_file_test"
|
||||
android:title="@string/action_file_test"
|
||||
android:orderInCategory="100"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 26 KiB |
BIN
app/src/main/res/raw/ding.wav
Normal file
@ -4,10 +4,12 @@
|
||||
<string name="title_activity_setting_network">网络设置界面</string>
|
||||
<string name="action_setting_voice">语音设置</string>
|
||||
<string name="title_activity_setting_voice">语音设置界面</string>
|
||||
<string name="action_file_test">文件测试</string>
|
||||
<string name="title_activity_file_test">文件选择测试</string>
|
||||
<string name="title_activity_main">主页</string>
|
||||
|
||||
<!-- 讯飞离线语音appid-->
|
||||
<string name="app_id">601c9ec6</string>
|
||||
<string name="app_id">602e1727</string>
|
||||
|
||||
<!-- 讯飞离线语音弹出框格式-->
|
||||
<string name="tts_toast_format" formatted="false">缓冲进度为%d%%,播放进度为%d%%</string>
|
||||
|
||||
7
app/src/main/res/xml/file_paths.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-path name="external_files" path="." />
|
||||
<external-cache-path name="external_cache" path="." />
|
||||
<cache-path name="cache" path="." />
|
||||
<files-path name="files" path="." />
|
||||
</paths>
|
||||
@ -5,7 +5,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:4.1.0"
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
||||