Compare commits
11 Commits
android-ma
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
011bfe2450 | ||
|
|
e52c86ea1a | ||
|
|
f1ae60c69f | ||
|
|
c906e8ac66 | ||
|
|
dff8489c36 | ||
|
|
030479a962 | ||
|
|
b581e310ed | ||
|
|
c579544351 | ||
|
|
aa08a75aef | ||
|
|
6187976b6b | ||
|
|
59e9203363 |
6
.gitignore
vendored
@@ -25,6 +25,12 @@ vite.config.ts.timestamp-*
|
|||||||
/src-tauri/target/
|
/src-tauri/target/
|
||||||
/src-tauri/target-codex-check*/
|
/src-tauri/target-codex-check*/
|
||||||
/src-tauri/gen/schemas/
|
/src-tauri/gen/schemas/
|
||||||
|
/src-tauri/gen/android/app/build/
|
||||||
|
/src-tauri/gen/android/buildSrc/build/
|
||||||
|
/src-tauri/gen/android/.gradle/
|
||||||
|
/src-tauri/gen/android/app/.gradle/
|
||||||
|
/src-tauri/gen/android/buildSrc/.gradle/
|
||||||
|
/src-tauri/gen/android/build/reports/
|
||||||
|
|
||||||
/src-tauri/program.log*
|
/src-tauri/program.log*
|
||||||
/src-tauri/recording_replay_debug_*.csv
|
/src-tauri/recording_replay_debug_*.csv
|
||||||
|
|||||||
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "eskin-finger-sdk"]
|
||||||
|
path = eskin-finger-sdk
|
||||||
|
url = https://gitea.e-skin.top/yanjie/eskin-finger-sdk.git
|
||||||
52
README.md
@@ -1,11 +1,10 @@
|
|||||||
# JE-Skin (SvelteKit + Tauri)
|
# Tauri Demo (SvelteKit + TypeScript)
|
||||||
|
|
||||||
## 环境要求
|
## 环境要求
|
||||||
|
|
||||||
- Node.js 18+(建议 LTS)
|
- Node.js 18+(建议 LTS)
|
||||||
- Rust stable(`rustup` + `cargo`)
|
- Rust stable(`rustup` + `cargo`)
|
||||||
- Windows 下请确保已安装 WebView2 Runtime 和 MSVC C++ 构建工具
|
- Windows 下请确保已安装 WebView2 Runtime 和 MSVC C++ 构建工具
|
||||||
- Android 构建需要 Android SDK + NDK
|
|
||||||
|
|
||||||
## 安装依赖
|
## 安装依赖
|
||||||
|
|
||||||
@@ -43,61 +42,12 @@ npm run build
|
|||||||
npm run tauri build
|
npm run tauri build
|
||||||
```
|
```
|
||||||
|
|
||||||
构建 Android APK / AAB:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npx tauri android build
|
|
||||||
```
|
|
||||||
|
|
||||||
产物路径:
|
|
||||||
- APK: `src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk`
|
|
||||||
- AAB: `src-tauri/gen/android/app/build/outputs/bundle/universalRelease/app-universal-release.aab`
|
|
||||||
|
|
||||||
Release APK 默认使用 debug keystore 签名(`src-tauri/gen/android/app/je-skin-debug.keystore`),可直接 `adb install` 到设备。
|
|
||||||
|
|
||||||
## 代码检查
|
## 代码检查
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm run check
|
npm run check
|
||||||
```
|
```
|
||||||
|
|
||||||
## v0.5.0 修改记录
|
|
||||||
|
|
||||||
### Android USB 串口接入
|
|
||||||
|
|
||||||
- **Tauri 插件注册**:Android 端通过 Rust builder 注册 `usb-serial` 插件,移除 `MainActivity` 中的手动加载逻辑
|
|
||||||
- **USB 设备枚举**:使用 `usb-serial-for-android` 的 `UsbSerialProber` 识别串口设备,并返回设备名、厂商 ID、产品 ID、权限状态等信息
|
|
||||||
- **USB 权限申请**:完善 Android USB 授权回调,支持按设备名、vendorId/productId 解析设备并处理授权后的打开流程
|
|
||||||
- **串口数据桥接**:Kotlin 端打开 USB serial port 后通过 Unix socketpair 将 fd 交给 Rust,Rust 端继续复用 `serial_connect_fd` 数据采集链路
|
|
||||||
- **资源释放**:关闭连接时同步释放桥接 fd、USB serial port 和 `UsbDeviceConnection`,避免重复打开后的资源残留
|
|
||||||
|
|
||||||
### Tauri 权限与构建
|
|
||||||
|
|
||||||
- 新增 `src-tauri/permissions/usb-serial/default.toml`,声明 Android USB serial 插件命令和前端所需本地命令权限
|
|
||||||
- `default.json` 增加 USB serial 与本地命令权限,兼容 snake_case / camelCase 插件命令名
|
|
||||||
- Android Gradle 仓库加入 JitPack,用于解析 USB serial 驱动依赖
|
|
||||||
- ProGuard 增加 Tauri 插件注解、`UsbSerialPlugin` 和 `com.hoho.android.usbserial` 保留规则,避免 release 包混淆后插件命令失效
|
|
||||||
- Android 构建下 `serial_enum` 返回空列表,并仅保留 fd 连接入口,避免桌面串口枚举依赖进入 Android 编译路径
|
|
||||||
|
|
||||||
## v0.4.0 修改记录
|
|
||||||
|
|
||||||
### 移动端性能优化
|
|
||||||
|
|
||||||
- **SignalChart / SummaryCurve**:在 `@media (max-width: 900px)` 下移除 SVG 路径上的 `filter: drop-shadow()`,避免移动端 GPU 软件回流导致卡顿
|
|
||||||
- **SignalChart**:隐藏 `.scan-haze`(`mix-blend-mode: screen` 合成开销大),简化面板 `background` / `box-shadow`
|
|
||||||
- **SummaryCurve**:移动端移除 `.summary-line` 和 `.summary-dot` 的 drop-shadow 滤镜
|
|
||||||
- **页面级**:移动端隐藏 `.hud-noise`(`feTurbulence` SVG 滤镜是最大性能杀手),降低 `.hud-vignette` 透明度,简化 `.hud-gradient`
|
|
||||||
- 移除 inactive 面板的 `filter: blur()` 过渡动画
|
|
||||||
- 移除 transition 中的 `filter` 属性,添加 `will-change: d` 优化路径更新
|
|
||||||
|
|
||||||
### 移动端 UI 调整
|
|
||||||
|
|
||||||
- **隐藏三大金刚**:`@media (max-width: 900px)` 下隐藏标题栏右侧的最小化/最大化/关闭按钮(Android 系统自带窗口管理)
|
|
||||||
|
|
||||||
### Android 打包
|
|
||||||
|
|
||||||
- Release 构建配置使用 debug keystore 签名,输出签名 APK 而非 unsigned
|
|
||||||
|
|
||||||
## 推荐 IDE 插件
|
## 推荐 IDE 插件
|
||||||
|
|
||||||
[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
|
[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
|
||||||
|
|||||||
BIN
ad_solver.6dgoloo5nyv74ie878md8rtxa.rcgu.o
Normal file
BIN
ad_solver.ad_solver.cdfee8e00be01766-cgu.0.rcgu.o
Normal file
BIN
ad_solver.exe
Normal file
BIN
ad_solver.pdb
Normal file
BIN
devkit/__pycache__/sensor_server.cpython-314.pyc
Normal file
BIN
devkit/__pycache__/sensor_stream_pb2.cpython-314.pyc
Normal file
BIN
devkit/__pycache__/sensor_stream_pb2_grpc.cpython-314.pyc
Normal file
2188
devkit/build/je-skin-devkit-server/Analysis-00.toc
Normal file
359
devkit/build/je-skin-devkit-server/EXE-00.toc
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
('d:\\JE-Skin-main\\devkit\\dist\\je-skin-devkit-server.exe',
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\bootloader\\images\\icon-console.ico',
|
||||||
|
None,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<assembly xmlns='
|
||||||
|
b'"urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n <trustInfo x'
|
||||||
|
b'mlns="urn:schemas-microsoft-com:asm.v3">\n <security>\n <requested'
|
||||||
|
b'Privileges>\n <requestedExecutionLevel level="asInvoker" uiAccess='
|
||||||
|
b'"false"/>\n </requestedPrivileges>\n </security>\n </trustInfo>\n '
|
||||||
|
b'<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\n <'
|
||||||
|
b'application>\n <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f'
|
||||||
|
b'0}"/>\n <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\n '
|
||||||
|
b' <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\n <s'
|
||||||
|
b'upportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\n <supporte'
|
||||||
|
b'dOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\n </application>\n <'
|
||||||
|
b'/compatibility>\n <application xmlns="urn:schemas-microsoft-com:asm.v3">'
|
||||||
|
b'\n <windowsSettings>\n <longPathAware xmlns="http://schemas.micros'
|
||||||
|
b'oft.com/SMI/2016/WindowsSettings">true</longPathAware>\n </windowsSett'
|
||||||
|
b'ings>\n </application>\n <dependency>\n <dependentAssembly>\n <ass'
|
||||||
|
b'emblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version='
|
||||||
|
b'"6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" langua'
|
||||||
|
b'ge="*"/>\n </dependentAssembly>\n </dependency>\n</assembly>',
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\je-skin-devkit-server.pkg',
|
||||||
|
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||||
|
('PYZ-00.pyz',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\PYZ-00.pyz',
|
||||||
|
'PYZ'),
|
||||||
|
('struct',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\struct.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod01_archive',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod01_archive.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod02_importers',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod02_importers.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod03_ctypes',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod03_ctypes.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod04_pywin32',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod04_pywin32.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyiboot01_bootstrap',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_inspect',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_pkgutil',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_multiprocessing',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('sensor_server', 'D:\\JE-Skin-main\\devkit\\sensor_server.py', 'PYSOURCE'),
|
||||||
|
('python314.dll', 'C:\\Python314\\python314.dll', 'BINARY'),
|
||||||
|
('numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('select.pyd', 'C:\\Python314\\DLLs\\select.pyd', 'EXTENSION'),
|
||||||
|
('_multiprocessing.pyd',
|
||||||
|
'C:\\Python314\\DLLs\\_multiprocessing.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_zstd.pyd', 'C:\\Python314\\DLLs\\_zstd.pyd', 'EXTENSION'),
|
||||||
|
('pyexpat.pyd', 'C:\\Python314\\DLLs\\pyexpat.pyd', 'EXTENSION'),
|
||||||
|
('_lzma.pyd', 'C:\\Python314\\DLLs\\_lzma.pyd', 'EXTENSION'),
|
||||||
|
('_bz2.pyd', 'C:\\Python314\\DLLs\\_bz2.pyd', 'EXTENSION'),
|
||||||
|
('_ssl.pyd', 'C:\\Python314\\DLLs\\_ssl.pyd', 'EXTENSION'),
|
||||||
|
('_hashlib.pyd', 'C:\\Python314\\DLLs\\_hashlib.pyd', 'EXTENSION'),
|
||||||
|
('unicodedata.pyd', 'C:\\Python314\\DLLs\\unicodedata.pyd', 'EXTENSION'),
|
||||||
|
('_decimal.pyd', 'C:\\Python314\\DLLs\\_decimal.pyd', 'EXTENSION'),
|
||||||
|
('_socket.pyd', 'C:\\Python314\\DLLs\\_socket.pyd', 'EXTENSION'),
|
||||||
|
('_ctypes.pyd', 'C:\\Python314\\DLLs\\_ctypes.pyd', 'EXTENSION'),
|
||||||
|
('_queue.pyd', 'C:\\Python314\\DLLs\\_queue.pyd', 'EXTENSION'),
|
||||||
|
('numpy\\_core\\_multiarray_tests.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\_core\\_multiarray_tests.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\_core\\_multiarray_umath.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\_core\\_multiarray_umath.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_wmi.pyd', 'C:\\Python314\\DLLs\\_wmi.pyd', 'EXTENSION'),
|
||||||
|
('_overlapped.pyd', 'C:\\Python314\\DLLs\\_overlapped.pyd', 'EXTENSION'),
|
||||||
|
('_asyncio.pyd', 'C:\\Python314\\DLLs\\_asyncio.pyd', 'EXTENSION'),
|
||||||
|
('numpy\\linalg\\_umath_linalg.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\linalg\\_umath_linalg.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\mtrand.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\mtrand.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\bit_generator.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\bit_generator.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_sfc64.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_sfc64.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_philox.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_philox.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_pcg64.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_pcg64.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_mt19937.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_mt19937.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_generator.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_generator.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_common.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_common.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_bounded_integers.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_bounded_integers.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\fft\\_pocketfft_umath.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\fft\\_pocketfft_umath.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_elementtree.pyd', 'C:\\Python314\\DLLs\\_elementtree.pyd', 'EXTENSION'),
|
||||||
|
('grpc\\_cython\\cygrpc.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\cygrpc.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('google\\_upb\\_message.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\google\\_upb\\_message.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('grpc_tools\\_protoc_compiler.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc_tools\\_protoc_compiler.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-locale-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-locale-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-time-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-time-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-environment-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-environment-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-runtime-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-runtime-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-convert-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-convert-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-heap-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-heap-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-string-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-string-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-process-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-process-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-math-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-math-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-stdio-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-stdio-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-conio-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-conio-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('VCRUNTIME140.dll', 'C:\\Python314\\VCRUNTIME140.dll', 'BINARY'),
|
||||||
|
('VCRUNTIME140_1.dll', 'C:\\Python314\\VCRUNTIME140_1.dll', 'BINARY'),
|
||||||
|
('api-ms-win-crt-utility-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-utility-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-private-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-private-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('libcrypto-3.dll', 'C:\\Python314\\DLLs\\libcrypto-3.dll', 'BINARY'),
|
||||||
|
('libssl-3.dll', 'C:\\Python314\\DLLs\\libssl-3.dll', 'BINARY'),
|
||||||
|
('libffi-8.dll', 'C:\\Python314\\DLLs\\libffi-8.dll', 'BINARY'),
|
||||||
|
('python3.dll', 'C:\\Python314\\python3.dll', 'BINARY'),
|
||||||
|
('ucrtbase.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\ucrtbase.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-profile-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-profile-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processthreads-l1-1-1.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-memory-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-memory-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l2-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l2-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processthreads-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-debug-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-debug-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l1-2-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-string-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-string-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-timezone-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-timezone-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-localization-l1-2-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-localization-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-datetime-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-datetime-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-util-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-util-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-console-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-console-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-synch-l1-2-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-synch-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-interlocked-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-interlocked-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-handle-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-handle-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-fibers-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-fibers-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-heap-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-heap-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-synch-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-synch-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('grpc\\_cython\\_credentials\\roots.pem',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_credentials\\roots.pem',
|
||||||
|
'DATA'),
|
||||||
|
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||||
|
'DATA'),
|
||||||
|
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\INSTALLER',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\INSTALLER',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\REQUESTED',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\REQUESTED',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\RECORD',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\RECORD',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\WHEEL',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\WHEEL',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\entry_points.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\entry_points.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\LICENSE.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\LICENSE.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\METADATA',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\METADATA',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\DELVEWHEEL',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\DELVEWHEEL',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('base_library.zip',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\base_library.zip',
|
||||||
|
'DATA')],
|
||||||
|
[],
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
1779678963,
|
||||||
|
[('run.exe',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
||||||
|
'EXECUTABLE')],
|
||||||
|
'C:\\Python314\\python314.dll')
|
||||||
337
devkit/build/je-skin-devkit-server/PKG-00.toc
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
('d:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\je-skin-devkit-server.pkg',
|
||||||
|
{'BINARY': True,
|
||||||
|
'DATA': True,
|
||||||
|
'EXECUTABLE': True,
|
||||||
|
'EXTENSION': True,
|
||||||
|
'PYMODULE': True,
|
||||||
|
'PYSOURCE': True,
|
||||||
|
'PYZ': False,
|
||||||
|
'SPLASH': True,
|
||||||
|
'SYMLINK': False},
|
||||||
|
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||||
|
('PYZ-00.pyz',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\PYZ-00.pyz',
|
||||||
|
'PYZ'),
|
||||||
|
('struct',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\struct.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod01_archive',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod01_archive.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod02_importers',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod02_importers.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod03_ctypes',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod03_ctypes.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyimod04_pywin32',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\localpycs\\pyimod04_pywin32.pyc',
|
||||||
|
'PYMODULE'),
|
||||||
|
('pyiboot01_bootstrap',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_inspect',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_pkgutil',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('pyi_rth_multiprocessing',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||||
|
'PYSOURCE'),
|
||||||
|
('sensor_server', 'D:\\JE-Skin-main\\devkit\\sensor_server.py', 'PYSOURCE'),
|
||||||
|
('python314.dll', 'C:\\Python314\\python314.dll', 'BINARY'),
|
||||||
|
('numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy.libs\\msvcp140-a4c2229bdc2a2a630acdc095b4d86008.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy.libs\\libscipy_openblas64_-63c857e738469261263c764a36be9436.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('select.pyd', 'C:\\Python314\\DLLs\\select.pyd', 'EXTENSION'),
|
||||||
|
('_multiprocessing.pyd',
|
||||||
|
'C:\\Python314\\DLLs\\_multiprocessing.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_zstd.pyd', 'C:\\Python314\\DLLs\\_zstd.pyd', 'EXTENSION'),
|
||||||
|
('pyexpat.pyd', 'C:\\Python314\\DLLs\\pyexpat.pyd', 'EXTENSION'),
|
||||||
|
('_lzma.pyd', 'C:\\Python314\\DLLs\\_lzma.pyd', 'EXTENSION'),
|
||||||
|
('_bz2.pyd', 'C:\\Python314\\DLLs\\_bz2.pyd', 'EXTENSION'),
|
||||||
|
('_ssl.pyd', 'C:\\Python314\\DLLs\\_ssl.pyd', 'EXTENSION'),
|
||||||
|
('_hashlib.pyd', 'C:\\Python314\\DLLs\\_hashlib.pyd', 'EXTENSION'),
|
||||||
|
('unicodedata.pyd', 'C:\\Python314\\DLLs\\unicodedata.pyd', 'EXTENSION'),
|
||||||
|
('_decimal.pyd', 'C:\\Python314\\DLLs\\_decimal.pyd', 'EXTENSION'),
|
||||||
|
('_socket.pyd', 'C:\\Python314\\DLLs\\_socket.pyd', 'EXTENSION'),
|
||||||
|
('_ctypes.pyd', 'C:\\Python314\\DLLs\\_ctypes.pyd', 'EXTENSION'),
|
||||||
|
('_queue.pyd', 'C:\\Python314\\DLLs\\_queue.pyd', 'EXTENSION'),
|
||||||
|
('numpy\\_core\\_multiarray_tests.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\_core\\_multiarray_tests.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\_core\\_multiarray_umath.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\_core\\_multiarray_umath.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_wmi.pyd', 'C:\\Python314\\DLLs\\_wmi.pyd', 'EXTENSION'),
|
||||||
|
('_overlapped.pyd', 'C:\\Python314\\DLLs\\_overlapped.pyd', 'EXTENSION'),
|
||||||
|
('_asyncio.pyd', 'C:\\Python314\\DLLs\\_asyncio.pyd', 'EXTENSION'),
|
||||||
|
('numpy\\linalg\\_umath_linalg.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\linalg\\_umath_linalg.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\mtrand.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\mtrand.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\bit_generator.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\bit_generator.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_sfc64.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_sfc64.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_philox.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_philox.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_pcg64.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_pcg64.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_mt19937.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_mt19937.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_generator.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_generator.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_common.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_common.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\random\\_bounded_integers.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\random\\_bounded_integers.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('numpy\\fft\\_pocketfft_umath.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy\\fft\\_pocketfft_umath.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('_elementtree.pyd', 'C:\\Python314\\DLLs\\_elementtree.pyd', 'EXTENSION'),
|
||||||
|
('grpc\\_cython\\cygrpc.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\cygrpc.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('google\\_upb\\_message.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\google\\_upb\\_message.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('grpc_tools\\_protoc_compiler.cp314-win_amd64.pyd',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc_tools\\_protoc_compiler.cp314-win_amd64.pyd',
|
||||||
|
'EXTENSION'),
|
||||||
|
('api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-filesystem-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-locale-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-locale-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-time-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-time-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-environment-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-environment-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-runtime-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-runtime-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-convert-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-convert-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-heap-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-heap-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-string-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-string-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-process-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-process-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-math-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-math-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-stdio-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-stdio-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-conio-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-conio-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('VCRUNTIME140.dll', 'C:\\Python314\\VCRUNTIME140.dll', 'BINARY'),
|
||||||
|
('VCRUNTIME140_1.dll', 'C:\\Python314\\VCRUNTIME140_1.dll', 'BINARY'),
|
||||||
|
('api-ms-win-crt-utility-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-utility-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-crt-private-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-crt-private-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('libcrypto-3.dll', 'C:\\Python314\\DLLs\\libcrypto-3.dll', 'BINARY'),
|
||||||
|
('libssl-3.dll', 'C:\\Python314\\DLLs\\libssl-3.dll', 'BINARY'),
|
||||||
|
('libffi-8.dll', 'C:\\Python314\\DLLs\\libffi-8.dll', 'BINARY'),
|
||||||
|
('python3.dll', 'C:\\Python314\\python3.dll', 'BINARY'),
|
||||||
|
('ucrtbase.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\ucrtbase.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-profile-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-profile-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processthreads-l1-1-1.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-1.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-errorhandling-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-memory-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-memory-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l2-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l2-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processthreads-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processthreads-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-debug-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-debug-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l1-2-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-string-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-string-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-namedpipe-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-timezone-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-timezone-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-rtlsupport-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-localization-l1-2-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-localization-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-datetime-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-datetime-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-util-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-util-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-console-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-console-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-synch-l1-2-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-synch-l1-2-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-interlocked-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-interlocked-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-handle-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-handle-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-libraryloader-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-fibers-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-fibers-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-heap-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-heap-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-file-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-file-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-sysinfo-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-processenvironment-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('api-ms-win-core-synch-l1-1-0.dll',
|
||||||
|
'C:\\Users\\Administrator\\miniconda3\\api-ms-win-core-synch-l1-1-0.dll',
|
||||||
|
'BINARY'),
|
||||||
|
('grpc\\_cython\\_credentials\\roots.pem',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_credentials\\roots.pem',
|
||||||
|
'DATA'),
|
||||||
|
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.h',
|
||||||
|
'DATA'),
|
||||||
|
('grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\grpc\\_cython\\_cygrpc\\private_key_signing\\private_key_signer_py_wrapper.cc',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\common\\pythoncapi-compat\\COPYING',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\INSTALLER',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\INSTALLER',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\REQUESTED',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\REQUESTED',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\fft\\pocketfft\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\splitmix64\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\linalg\\lapack_lite\\LICENSE.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\include\\numpy\\libdivide\\LICENSE.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\RECORD',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\RECORD',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\WHEEL',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\WHEEL',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\sfc64\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\philox\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\pcg64\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\ma\\LICENSE',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\umath\\svml\\LICENSE',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\entry_points.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\entry_points.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\mt19937\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\LICENSE.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\LICENSE.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\multiarray\\dragon4_LICENSE.txt',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\METADATA',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\METADATA',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\DELVEWHEEL',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\DELVEWHEEL',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\highway\\LICENSE',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\random\\src\\distributions\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||||
|
'C:\\Python314\\Lib\\site-packages\\numpy-2.4.4.dist-info\\licenses\\numpy\\_core\\src\\npysort\\x86-simd-sort\\LICENSE.md',
|
||||||
|
'DATA'),
|
||||||
|
('base_library.zip',
|
||||||
|
'd:\\JE-Skin-main\\devkit\\build\\je-skin-devkit-server\\base_library.zip',
|
||||||
|
'DATA')],
|
||||||
|
'python314.dll',
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
[],
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None)
|
||||||
BIN
devkit/build/je-skin-devkit-server/PYZ-00.pyz
Normal file
1595
devkit/build/je-skin-devkit-server/PYZ-00.toc
Normal file
BIN
devkit/build/je-skin-devkit-server/base_library.zip
Normal file
BIN
devkit/build/je-skin-devkit-server/je-skin-devkit-server.pkg
Normal file
BIN
devkit/build/je-skin-devkit-server/localpycs/pyimod03_ctypes.pyc
Normal file
BIN
devkit/build/je-skin-devkit-server/localpycs/struct.pyc
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
|
||||||
|
This file lists modules PyInstaller was not able to find. This does not
|
||||||
|
necessarily mean these modules are required for running your program. Both
|
||||||
|
Python's standard library and 3rd-party Python packages often conditionally
|
||||||
|
import optional modules, some of which may be available only on certain
|
||||||
|
platforms.
|
||||||
|
|
||||||
|
Types of import:
|
||||||
|
* top-level: imported at the top-level - look at these first
|
||||||
|
* conditional: imported within an if-statement
|
||||||
|
* delayed: imported within a function
|
||||||
|
* optional: imported within a try-except-statement
|
||||||
|
|
||||||
|
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||||
|
tracking down the missing module yourself. Thanks!
|
||||||
|
|
||||||
|
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib (optional), netrc (delayed, optional), subprocess (delayed, conditional, optional), http.server (delayed, optional)
|
||||||
|
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib (optional), subprocess (delayed, conditional, optional)
|
||||||
|
missing module named 'collections.abc' - imported by _colorize (top-level), typing (top-level), traceback (top-level), logging (top-level), selectors (top-level), http.client (top-level), importlib.resources.readers (top-level), inspect (top-level), tracemalloc (top-level), multiprocessing.managers (top-level), typing_extensions (top-level), asyncio.base_events (top-level), asyncio.coroutines (top-level), grpc.aio._metadata (top-level), google.protobuf.internal.containers (top-level), google.protobuf.internal.well_known_types (top-level), numpy._typing._array_like (top-level), numpy._typing._nested_sequence (conditional), numpy._typing._shape (top-level), numpy._typing._dtype_like (top-level), numpy.lib._function_base_impl (top-level), _pyrepl.types (top-level), numpy.lib._npyio_impl (top-level), numpy.random._common (top-level), numpy.random._generator (top-level), numpy.random.bit_generator (top-level), numpy.random.mtrand (top-level), numpy.polynomial._polybase (top-level), xml.etree.ElementTree (top-level)
|
||||||
|
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||||
|
missing module named fcntl - imported by pathlib._os (optional), subprocess (optional)
|
||||||
|
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||||
|
missing module named _scproxy - imported by urllib.request (conditional)
|
||||||
|
missing module named posix - imported by posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), pathlib._os (optional), os (conditional, optional), _pyrepl.trace (conditional)
|
||||||
|
missing module named resource - imported by posix (top-level)
|
||||||
|
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||||
|
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||||
|
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||||
|
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.forkserver (top-level), multiprocessing.connection (top-level)
|
||||||
|
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||||
|
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||||
|
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||||
|
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||||
|
missing module named pyimod02_importers - imported by C:\Python314\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||||
|
missing module named _dummy_thread - imported by numpy._core.arrayprint (optional)
|
||||||
|
missing module named 'numpy_distutils.cpuinfo' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||||
|
missing module named 'numpy_distutils.fcompiler' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||||
|
missing module named 'numpy_distutils.command' - imported by numpy.f2py.diagnose (delayed, conditional, optional)
|
||||||
|
missing module named numpy_distutils - imported by numpy.f2py.diagnose (delayed, optional)
|
||||||
|
missing module named charset_normalizer - imported by numpy.f2py.crackfortran (optional)
|
||||||
|
missing module named vms_lib - imported by platform (delayed, optional)
|
||||||
|
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||||
|
missing module named java - imported by platform (delayed)
|
||||||
|
missing module named psutil - imported by numpy.testing._private.utils (delayed, optional)
|
||||||
|
missing module named termios - imported by tty (top-level), _pyrepl.pager (delayed, optional)
|
||||||
|
missing module named readline - imported by cmd (delayed, conditional, optional), code (delayed, conditional, optional), pdb (delayed, conditional, optional), rlcompleter (optional)
|
||||||
|
missing module named win32pdh - imported by numpy.testing._private.utils (delayed, conditional)
|
||||||
|
missing module named _typeshed - imported by numpy.random.bit_generator (top-level)
|
||||||
|
missing module named numpy.random.RandomState - imported by numpy.random (top-level), numpy.random._generator (top-level)
|
||||||
|
missing module named pyodide_js - imported by threadpoolctl (delayed, optional)
|
||||||
|
missing module named numpy._core.zeros - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.vstack - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.void - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.vecmat - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.vecdot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.ushort - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.unsignedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.ulonglong - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.ulong - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.uintp - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.uintc - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.uint64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.uint32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.uint16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.uint - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.ubyte - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.trunc - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.true_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._function_base_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.trace - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.timedelta64 - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.tensordot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.tanh - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.tan - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.swapaxes - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.sum - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.subtract - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.str_ - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.square - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.sqrt - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||||
|
missing module named numpy._core.spacing - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.sort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.sinh - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.single - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.signedinteger - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.signbit - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||||
|
missing module named numpy._core.sign - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.short - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.rint - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.right_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.result_type - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||||
|
missing module named numpy._core.remainder - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.reciprocal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||||
|
missing module named numpy._core.radians - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.rad2deg - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.prod - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.power - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.positive - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.pi - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.outer - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.ones - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.object_ - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||||
|
missing module named numpy._core.number - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||||
|
missing module named numpy._core.not_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.nextafter - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.newaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.negative - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.ndarray - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy.lib._utils_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.multiply - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.moveaxis - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.modf - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.mod - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.minimum - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.maximum - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.max - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||||
|
missing module named numpy._core.matvec - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.matrix_transpose - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.matmul - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.longlong - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.longdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.long - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.logical_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.logical_or - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.logical_not - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.logical_and - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.logaddexp2 - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.logaddexp - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.log10 - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.log2 - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.log1p - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.log - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.linspace - imported by numpy._core (top-level), numpy.lib._index_tricks_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.less_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.less - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.left_shift - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.ldexp - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.lcm - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.isscalar - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.isnat - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.isnan - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||||
|
missing module named numpy._core.isfinite - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.intp - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.integer - imported by numpy._core (conditional), numpy (conditional), numpy.fft._helper (top-level)
|
||||||
|
missing module named numpy._core.intc - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.int64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.int32 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.int16 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.int8 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.inf - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||||
|
missing module named numpy._core.inexact - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.iinfo - imported by numpy._core (top-level), numpy.lib._twodim_base_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.hypot - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.hstack - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.heaviside - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.half - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.greater_equal - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.greater - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.gcd - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.frompyfunc - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.frexp - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.fmod - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.fmin - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.fmax - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.floor_divide - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.floor - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.floating - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.float_power - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.float32 - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.float16 - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.finfo - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.fabs - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.expm1 - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.exp2 - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.exp - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.euler_gamma - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.errstate - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||||
|
missing module named numpy._core.equal - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.empty_like - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||||
|
missing module named numpy._core.empty - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||||
|
missing module named numpy._core.e - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.double - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.dot - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.divmod - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.divide - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.diagonal - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.degrees - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.deg2rad - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.datetime64 - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.csingle - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.cross - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.count_nonzero - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.cosh - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.cos - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.copysign - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.conjugate - imported by numpy._core (conditional), numpy (conditional), numpy.fft._pocketfft (top-level)
|
||||||
|
missing module named numpy._core.conj - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.complexfloating - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.complex64 - imported by numpy._core (conditional), numpy (conditional), numpy._array_api_info (top-level)
|
||||||
|
missing module named numpy._core.clongdouble - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.character - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.ceil - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.cdouble - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.cbrt - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.bytes_ - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.byte - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.bool_ - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.bitwise_xor - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.bitwise_or - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.bitwise_count - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.bitwise_and - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.atleast_3d - imported by numpy._core (top-level), numpy.lib._shape_base_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.atleast_2d - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.atleast_1d - imported by numpy._core (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.asarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.lib._array_utils_impl (top-level), numpy (conditional), numpy.fft._helper (top-level), numpy.fft._pocketfft (top-level)
|
||||||
|
missing module named numpy._core.asanyarray - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.array_repr - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.array2string - imported by numpy._core (delayed), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||||
|
missing module named numpy._core.array - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (top-level), numpy.lib._polynomial_impl (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.argsort - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.arctanh - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.arctan2 - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.arctan - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.arcsinh - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.arcsin - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.arccosh - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.arccos - imported by numpy._core (conditional), numpy (conditional)
|
||||||
|
missing module named numpy._core.arange - imported by numpy._core (top-level), numpy.testing._private.utils (top-level), numpy (conditional), numpy.fft._helper (top-level)
|
||||||
|
missing module named numpy._core.amin - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.amax - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named numpy._core.all - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy.testing._private.utils (delayed), numpy (conditional)
|
||||||
|
missing module named numpy._core.add - imported by numpy._core (top-level), numpy.linalg._linalg (top-level), numpy (conditional)
|
||||||
|
missing module named yaml - imported by numpy.__config__ (delayed)
|
||||||
|
missing module named numpy._distributor_init_local - imported by numpy (optional), numpy._distributor_init (optional)
|
||||||
|
missing module named defusedxml - imported by openpyxl.xml (delayed, optional)
|
||||||
|
missing module named lxml - imported by openpyxl.xml (delayed, optional)
|
||||||
|
missing module named 'defusedxml.ElementTree' - imported by openpyxl.xml.functions (conditional)
|
||||||
|
missing module named 'lxml.etree' - imported by openpyxl.xml.functions (conditional)
|
||||||
|
missing module named PIL - imported by openpyxl.drawing.image (optional)
|
||||||
|
missing module named openpyxl.tests - imported by openpyxl.reader.excel (optional)
|
||||||
|
missing module named google.protobuf.pyext._message - imported by google.protobuf.pyext (conditional, optional), google.protobuf.internal.api_implementation (conditional, optional), google.protobuf.descriptor (conditional), google.protobuf.pyext.cpp_message (conditional)
|
||||||
|
missing module named google.protobuf.enable_deterministic_proto_serialization - imported by google.protobuf (optional), google.protobuf.internal.api_implementation (optional)
|
||||||
|
missing module named google.protobuf.internal._api_implementation - imported by google.protobuf.internal (optional), google.protobuf.internal.api_implementation (optional)
|
||||||
|
missing module named grpc_reflection - imported by grpc (optional)
|
||||||
|
missing module named grpc_health - imported by grpc (optional)
|
||||||
|
missing module named pkg_resources - imported by grpc_tools.protoc (conditional)
|
||||||
26741
devkit/build/je-skin-devkit-server/xref-je-skin-devkit-server.html
Normal file
BIN
devkit/je-skin-devkit-server.exe
Normal file
@@ -5,8 +5,8 @@ a = Analysis(
|
|||||||
['sensor_server.py'],
|
['sensor_server.py'],
|
||||||
pathex=[],
|
pathex=[],
|
||||||
binaries=[],
|
binaries=[],
|
||||||
datas=[('sensor_stream_pb2.py', '.'), ('sensor_stream_pb2_grpc.py', '.')],
|
datas=[],
|
||||||
hiddenimports=['grpc', 'openpyxl', 'numpy'],
|
hiddenimports=[],
|
||||||
hookspath=[],
|
hookspath=[],
|
||||||
hooksconfig={},
|
hooksconfig={},
|
||||||
runtime_hooks=[],
|
runtime_hooks=[],
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import sys
|
|||||||
import time
|
import time
|
||||||
from concurrent import futures
|
from concurrent import futures
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
import sensor_stream_pb2
|
import sensor_stream_pb2
|
||||||
import sensor_stream_pb2_grpc
|
import sensor_stream_pb2_grpc
|
||||||
@@ -231,30 +230,56 @@ def _append_analysis_log(source_csv: str, stats: dict):
|
|||||||
class SensorPushServicer(sensor_stream_pb2_grpc.SensorPushServicer):
|
class SensorPushServicer(sensor_stream_pb2_grpc.SensorPushServicer):
|
||||||
"""接收实时传感器帧(streaming)"""
|
"""接收实时传感器帧(streaming)"""
|
||||||
|
|
||||||
|
_csv_path = None # 类变量,记录当前 CSV 路径
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.frame_count = 0
|
self.frame_count = 0
|
||||||
self.last_report_time = time.time()
|
self.last_report_time = time.time()
|
||||||
self.last_angle = None
|
self.last_angle = None
|
||||||
|
self._csv_file = None
|
||||||
|
self._csv_writer = None
|
||||||
|
|
||||||
|
def _open_csv(self):
|
||||||
|
"""打开一个新的 CSV 文件用于持续写入"""
|
||||||
|
ts = time.strftime("%Y%m%d_%H%M%S")
|
||||||
|
SensorPushServicer._csv_path = os.path.join(os.getcwd(), f"sensor_log_{ts}.csv")
|
||||||
|
self._csv_file = open(SensorPushServicer._csv_path, "w", newline="", encoding="utf-8-sig")
|
||||||
|
self._csv_writer = csv.writer(self._csv_file)
|
||||||
|
header = ["seq", "timestamp_ms", "dts_ms", "angle", "magnitude", "state", "cop_x", "cop_y", "base_x", "base_y", "resultant_force"] + [f"ch{i}" for i in range(SENSOR_ROWS * SENSOR_COLS)]
|
||||||
|
self._csv_writer.writerow(header)
|
||||||
|
self._csv_file.flush()
|
||||||
|
print(f"[SensorPush] CSV logging to: {SensorPushServicer._csv_path}")
|
||||||
|
|
||||||
|
def _close_csv(self):
|
||||||
|
"""关闭 CSV 文件"""
|
||||||
|
if self._csv_file:
|
||||||
|
self._csv_file.close()
|
||||||
|
print(f"[SensorPush] CSV saved: {SensorPushServicer._csv_path}")
|
||||||
|
self._csv_file = None
|
||||||
|
self._csv_writer = None
|
||||||
|
|
||||||
def Upload(self, request_iterator, context):
|
def Upload(self, request_iterator, context):
|
||||||
print("[SensorPush] Client connected, waiting for frames...")
|
print("[SensorPush] Client connected, waiting for frames...")
|
||||||
reset_baseline()
|
reset_baseline()
|
||||||
self.last_angle = None
|
self.last_angle = None
|
||||||
|
self.frame_count = 0
|
||||||
|
self._open_csv()
|
||||||
|
|
||||||
for frame in request_iterator:
|
for frame in request_iterator:
|
||||||
self.frame_count += 1
|
self.frame_count += 1
|
||||||
angle = 0.0
|
angle = 0.0
|
||||||
|
magnitude = 0.0
|
||||||
|
state = 0
|
||||||
ok = True
|
ok = True
|
||||||
message = "OK"
|
message = "OK"
|
||||||
|
cop_x = cop_y = base_x = base_y = 0.0
|
||||||
|
total_press = 0.0
|
||||||
|
threshold = 0.0
|
||||||
if len(frame.matrix) == SENSOR_ROWS * SENSOR_COLS:
|
if len(frame.matrix) == SENSOR_ROWS * SENSOR_COLS:
|
||||||
try:
|
try:
|
||||||
angle = get_pzt_angle(frame.matrix)
|
angle, magnitude, state, cop_x, cop_y, base_x, base_y, total_press, threshold = get_pzt_angle(frame.matrix)
|
||||||
self.last_angle = angle
|
self.last_angle = angle
|
||||||
if self.frame_count <= 10 or self.frame_count % 30 == 0:
|
print(f"devkit: angle={angle:.2f}, magnitude={magnitude:.4f}, state={state}, cop_x={cop_x:.4f}, cop_y={cop_y:.4f}, base_x={base_x:.4f}, base_y={base_y:.4f}, total_press={total_press:.2f}, thresh={threshold:.2f}")
|
||||||
print(
|
|
||||||
f"[SensorPush] PZT angle frame #{frame.seq} "
|
|
||||||
f"dts={frame.dts_ms} angle={angle:.2f}"
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
ok = False
|
ok = False
|
||||||
message = str(e)
|
message = str(e)
|
||||||
@@ -262,6 +287,18 @@ class SensorPushServicer(sensor_stream_pb2_grpc.SensorPushServicer):
|
|||||||
else:
|
else:
|
||||||
ok = False
|
ok = False
|
||||||
message = f"Invalid matrix length: {len(frame.matrix)}"
|
message = f"Invalid matrix length: {len(frame.matrix)}"
|
||||||
|
print(f"[Recv #{frame.seq}] INVALID len={len(frame.matrix)}")
|
||||||
|
|
||||||
|
# 持续写入 CSV
|
||||||
|
if self._csv_writer:
|
||||||
|
row = [frame.seq, frame.timestamp_ms, frame.dts_ms,
|
||||||
|
f"{angle:.4f}", f"{magnitude:.4f}", state,
|
||||||
|
f"{cop_x:.4f}", f"{cop_y:.4f}", f"{base_x:.4f}", f"{base_y:.4f}",
|
||||||
|
frame.resultant_force]
|
||||||
|
row += list(frame.matrix)
|
||||||
|
self._csv_writer.writerow(row)
|
||||||
|
if self.frame_count % 10 == 0:
|
||||||
|
self._csv_file.flush()
|
||||||
|
|
||||||
yield sensor_stream_pb2.PztAngleResponse(
|
yield sensor_stream_pb2.PztAngleResponse(
|
||||||
seq=frame.seq,
|
seq=frame.seq,
|
||||||
@@ -270,6 +307,14 @@ class SensorPushServicer(sensor_stream_pb2_grpc.SensorPushServicer):
|
|||||||
dts_ms=frame.dts_ms,
|
dts_ms=frame.dts_ms,
|
||||||
ok=ok,
|
ok=ok,
|
||||||
message=message,
|
message=message,
|
||||||
|
magnitude=magnitude,
|
||||||
|
state=state,
|
||||||
|
cop_x=cop_x,
|
||||||
|
cop_y=cop_y,
|
||||||
|
base_x=base_x,
|
||||||
|
base_y=base_y,
|
||||||
|
total_press=total_press,
|
||||||
|
threshold=threshold,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.frame_count % 100 == 0:
|
if self.frame_count % 100 == 0:
|
||||||
@@ -290,6 +335,7 @@ class SensorPushServicer(sensor_stream_pb2_grpc.SensorPushServicer):
|
|||||||
f"total={self.frame_count} | ~{fps:.1f} fps"
|
f"total={self.frame_count} | ~{fps:.1f} fps"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._close_csv()
|
||||||
print(f"[SensorPush] Stream ended. Total: {self.frame_count}")
|
print(f"[SensorPush] Stream ended. Total: {self.frame_count}")
|
||||||
|
|
||||||
|
|
||||||
@@ -350,67 +396,84 @@ def serve(port: int):
|
|||||||
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import threading
|
from collections import deque
|
||||||
|
|
||||||
# ===================== 算法参数=====================
|
# ===================== 算法参数=====================
|
||||||
TOTAL_PRESSURE_LOW_THRESHOLD = 500
|
COP_INIT_MEDIAN_FRAMES = 1 # 初始COP取中位数的帧数
|
||||||
COP_STABILITY_FRAMES_REQUIRED = 5
|
NOISE_COLLECT_FRAMES = 10 # 动态阈值基线采集帧数
|
||||||
SENSOR_ROWS = 12
|
THRESH_K = 5 # 阈值 = K * mean
|
||||||
SENSOR_COLS = 7
|
SENSOR_ROWS = 12
|
||||||
|
SENSOR_COLS = 7
|
||||||
|
|
||||||
|
# ===================== 二次静置精修参数 =====================
|
||||||
|
POST_INIT_WINDOW_CNT = 60000
|
||||||
|
POST_INIT_STABLE_CNT = 100
|
||||||
|
POST_INIT_STABLE_THRESH = 0.1
|
||||||
|
|
||||||
# ===================== 线程安全全局状态 =====================
|
# ===================== 线程安全全局状态 =====================
|
||||||
first_frame = None
|
first_contact_CoP_x = None
|
||||||
first_frame_lock = threading.Lock()
|
first_contact_CoP_y = None
|
||||||
|
contact_initialized = False
|
||||||
|
|
||||||
first_contact_CoP_x = None
|
# 候选初始CoP缓冲
|
||||||
first_contact_CoP_y = None
|
cop_init_x_buf = deque(maxlen=COP_INIT_MEDIAN_FRAMES)
|
||||||
contact_initialized = False
|
cop_init_y_buf = deque(maxlen=COP_INIT_MEDIAN_FRAMES)
|
||||||
|
|
||||||
total_pressure_low_counter = 0
|
# 动态阈值
|
||||||
|
noise_sum_buf = deque(maxlen=NOISE_COLLECT_FRAMES)
|
||||||
|
dynamic_thresh = None
|
||||||
|
|
||||||
|
# 二次静置精修状态
|
||||||
|
post_init_frame_cnt = 0
|
||||||
|
post_stable_cnt = 0
|
||||||
|
post_refined_flag = False
|
||||||
|
post_cand_x = None
|
||||||
|
post_cand_y = None
|
||||||
|
|
||||||
# ===================== 基线减除 =====================
|
|
||||||
def subtract_baseline(current_frame):
|
|
||||||
global first_frame
|
|
||||||
current_frame = np.array(current_frame, dtype=np.float32).flatten()
|
|
||||||
|
|
||||||
with first_frame_lock:
|
|
||||||
if first_frame is None:
|
|
||||||
first_frame = current_frame.copy()
|
|
||||||
|
|
||||||
diff = current_frame - first_frame
|
|
||||||
return np.clip(diff, 0, None)
|
|
||||||
|
|
||||||
# ===================== 重置CoP状态 =====================
|
# ===================== 重置CoP状态 =====================
|
||||||
def reset_cop_state():
|
def reset_cop_state():
|
||||||
global first_contact_CoP_x, first_contact_CoP_y, contact_initialized
|
global first_contact_CoP_x, first_contact_CoP_y, contact_initialized
|
||||||
global total_pressure_low_counter
|
global post_init_frame_cnt, post_stable_cnt, post_refined_flag
|
||||||
|
global post_cand_x, post_cand_y
|
||||||
|
|
||||||
first_contact_CoP_x = None
|
first_contact_CoP_x = None
|
||||||
first_contact_CoP_y = None
|
first_contact_CoP_y = None
|
||||||
contact_initialized = False
|
contact_initialized = False
|
||||||
total_pressure_low_counter = 0
|
cop_init_x_buf.clear()
|
||||||
|
cop_init_y_buf.clear()
|
||||||
|
post_init_frame_cnt = 0
|
||||||
|
post_stable_cnt = 0
|
||||||
|
post_refined_flag = False
|
||||||
|
post_cand_x = None
|
||||||
|
post_cand_y = None
|
||||||
|
|
||||||
|
|
||||||
# ===================== CoP压力中心计算 =====================
|
# ===================== CoP压力中心计算 =====================
|
||||||
def compute_pressure_direction(baseline_subtracted_frame):
|
def compute_pressure_direction(raw_frame):
|
||||||
global first_contact_CoP_x, first_contact_CoP_y, contact_initialized
|
global first_contact_CoP_x, first_contact_CoP_y, contact_initialized
|
||||||
global total_pressure_low_counter
|
global post_init_frame_cnt, post_stable_cnt, post_refined_flag
|
||||||
|
global post_cand_x, post_cand_y
|
||||||
|
global noise_sum_buf, dynamic_thresh
|
||||||
|
|
||||||
rows, cols = SENSOR_ROWS, SENSOR_COLS
|
rows, cols = SENSOR_ROWS, SENSOR_COLS
|
||||||
frame_flat = np.asarray(baseline_subtracted_frame, dtype=np.float32).flatten()
|
frame_flat = np.asarray(raw_frame, dtype=np.float32).flatten()
|
||||||
frame2d = frame_flat.reshape(rows, cols)
|
frame2d = frame_flat.reshape(rows, cols)
|
||||||
|
|
||||||
total_pressure = np.sum(frame2d)
|
total_pressure = np.sum(frame2d)
|
||||||
if total_pressure < TOTAL_PRESSURE_LOW_THRESHOLD:
|
|
||||||
total_pressure_low_counter += 1
|
|
||||||
else:
|
|
||||||
total_pressure_low_counter = 0
|
|
||||||
|
|
||||||
if total_pressure_low_counter >= COP_STABILITY_FRAMES_REQUIRED:
|
# 动态阈值
|
||||||
reset_cop_state()
|
if dynamic_thresh is None:
|
||||||
return 0.0, 0.0
|
noise_sum_buf.append(total_pressure)
|
||||||
|
if len(noise_sum_buf) >= NOISE_COLLECT_FRAMES:
|
||||||
|
sums = np.array(noise_sum_buf)
|
||||||
|
dynamic_thresh = THRESH_K * float(np.mean(sums))
|
||||||
|
|
||||||
if total_pressure == 0:
|
# 低压重置
|
||||||
return 0.0, 0.0
|
if total_pressure == 0 or (dynamic_thresh is not None and total_pressure < dynamic_thresh):
|
||||||
|
if contact_initialized and dynamic_thresh is not None:
|
||||||
|
reset_cop_state()
|
||||||
|
return 0.0, 0.0, 0, rows-1, 0, cols-1, 0.0, 0.0, 0.0, 0.0, 0.0, 0, 0.0, dynamic_thresh
|
||||||
|
|
||||||
x_grid = np.tile(np.arange(cols), (rows, 1))
|
x_grid = np.tile(np.arange(cols), (rows, 1))
|
||||||
y_grid = np.repeat(np.arange(rows), cols).reshape(rows, cols)
|
y_grid = np.repeat(np.arange(rows), cols).reshape(rows, cols)
|
||||||
@@ -419,44 +482,98 @@ def compute_pressure_direction(baseline_subtracted_frame):
|
|||||||
|
|
||||||
delta_CoP_x = 0.0
|
delta_CoP_x = 0.0
|
||||||
delta_CoP_y = 0.0
|
delta_CoP_y = 0.0
|
||||||
|
base_x = cop_x
|
||||||
|
base_y = cop_y
|
||||||
|
|
||||||
|
# ============ 初始点稳定判断(中位数判定) ============
|
||||||
if not contact_initialized:
|
if not contact_initialized:
|
||||||
first_contact_CoP_x = cop_x
|
cop_init_x_buf.append(cop_x)
|
||||||
first_contact_CoP_y = cop_y
|
cop_init_y_buf.append(cop_y)
|
||||||
contact_initialized = True
|
|
||||||
else:
|
if len(cop_init_x_buf) >= COP_INIT_MEDIAN_FRAMES:
|
||||||
delta_CoP_x = cop_x - first_contact_CoP_x
|
first_contact_CoP_x = float(np.median(cop_init_x_buf))
|
||||||
delta_CoP_y = cop_y - first_contact_CoP_y
|
first_contact_CoP_y = float(np.median(cop_init_y_buf))
|
||||||
|
contact_initialized = True
|
||||||
|
cop_init_x_buf.clear()
|
||||||
|
cop_init_y_buf.clear()
|
||||||
|
|
||||||
|
# ========== 计算偏移量 ==========
|
||||||
|
else:
|
||||||
|
# 二次静置精修
|
||||||
|
post_init_frame_cnt += 1
|
||||||
|
if not post_refined_flag and post_init_frame_cnt <= POST_INIT_WINDOW_CNT:
|
||||||
|
if post_cand_x is not None:
|
||||||
|
dist_val = np.hypot(cop_x - post_cand_x, cop_y - post_cand_y)
|
||||||
|
if dist_val <= POST_INIT_STABLE_THRESH:
|
||||||
|
post_stable_cnt += 1
|
||||||
|
else:
|
||||||
|
post_cand_x = cop_x
|
||||||
|
post_cand_y = cop_y
|
||||||
|
post_stable_cnt = 1
|
||||||
|
else:
|
||||||
|
post_cand_x = cop_x
|
||||||
|
post_cand_y = cop_y
|
||||||
|
post_stable_cnt = 1
|
||||||
|
|
||||||
|
if post_stable_cnt >= POST_INIT_STABLE_CNT:
|
||||||
|
first_contact_CoP_x = post_cand_x
|
||||||
|
first_contact_CoP_y = post_cand_y
|
||||||
|
post_refined_flag = True
|
||||||
|
else:
|
||||||
|
post_refined_flag = True
|
||||||
|
|
||||||
|
delta_CoP_x = cop_x - first_contact_CoP_x
|
||||||
|
delta_CoP_y = first_contact_CoP_y - cop_y
|
||||||
|
base_x = first_contact_CoP_x
|
||||||
|
base_y = first_contact_CoP_y
|
||||||
|
|
||||||
|
magnitude = np.hypot(delta_CoP_x, delta_CoP_y)
|
||||||
|
if not contact_initialized:
|
||||||
|
state = 0
|
||||||
|
elif not post_refined_flag:
|
||||||
|
state = 1
|
||||||
|
else:
|
||||||
|
state = 2
|
||||||
|
|
||||||
|
return (cop_x, cop_y,
|
||||||
|
0, rows-1, 0, cols-1,
|
||||||
|
delta_CoP_x, delta_CoP_y,
|
||||||
|
base_x, base_y,
|
||||||
|
magnitude, state,
|
||||||
|
total_pressure, dynamic_thresh)
|
||||||
|
|
||||||
return delta_CoP_x, delta_CoP_y
|
|
||||||
|
|
||||||
# ===================== 角度计算核心 =====================
|
# ===================== 角度计算核心 =====================
|
||||||
def compute_vector_angle(x: float, y: float) -> tuple[float, float]:
|
def compute_vector_angle(x: float, y: float) -> tuple[float, float]:
|
||||||
epsilon = 1e-8
|
epsilon = 1e-8
|
||||||
mag = np.hypot(x, y)
|
mag = np.hypot(x, y)
|
||||||
angle = np.degrees(np.arctan2(y, x + epsilon))
|
angle = np.degrees(np.arctan2(y, x + epsilon))
|
||||||
if angle < 0:
|
if angle < 0:
|
||||||
angle += 360
|
angle += 360
|
||||||
return angle, mag
|
return angle, mag
|
||||||
|
|
||||||
def compute_PZT_angle(Px: float, Py: float) -> tuple[float, float]:
|
def compute_PZT_angle(Px: float, Py: float) -> tuple[float, float]:
|
||||||
return compute_vector_angle(Px, -Py)
|
return compute_vector_angle(Px, Py)
|
||||||
|
|
||||||
|
|
||||||
# ===================== 核心入口函数 =====================
|
# ===================== 核心入口函数 =====================
|
||||||
def get_pzt_angle(adc_data):
|
def get_pzt_angle(adc_data):
|
||||||
if len(adc_data) != 84:
|
if len(adc_data) != 84:
|
||||||
raise ValueError("ADC数据长度必须为84")
|
raise ValueError("ADC数据长度必须为84")
|
||||||
baseline_subtracted = subtract_baseline(adc_data)
|
result = compute_pressure_direction(adc_data)
|
||||||
dx, dy = compute_pressure_direction(baseline_subtracted)
|
cop_x, cop_y = result[0], result[1]
|
||||||
|
dx, dy = result[6], result[7]
|
||||||
|
base_x, base_y = result[8], result[9]
|
||||||
|
magnitude = result[10]
|
||||||
|
state = int(result[11])
|
||||||
|
total_press = result[12]
|
||||||
|
threshold = result[13]
|
||||||
pzt_angle, _ = compute_PZT_angle(dx, dy)
|
pzt_angle, _ = compute_PZT_angle(dx, dy)
|
||||||
|
return pzt_angle, magnitude, state, cop_x, cop_y, base_x, base_y, total_press, threshold
|
||||||
return pzt_angle
|
|
||||||
|
|
||||||
# ===================== 重置基线(校准用) =====================
|
# ===================== 重置基线(校准用) =====================
|
||||||
def reset_baseline():
|
def reset_baseline():
|
||||||
global first_frame
|
|
||||||
with first_frame_lock:
|
|
||||||
first_frame = None
|
|
||||||
reset_cop_state()
|
reset_cop_state()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13sensor_stream.proto\x12\rsensor_stream\"\x85\x01\n\x0bSensorFrame\x12\x0b\n\x03seq\x18\x01 \x01(\x04\x12\x14\n\x0ctimestamp_ms\x18\x02 \x01(\x04\x12\x0c\n\x04rows\x18\x03 \x01(\r\x12\x0c\n\x04\x63ols\x18\x04 \x01(\r\x12\x0e\n\x06matrix\x18\x05 \x03(\r\x12\x17\n\x0fresultant_force\x18\x06 \x01(\x01\x12\x0e\n\x06\x64ts_ms\x18\x07 \x01(\r\"q\n\x10PztAngleResponse\x12\x0b\n\x03seq\x18\x01 \x01(\x04\x12\x14\n\x0ctimestamp_ms\x18\x02 \x01(\x04\x12\r\n\x05\x61ngle\x18\x03 \x01(\x02\x12\x0e\n\x06\x64ts_ms\x18\x04 \x01(\r\x12\n\n\x02ok\x18\x05 \x01(\x08\x12\x0f\n\x07message\x18\x06 \x01(\t\"8\n\x0eProcessRequest\x12\x10\n\x08\x63sv_path\x18\x01 \x01(\t\x12\x14\n\x0csave_as_xlsx\x18\x02 \x01(\x08\"\xa6\x01\n\x0fProcessResponse\x12\n\n\x02ok\x18\x01 \x01(\x08\x12\x13\n\x0boutput_path\x18\x02 \x01(\t\x12\x13\n\x0bgroups_used\x18\x03 \x01(\r\x12\x12\n\nmean_value\x18\x04 \x01(\x01\x12\x11\n\tthreshold\x18\x05 \x01(\x01\x12\x12\n\nrows_total\x18\x06 \x01(\r\x12\x11\n\trows_kept\x18\x07 \x01(\r\x12\x0f\n\x07message\x18\x08 \x01(\t2W\n\nSensorPush\x12I\n\x06Upload\x12\x1a.sensor_stream.SensorFrame\x1a\x1f.sensor_stream.PztAngleResponse(\x01\x30\x01\x32_\n\x0f\x45xportProcessor\x12L\n\x0bProcessFile\x12\x1d.sensor_stream.ProcessRequest\x1a\x1e.sensor_stream.ProcessResponseb\x06proto3')
|
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13sensor_stream.proto\x12\rsensor_stream\"\x85\x01\n\x0bSensorFrame\x12\x0b\n\x03seq\x18\x01 \x01(\x04\x12\x14\n\x0ctimestamp_ms\x18\x02 \x01(\x04\x12\x0c\n\x04rows\x18\x03 \x01(\r\x12\x0c\n\x04\x63ols\x18\x04 \x01(\r\x12\x0e\n\x06matrix\x18\x05 \x03(\r\x12\x17\n\x0fresultant_force\x18\x06 \x01(\x01\x12\x0e\n\x06\x64ts_ms\x18\x07 \x01(\r\"\xd1\x01\n\x10PztAngleResponse\x12\x0b\n\x03seq\x18\x01 \x01(\x04\x12\x14\n\x0ctimestamp_ms\x18\x02 \x01(\x04\x12\r\n\x05\x61ngle\x18\x03 \x01(\x02\x12\x0e\n\x06\x64ts_ms\x18\x04 \x01(\r\x12\n\n\x02ok\x18\x05 \x01(\x08\x12\x0f\n\x07message\x18\x06 \x01(\t\x12\x11\n\tmagnitude\x18\x07 \x01(\x02\x12\r\n\x05state\x18\x08 \x01(\r\x12\r\n\x05\x63op_x\x18\t \x01(\x02\x12\r\n\x05\x63op_y\x18\n \x01(\x02\x12\x0e\n\x06\x62\x61se_x\x18\x0b \x01(\x02\x12\x0e\n\x06\x62\x61se_y\x18\x0c \x01(\x02\"8\n\x0eProcessRequest\x12\x10\n\x08\x63sv_path\x18\x01 \x01(\t\x12\x14\n\x0csave_as_xlsx\x18\x02 \x01(\x08\"\xa6\x01\n\x0fProcessResponse\x12\n\n\x02ok\x18\x01 \x01(\x08\x12\x13\n\x0boutput_path\x18\x02 \x01(\t\x12\x13\n\x0bgroups_used\x18\x03 \x01(\r\x12\x12\n\nmean_value\x18\x04 \x01(\x01\x12\x11\n\tthreshold\x18\x05 \x01(\x01\x12\x12\n\nrows_total\x18\x06 \x01(\r\x12\x11\n\trows_kept\x18\x07 \x01(\r\x12\x0f\n\x07message\x18\x08 \x01(\t2W\n\nSensorPush\x12I\n\x06Upload\x12\x1a.sensor_stream.SensorFrame\x1a\x1f.sensor_stream.PztAngleResponse(\x01\x30\x01\x32_\n\x0f\x45xportProcessor\x12L\n\x0bProcessFile\x12\x1d.sensor_stream.ProcessRequest\x1a\x1e.sensor_stream.ProcessResponseb\x06proto3')
|
||||||
|
|
||||||
_globals = globals()
|
_globals = globals()
|
||||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||||
@@ -33,14 +33,14 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|||||||
DESCRIPTOR._loaded_options = None
|
DESCRIPTOR._loaded_options = None
|
||||||
_globals['_SENSORFRAME']._serialized_start=39
|
_globals['_SENSORFRAME']._serialized_start=39
|
||||||
_globals['_SENSORFRAME']._serialized_end=172
|
_globals['_SENSORFRAME']._serialized_end=172
|
||||||
_globals['_PZTANGLERESPONSE']._serialized_start=174
|
_globals['_PZTANGLERESPONSE']._serialized_start=175
|
||||||
_globals['_PZTANGLERESPONSE']._serialized_end=287
|
_globals['_PZTANGLERESPONSE']._serialized_end=384
|
||||||
_globals['_PROCESSREQUEST']._serialized_start=289
|
_globals['_PROCESSREQUEST']._serialized_start=386
|
||||||
_globals['_PROCESSREQUEST']._serialized_end=345
|
_globals['_PROCESSREQUEST']._serialized_end=442
|
||||||
_globals['_PROCESSRESPONSE']._serialized_start=348
|
_globals['_PROCESSRESPONSE']._serialized_start=445
|
||||||
_globals['_PROCESSRESPONSE']._serialized_end=514
|
_globals['_PROCESSRESPONSE']._serialized_end=611
|
||||||
_globals['_SENSORPUSH']._serialized_start=516
|
_globals['_SENSORPUSH']._serialized_start=613
|
||||||
_globals['_SENSORPUSH']._serialized_end=603
|
_globals['_SENSORPUSH']._serialized_end=700
|
||||||
_globals['_EXPORTPROCESSOR']._serialized_start=605
|
_globals['_EXPORTPROCESSOR']._serialized_start=702
|
||||||
_globals['_EXPORTPROCESSOR']._serialized_end=700
|
_globals['_EXPORTPROCESSOR']._serialized_end=797
|
||||||
# @@protoc_insertion_point(module_scope)
|
# @@protoc_insertion_point(module_scope)
|
||||||
|
|||||||
127
devkit/test_pzt.py
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
"""
|
||||||
|
独立测试脚本:读取84个原始ADC数据,传入CoP算法计算角度,终端打印结果。
|
||||||
|
|
||||||
|
用法:
|
||||||
|
python test_pzt.py # 从 stdin 逐行读取(每行84个逗号分隔数值)
|
||||||
|
python test_pzt.py data.csv # 从 CSV 文件逐行读取
|
||||||
|
python test_pzt.py --random # 生成随机测试数据(调试用)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import csv
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# ── 从 sensor_server.py 导入算法 ──
|
||||||
|
sys.path.insert(0, ".")
|
||||||
|
from sensor_server import (
|
||||||
|
get_pzt_angle,
|
||||||
|
reset_baseline,
|
||||||
|
subtract_baseline,
|
||||||
|
compute_pressure_direction,
|
||||||
|
compute_PZT_angle,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def print_result(data_label: str, pzt_angle: float, magnitude: float, state: int, cop_x: float, cop_y: float, base_x: float, base_y: float):
|
||||||
|
dx = cop_x - base_x
|
||||||
|
dy = base_y - cop_y
|
||||||
|
print(
|
||||||
|
f"devkit: angle={pzt_angle:.2f}, magnitude={magnitude:.4f}, state={state}, "
|
||||||
|
f"cop_x={cop_x:.4f}, cop_y={cop_y:.4f}, dx={dx:.4f}, dy={dy:.4f}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def process_values(values: list[int | float]):
|
||||||
|
"""处理一帧84个值并打印结果"""
|
||||||
|
if len(values) != 84:
|
||||||
|
print(f"[ERROR] 期望84个值,实际收到 {len(values)} 个", file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
pzt_angle, magnitude, state, cop_x, cop_y, base_x, base_y = get_pzt_angle(values)
|
||||||
|
print_result("", pzt_angle, magnitude, state, cop_x, cop_y, base_x, base_y)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] 计算失败: {e}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def run_random_test():
|
||||||
|
"""生成随机数据测试算法"""
|
||||||
|
reset_baseline()
|
||||||
|
print("[TEST] 使用随机数据测试 CoP 算法")
|
||||||
|
print("[TEST] 先用全零帧建立基线...")
|
||||||
|
process_values([0] * 84)
|
||||||
|
print("[TEST] 模拟右侧偏移按压...")
|
||||||
|
# 模拟:row 5-7, col 4-6 区域有压力
|
||||||
|
data = [0.0] * 84
|
||||||
|
for r in range(5, 8):
|
||||||
|
for c in range(4, 7):
|
||||||
|
idx = r * 7 + c
|
||||||
|
data[idx] = 100.0 + (c - 4) * 50 # 右侧更强
|
||||||
|
process_values(data)
|
||||||
|
print("[TEST] 模拟下方偏移按压...")
|
||||||
|
data2 = [0.0] * 84
|
||||||
|
for r in range(8, 11):
|
||||||
|
for c in range(2, 5):
|
||||||
|
idx = r * 7 + c
|
||||||
|
data2[idx] = 150.0 + (r - 8) * 30
|
||||||
|
process_values(data2)
|
||||||
|
print("[TEST] 完成")
|
||||||
|
|
||||||
|
|
||||||
|
def run_csv_mode(filepath: str):
|
||||||
|
"""从 CSV 文件逐行读取并处理"""
|
||||||
|
reset_baseline()
|
||||||
|
print(f"[CSV] 读取文件: {filepath}")
|
||||||
|
with open(filepath, "r", encoding="utf-8-sig", newline="") as f:
|
||||||
|
reader = csv.reader(f)
|
||||||
|
for i, row in enumerate(reader):
|
||||||
|
if not row:
|
||||||
|
continue
|
||||||
|
# 跳过 header
|
||||||
|
if row[0].strip() in ("seq", "timestamp_ms"):
|
||||||
|
print(f"[CSV] 跳过 header: {row[:5]}...")
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
values = [float(v) for v in row]
|
||||||
|
if len(values) == 84:
|
||||||
|
process_values(values)
|
||||||
|
elif len(values) > 84:
|
||||||
|
process_values(values[:84])
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
def run_stdin_mode():
|
||||||
|
"""从 stdin 逐行读取"""
|
||||||
|
reset_baseline()
|
||||||
|
print("[STDIN] 等待输入(每行84个逗号分隔数值,Ctrl+C 退出)...")
|
||||||
|
try:
|
||||||
|
for line in sys.stdin:
|
||||||
|
line = line.strip()
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
values = [float(v) for v in line.split(",")]
|
||||||
|
if len(values) >= 84:
|
||||||
|
process_values(values[:84])
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n[STDIN] 已退出")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
arg = sys.argv[1]
|
||||||
|
if arg == "--random":
|
||||||
|
run_random_test()
|
||||||
|
elif arg == "--help" or arg == "-h":
|
||||||
|
print(__doc__)
|
||||||
|
else:
|
||||||
|
run_csv_mode(arg)
|
||||||
|
else:
|
||||||
|
run_stdin_mode()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
1
eskin-finger-sdk
Submodule
54
package-lock.json
generated
@@ -625,6 +625,9 @@
|
|||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -639,6 +642,9 @@
|
|||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -653,6 +659,9 @@
|
|||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -667,6 +676,9 @@
|
|||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -681,6 +693,9 @@
|
|||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -695,6 +710,9 @@
|
|||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -709,6 +727,9 @@
|
|||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -723,6 +744,9 @@
|
|||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -737,6 +761,9 @@
|
|||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -751,6 +778,9 @@
|
|||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -765,6 +795,9 @@
|
|||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -779,6 +812,9 @@
|
|||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -793,6 +829,9 @@
|
|||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1091,6 +1130,9 @@
|
|||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "Apache-2.0 OR MIT",
|
"license": "Apache-2.0 OR MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1108,6 +1150,9 @@
|
|||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "Apache-2.0 OR MIT",
|
"license": "Apache-2.0 OR MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1125,6 +1170,9 @@
|
|||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "Apache-2.0 OR MIT",
|
"license": "Apache-2.0 OR MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1142,6 +1190,9 @@
|
|||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "Apache-2.0 OR MIT",
|
"license": "Apache-2.0 OR MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
@@ -1159,6 +1210,9 @@
|
|||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"musl"
|
||||||
|
],
|
||||||
"license": "Apache-2.0 OR MIT",
|
"license": "Apache-2.0 OR MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|||||||
11
src-tauri/.gitignore
vendored
@@ -7,14 +7,3 @@
|
|||||||
# will have schema files for capabilities auto-completion
|
# will have schema files for capabilities auto-completion
|
||||||
/gen/schemas
|
/gen/schemas
|
||||||
*log*
|
*log*
|
||||||
|
|
||||||
# Android build artifacts
|
|
||||||
/gen/android/app/build/
|
|
||||||
/gen/android/build/
|
|
||||||
/gen/android/.gradle/
|
|
||||||
/gen/android/.tauri/
|
|
||||||
/gen/android/local.properties
|
|
||||||
/gen/android/key.properties
|
|
||||||
/gen/android/keystore.properties
|
|
||||||
/gen/android/tauri.settings.gradle
|
|
||||||
/gen/android/app/src/main/jniLibs/
|
|
||||||
|
|||||||
1
src-tauri/Cargo.lock
generated
@@ -17,7 +17,6 @@ dependencies = [
|
|||||||
"fern",
|
"fern",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"humantime",
|
"humantime",
|
||||||
"libc",
|
|
||||||
"log",
|
"log",
|
||||||
"ndarray",
|
"ndarray",
|
||||||
"prost",
|
"prost",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ name = "tauri_demo_lib"
|
|||||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = ["multi-dim"]
|
||||||
devkit = ["dep:tonic", "dep:prost", "dep:prost-types", "dep:async-stream", "dep:dirs"]
|
devkit = ["dep:tonic", "dep:prost", "dep:prost-types", "dep:async-stream", "dep:dirs"]
|
||||||
multi-dim = ["dep:ndarray"]
|
multi-dim = ["dep:ndarray"]
|
||||||
|
|
||||||
@@ -53,8 +53,6 @@ uuid = { version = "1", features = ["v4", "serde"] }
|
|||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
|
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
|
||||||
ndarray = { version = "0.15", optional = true }
|
ndarray = { version = "0.15", optional = true }
|
||||||
[target.'cfg(target_os = "android")'.dependencies]
|
|
||||||
libc = "0.2"
|
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||||
tauri-plugin-updater = "2"
|
tauri-plugin-updater = "2"
|
||||||
|
|||||||
@@ -12,12 +12,6 @@
|
|||||||
"core:window:allow-start-dragging",
|
"core:window:allow-start-dragging",
|
||||||
"opener:default",
|
"opener:default",
|
||||||
"process:default",
|
"process:default",
|
||||||
"allow-usb-serial-list",
|
"updater:default"
|
||||||
"allow-usb-serial-open",
|
|
||||||
"allow-usb-serial-close",
|
|
||||||
"allow-usb-serial-list-camel",
|
|
||||||
"allow-usb-serial-open-camel",
|
|
||||||
"allow-usb-serial-close-camel",
|
|
||||||
"allow-local-commands"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
# EditorConfig is awesome: https://EditorConfig.org
|
|
||||||
|
|
||||||
# top-most EditorConfig file
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = false
|
|
||||||
insert_final_newline = false
|
|
||||||
20
src-tauri/gen/android/.gitignore
vendored
@@ -1,20 +0,0 @@
|
|||||||
*.iml
|
|
||||||
.gradle
|
|
||||||
/local.properties
|
|
||||||
/.idea/caches
|
|
||||||
/.idea/libraries
|
|
||||||
/.idea/modules.xml
|
|
||||||
/.idea/workspace.xml
|
|
||||||
/.idea/navEditor.xml
|
|
||||||
/.idea/assetWizardSettings.xml
|
|
||||||
.DS_Store
|
|
||||||
build
|
|
||||||
/captures
|
|
||||||
.externalNativeBuild
|
|
||||||
.cxx
|
|
||||||
local.properties
|
|
||||||
key.properties
|
|
||||||
keystore.properties
|
|
||||||
|
|
||||||
/.tauri
|
|
||||||
/tauri.settings.gradle
|
|
||||||
6
src-tauri/gen/android/app/.gitignore
vendored
@@ -1,6 +0,0 @@
|
|||||||
/src/main/**/generated
|
|
||||||
/src/main/jniLibs/**/*.so
|
|
||||||
/src/main/assets/tauri.conf.json
|
|
||||||
/tauri.build.gradle.kts
|
|
||||||
/proguard-tauri.pro
|
|
||||||
/tauri.properties
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
import java.util.Properties
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id("com.android.application")
|
|
||||||
id("org.jetbrains.kotlin.android")
|
|
||||||
id("rust")
|
|
||||||
}
|
|
||||||
|
|
||||||
val tauriProperties = Properties().apply {
|
|
||||||
val propFile = file("tauri.properties")
|
|
||||||
if (propFile.exists()) {
|
|
||||||
propFile.inputStream().use { load(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdk = 36
|
|
||||||
namespace = "com.lenn.tauri_serial"
|
|
||||||
defaultConfig {
|
|
||||||
manifestPlaceholders["usesCleartextTraffic"] = "false"
|
|
||||||
applicationId = "com.lenn.tauri_serial"
|
|
||||||
minSdk = 24
|
|
||||||
targetSdk = 36
|
|
||||||
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
|
|
||||||
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
|
|
||||||
}
|
|
||||||
buildTypes {
|
|
||||||
getByName("debug") {
|
|
||||||
manifestPlaceholders["usesCleartextTraffic"] = "true"
|
|
||||||
isDebuggable = true
|
|
||||||
isJniDebuggable = true
|
|
||||||
isMinifyEnabled = false
|
|
||||||
packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
|
|
||||||
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
|
|
||||||
jniLibs.keepDebugSymbols.add("*/x86/*.so")
|
|
||||||
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getByName("release") {
|
|
||||||
isMinifyEnabled = true
|
|
||||||
proguardFiles(
|
|
||||||
*fileTree(".") { include("**/*.pro") }
|
|
||||||
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
|
|
||||||
.toList().toTypedArray()
|
|
||||||
)
|
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = "1.8"
|
|
||||||
}
|
|
||||||
buildFeatures {
|
|
||||||
buildConfig = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rust {
|
|
||||||
rootDirRel = "../../../"
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation("androidx.webkit:webkit:1.14.0")
|
|
||||||
implementation("androidx.appcompat:appcompat:1.7.1")
|
|
||||||
implementation("androidx.activity:activity-ktx:1.10.1")
|
|
||||||
implementation("com.google.android.material:material:1.12.0")
|
|
||||||
implementation("androidx.lifecycle:lifecycle-process:2.10.0")
|
|
||||||
implementation("com.github.mik3y:usb-serial-for-android:3.9.0")
|
|
||||||
testImplementation("junit:junit:4.13.2")
|
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.1.4")
|
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(from = "tauri.build.gradle.kts")
|
|
||||||
34
src-tauri/gen/android/app/proguard-rules.pro
vendored
@@ -1,34 +0,0 @@
|
|||||||
# Add project specific ProGuard rules here.
|
|
||||||
# You can control the set of applied configuration files using the
|
|
||||||
# proguardFiles setting in build.gradle.
|
|
||||||
#
|
|
||||||
# For more details, see
|
|
||||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
|
||||||
|
|
||||||
# If your project uses WebView with JS, uncomment the following
|
|
||||||
# and specify the fully qualified class name to the JavaScript interface
|
|
||||||
# class:
|
|
||||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
|
||||||
# public *;
|
|
||||||
#}
|
|
||||||
|
|
||||||
# Uncomment this to preserve the line number information for
|
|
||||||
# debugging stack traces.
|
|
||||||
#-keepattributes SourceFile,LineNumberTable
|
|
||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
|
||||||
# hide the original source file name.
|
|
||||||
#-renamesourcefileattribute SourceFile
|
|
||||||
|
|
||||||
-keepattributes RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations,*Annotation*,Signature,InnerClasses,EnclosingMethod
|
|
||||||
|
|
||||||
-keep class app.tauri.annotation.** { *; }
|
|
||||||
-keep class app.tauri.plugin.** { *; }
|
|
||||||
|
|
||||||
-keep class com.lenn.tauri_serial.MainActivity { *; }
|
|
||||||
-keep class com.lenn.tauri_serial.UsbSerialPlugin { *; }
|
|
||||||
-keepclassmembers class com.lenn.tauri_serial.UsbSerialPlugin {
|
|
||||||
public *;
|
|
||||||
}
|
|
||||||
|
|
||||||
-keep class com.hoho.android.usbserial.** { *; }
|
|
||||||
5
src-tauri/gen/android/app/proguard-tauri.pro
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
|
||||||
|
-keep class com.lenn.tauri_serial.TauriActivity {
|
||||||
|
public app.tauri.plugin.PluginManager getPluginManager();
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
|
|
||||||
<!-- USB Host support for serial devices -->
|
|
||||||
<uses-feature android:name="android.hardware.usb.host" android:required="true" />
|
|
||||||
|
|
||||||
<!-- AndroidTV support -->
|
|
||||||
<uses-feature android:name="android.software.leanback" android:required="false" />
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@style/Theme.je_skin"
|
|
||||||
android:usesCleartextTraffic="${usesCleartextTraffic}">
|
|
||||||
<activity
|
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
|
||||||
android:launchMode="singleTask"
|
|
||||||
android:label="@string/main_activity_title"
|
|
||||||
android:name=".MainActivity"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
<!-- AndroidTV support -->
|
|
||||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
<!-- Auto-launch when USB device is attached -->
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
|
||||||
</intent-filter>
|
|
||||||
<meta-data
|
|
||||||
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
|
||||||
android:resource="@xml/usb_device_filter" />
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{"$schema":"https://schema.tauri.app/config/2","productName":"JE-Skin","version":"0.4.0","identifier":"com.lenn.tauri-serial","app":{"windows":[{"label":"main","create":true,"url":"index.html","dragDropEnabled":true,"center":false,"width":1366.0,"height":860.0,"resizable":true,"maximizable":true,"minimizable":true,"closable":true,"title":"JE-Skin","fullscreen":false,"focus":true,"focusable":true,"transparent":false,"maximized":false,"visible":true,"decorations":false,"alwaysOnBottom":false,"alwaysOnTop":false,"visibleOnAllWorkspaces":false,"contentProtected":false,"skipTaskbar":false,"titleBarStyle":"Visible","hiddenTitle":false,"acceptFirstMouse":false,"shadow":true,"incognito":false,"zoomHotkeysEnabled":false,"browserExtensionsEnabled":false,"useHttpsScheme":false,"javascriptDisabled":false,"allowLinkPreview":true,"disableInputAccessoryView":false,"scrollBarStyle":"default"}],"security":{"freezePrototype":false,"dangerousDisableAssetCspModification":false,"assetProtocol":{"scope":[],"enable":false},"pattern":{"use":"brownfield"},"capabilities":[]},"macOSPrivateApi":false,"withGlobalTauri":false,"enableGTKAppId":false},"build":{"devUrl":"http://localhost:1420/","frontendDist":"../build","beforeDevCommand":"npm run dev","beforeBuildCommand":"npm run build","removeUnusedCommands":false,"additionalWatchFolders":[]},"bundle":{"active":true,"targets":"all","createUpdaterArtifacts":true,"icon":["icons/32x32.png","icons/128x128.png","icons/128x128@2x.png","icons/icon.icns","icons/icon.ico"],"resources":["resources/je-skin-devkit-server.exe"],"useLocalToolsDir":false,"windows":{"digestAlgorithm":null,"certificateThumbprint":null,"timestampUrl":null,"tsp":false,"webviewInstallMode":{"type":"downloadBootstrapper","silent":true},"allowDowngrades":true,"wix":null,"nsis":{"template":"nsis/installer.nsi","headerImage":null,"sidebarImage":null,"installerIcon":"icons/icon.ico","installMode":"both","languages":null,"customLanguageFiles":null,"displayLanguageSelector":false,"compression":"lzma","startMenuFolder":null,"installerHooks":null,"minimumWebview2Version":null},"signCommand":null},"linux":{"appimage":{"bundleMediaFramework":false,"files":{}},"deb":{"files":{}},"rpm":{"release":"1","epoch":0,"files":{}}},"macOS":{"files":{},"minimumSystemVersion":"10.13","hardenedRuntime":true,"dmg":{"windowSize":{"width":660,"height":400},"appPosition":{"x":180,"y":170},"applicationFolderPosition":{"x":480,"y":170}}},"iOS":{"minimumSystemVersion":"14.0"},"android":{"minSdkVersion":24,"autoIncrementVersionCode":false}},"plugins":{}}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.lenn.tauri_serial
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import androidx.activity.enableEdgeToEdge
|
|
||||||
|
|
||||||
class MainActivity : TauriActivity() {
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
enableEdgeToEdge()
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,388 +0,0 @@
|
|||||||
package com.lenn.tauri_serial
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.hardware.usb.UsbDevice
|
|
||||||
import android.hardware.usb.UsbDeviceConnection
|
|
||||||
import android.hardware.usb.UsbManager
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.ParcelFileDescriptor
|
|
||||||
import android.system.Os
|
|
||||||
import android.system.OsConstants
|
|
||||||
import app.tauri.annotation.Command
|
|
||||||
import app.tauri.annotation.TauriPlugin
|
|
||||||
import app.tauri.plugin.Invoke
|
|
||||||
import app.tauri.plugin.JSObject
|
|
||||||
import app.tauri.plugin.Plugin
|
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialDriver
|
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialPort
|
|
||||||
import com.hoho.android.usbserial.driver.UsbSerialProber
|
|
||||||
import java.io.FileDescriptor
|
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.io.IOException
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
|
||||||
import org.json.JSONArray
|
|
||||||
|
|
||||||
@TauriPlugin
|
|
||||||
class UsbSerialPlugin(private val activity: Activity) : Plugin(activity) {
|
|
||||||
companion object {
|
|
||||||
private const val ACTION_USB_PERMISSION = "com.lenn.tauri_serial.USB_PERMISSION"
|
|
||||||
private const val BAUD_RATE = 921600
|
|
||||||
private const val READ_TIMEOUT_MS = 100
|
|
||||||
private const val WRITE_TIMEOUT_MS = 100
|
|
||||||
}
|
|
||||||
|
|
||||||
private var pendingConnectInvoke: Invoke? = null
|
|
||||||
private var pendingConnectDeviceName: String? = null
|
|
||||||
private var activeBridge: SerialBridge? = null
|
|
||||||
|
|
||||||
private val usbPermissionReceiver = object : BroadcastReceiver() {
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
if (ACTION_USB_PERMISSION != intent.action) return
|
|
||||||
|
|
||||||
synchronized(this@UsbSerialPlugin) {
|
|
||||||
val device = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
intent.getParcelableExtra(UsbManager.EXTRA_DEVICE, UsbDevice::class.java)
|
|
||||||
} else {
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
|
|
||||||
}
|
|
||||||
|
|
||||||
val granted = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)
|
|
||||||
val invoke = pendingConnectInvoke
|
|
||||||
val targetDeviceName = pendingConnectDeviceName
|
|
||||||
|
|
||||||
pendingConnectInvoke = null
|
|
||||||
pendingConnectDeviceName = null
|
|
||||||
|
|
||||||
if (invoke == null || device == null) return
|
|
||||||
|
|
||||||
if (!granted) {
|
|
||||||
invoke.reject("USB permission denied")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targetDeviceName != null && device.deviceName == targetDeviceName) {
|
|
||||||
openAndReturn(invoke, device.deviceName)
|
|
||||||
} else {
|
|
||||||
invoke.reject("USB device mismatch")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun load(webView: android.webkit.WebView) {
|
|
||||||
super.load(webView)
|
|
||||||
val filter = IntentFilter(ACTION_USB_PERMISSION)
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
activity.applicationContext.registerReceiver(
|
|
||||||
usbPermissionReceiver,
|
|
||||||
filter,
|
|
||||||
Context.RECEIVER_NOT_EXPORTED
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
activity.applicationContext.registerReceiver(usbPermissionReceiver, filter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
activeBridge?.close()
|
|
||||||
activeBridge = null
|
|
||||||
try {
|
|
||||||
activity.applicationContext.unregisterReceiver(usbPermissionReceiver)
|
|
||||||
} catch (_: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Command
|
|
||||||
fun usb_serial_list(invoke: Invoke) {
|
|
||||||
listDevices(invoke)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Command
|
|
||||||
fun usbSerialList(invoke: Invoke) {
|
|
||||||
listDevices(invoke)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun listDevices(invoke: Invoke) {
|
|
||||||
val usbManager = activity.getSystemService(Context.USB_SERVICE) as? UsbManager
|
|
||||||
if (usbManager == null) {
|
|
||||||
invoke.reject("USB service not available")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = JSObject()
|
|
||||||
val serialDevices = JSONArray()
|
|
||||||
|
|
||||||
for (driver in UsbSerialProber.getDefaultProber().findAllDrivers(usbManager)) {
|
|
||||||
val device = driver.device
|
|
||||||
val obj = JSObject()
|
|
||||||
obj.put("name", device.deviceName)
|
|
||||||
obj.put("vendorId", device.vendorId)
|
|
||||||
obj.put("productId", device.productId)
|
|
||||||
obj.put("manufacturer", safeDeviceString { device.manufacturerName })
|
|
||||||
obj.put("product", safeDeviceString { device.productName })
|
|
||||||
obj.put("serial", safeDeviceString { device.serialNumber })
|
|
||||||
obj.put("hasPermission", usbManager.hasPermission(device))
|
|
||||||
serialDevices.put(obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.put("devices", serialDevices)
|
|
||||||
invoke.resolve(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Command
|
|
||||||
fun usb_serial_open(invoke: Invoke) {
|
|
||||||
openDevice(invoke)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Command
|
|
||||||
fun usbSerialOpen(invoke: Invoke) {
|
|
||||||
openDevice(invoke)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun openDevice(invoke: Invoke) {
|
|
||||||
val args = invoke.parseArgs(JSObject::class.java)
|
|
||||||
val deviceName = args.optString("name", "")
|
|
||||||
val vendorId = if (args.has("vendorId")) args.optInt("vendorId") else null
|
|
||||||
val productId = if (args.has("productId")) args.optInt("productId") else null
|
|
||||||
|
|
||||||
val usbManager = activity.getSystemService(Context.USB_SERVICE) as? UsbManager
|
|
||||||
if (usbManager == null) {
|
|
||||||
invoke.reject("USB service not available")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val device = resolveDevice(usbManager, deviceName, vendorId, productId)
|
|
||||||
if (device == null) {
|
|
||||||
val available = usbManager.deviceList.values.joinToString(", ") { it.deviceName }
|
|
||||||
invoke.reject("USB device not found: $deviceName; available: $available")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!usbManager.hasPermission(device)) {
|
|
||||||
synchronized(this) {
|
|
||||||
pendingConnectInvoke = invoke
|
|
||||||
pendingConnectDeviceName = device.deviceName
|
|
||||||
}
|
|
||||||
|
|
||||||
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
|
||||||
} else {
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT
|
|
||||||
}
|
|
||||||
val permissionRequest = Intent(ACTION_USB_PERMISSION).setPackage(activity.packageName)
|
|
||||||
val permissionIntent = PendingIntent.getBroadcast(
|
|
||||||
activity,
|
|
||||||
0,
|
|
||||||
permissionRequest,
|
|
||||||
flags
|
|
||||||
)
|
|
||||||
usbManager.requestPermission(device, permissionIntent)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
openAndReturn(invoke, device.deviceName)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Command
|
|
||||||
fun usb_serial_close(invoke: Invoke) {
|
|
||||||
closeBridge()
|
|
||||||
invoke.resolve(JSObject())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Command
|
|
||||||
fun usbSerialClose(invoke: Invoke) {
|
|
||||||
closeBridge()
|
|
||||||
invoke.resolve(JSObject())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun closeBridge() {
|
|
||||||
activeBridge?.close()
|
|
||||||
activeBridge = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun openAndReturn(invoke: Invoke, deviceName: String) {
|
|
||||||
val usbManager = activity.getSystemService(Context.USB_SERVICE) as? UsbManager
|
|
||||||
if (usbManager == null) {
|
|
||||||
invoke.reject("USB service not available")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val driver = findDriver(usbManager, deviceName)
|
|
||||||
if (driver == null) {
|
|
||||||
invoke.reject("USB serial driver not found: $deviceName")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val connection = usbManager.openDevice(driver.device)
|
|
||||||
if (connection == null) {
|
|
||||||
invoke.reject("Failed to open USB device")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val port = driver.ports.firstOrNull()
|
|
||||||
if (port == null) {
|
|
||||||
connection.close()
|
|
||||||
invoke.reject("No serial port found on USB device")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
port.open(connection)
|
|
||||||
port.setParameters(
|
|
||||||
BAUD_RATE,
|
|
||||||
UsbSerialPort.DATABITS_8,
|
|
||||||
UsbSerialPort.STOPBITS_1,
|
|
||||||
UsbSerialPort.PARITY_NONE
|
|
||||||
)
|
|
||||||
|
|
||||||
val rustSide = FileDescriptor()
|
|
||||||
val bridgeSide = FileDescriptor()
|
|
||||||
Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_STREAM, 0, rustSide, bridgeSide)
|
|
||||||
val rustFd = ParcelFileDescriptor.dup(rustSide).detachFd()
|
|
||||||
Os.close(rustSide)
|
|
||||||
|
|
||||||
activeBridge?.close()
|
|
||||||
activeBridge = SerialBridge(bridgeSide, port, connection).also { it.start() }
|
|
||||||
|
|
||||||
val result = JSObject()
|
|
||||||
result.put("fd", rustFd)
|
|
||||||
result.put("name", driver.device.deviceName)
|
|
||||||
result.put("vendorId", driver.device.vendorId)
|
|
||||||
result.put("productId", driver.device.productId)
|
|
||||||
invoke.resolve(result)
|
|
||||||
} catch (error: Exception) {
|
|
||||||
try {
|
|
||||||
port.close()
|
|
||||||
} catch (_: Exception) {
|
|
||||||
}
|
|
||||||
connection.close()
|
|
||||||
invoke.reject(error.message ?: "Failed to open USB serial port")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findDriver(usbManager: UsbManager, deviceName: String): UsbSerialDriver? {
|
|
||||||
return UsbSerialProber.getDefaultProber()
|
|
||||||
.findAllDrivers(usbManager)
|
|
||||||
.firstOrNull { it.device.deviceName == deviceName || it.device.deviceName.equals(deviceName, ignoreCase = true) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun resolveDevice(
|
|
||||||
usbManager: UsbManager,
|
|
||||||
deviceName: String,
|
|
||||||
vendorId: Int?,
|
|
||||||
productId: Int?
|
|
||||||
): UsbDevice? {
|
|
||||||
usbManager.deviceList[deviceName]?.let { return it }
|
|
||||||
|
|
||||||
val devices = usbManager.deviceList.values.toList()
|
|
||||||
devices.firstOrNull { it.deviceName.equals(deviceName, ignoreCase = true) }?.let { return it }
|
|
||||||
|
|
||||||
if (vendorId != null && productId != null) {
|
|
||||||
devices.firstOrNull { it.vendorId == vendorId && it.productId == productId }?.let { return it }
|
|
||||||
}
|
|
||||||
|
|
||||||
val drivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager)
|
|
||||||
drivers.firstOrNull {
|
|
||||||
it.device.deviceName == deviceName || it.device.deviceName.equals(deviceName, ignoreCase = true)
|
|
||||||
}?.device?.let { return it }
|
|
||||||
|
|
||||||
if (drivers.size == 1) {
|
|
||||||
return drivers.first().device
|
|
||||||
}
|
|
||||||
|
|
||||||
if (devices.size == 1) {
|
|
||||||
return devices.first()
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun safeDeviceString(read: () -> String?): String {
|
|
||||||
return try {
|
|
||||||
read() ?: ""
|
|
||||||
} catch (_: SecurityException) {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SerialBridge(
|
|
||||||
private val bridgeFd: FileDescriptor,
|
|
||||||
private val port: UsbSerialPort,
|
|
||||||
private val connection: UsbDeviceConnection
|
|
||||||
) {
|
|
||||||
private val running = AtomicBoolean(false)
|
|
||||||
private lateinit var serialToRustThread: Thread
|
|
||||||
private lateinit var rustToSerialThread: Thread
|
|
||||||
|
|
||||||
fun start() {
|
|
||||||
running.set(true)
|
|
||||||
serialToRustThread = Thread(::copySerialToRust, "JE-Skin-usb-serial-rx")
|
|
||||||
rustToSerialThread = Thread(::copyRustToSerial, "JE-Skin-usb-serial-tx")
|
|
||||||
serialToRustThread.start()
|
|
||||||
rustToSerialThread.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun close() {
|
|
||||||
if (!running.getAndSet(false)) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
Os.close(bridgeFd)
|
|
||||||
} catch (_: Exception) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
port.close()
|
|
||||||
} catch (_: Exception) {
|
|
||||||
}
|
|
||||||
connection.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun copySerialToRust() {
|
|
||||||
val output = FileOutputStream(bridgeFd)
|
|
||||||
val buffer = ByteArray(4096)
|
|
||||||
|
|
||||||
while (running.get()) {
|
|
||||||
try {
|
|
||||||
val count = port.read(buffer, READ_TIMEOUT_MS)
|
|
||||||
if (count > 0) {
|
|
||||||
output.write(buffer, 0, count)
|
|
||||||
output.flush()
|
|
||||||
}
|
|
||||||
} catch (_: IOException) {
|
|
||||||
close()
|
|
||||||
} catch (_: Exception) {
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun copyRustToSerial() {
|
|
||||||
val input = FileInputStream(bridgeFd)
|
|
||||||
val buffer = ByteArray(4096)
|
|
||||||
|
|
||||||
while (running.get()) {
|
|
||||||
try {
|
|
||||||
val count = input.read(buffer)
|
|
||||||
if (count < 0) {
|
|
||||||
close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (count > 0) {
|
|
||||||
port.write(buffer.copyOf(count), WRITE_TIMEOUT_MS)
|
|
||||||
}
|
|
||||||
} catch (_: IOException) {
|
|
||||||
close()
|
|
||||||
} catch (_: Exception) {
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
|
||||||
|
|
||||||
|
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
@file:Suppress("unused")
|
||||||
|
|
||||||
|
package com.lenn.tauri_serial
|
||||||
|
|
||||||
|
import android.webkit.*
|
||||||
|
|
||||||
|
class Ipc(val webViewClient: RustWebViewClient) {
|
||||||
|
@JavascriptInterface
|
||||||
|
fun postMessage(message: String?) {
|
||||||
|
message?.let {m ->
|
||||||
|
// we're not using WebView::getUrl() here because it needs to be executed on the main thread
|
||||||
|
// and it would slow down the Ipc
|
||||||
|
// so instead we track the current URL on the webview client
|
||||||
|
this.ipc(webViewClient.currentUrl, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
init {
|
||||||
|
System.loadLibrary("tauri_demo_lib")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun ipc(url: String, message: String)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
|
||||||
|
|
||||||
|
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
@file:Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||||
|
|
||||||
|
package com.lenn.tauri_serial
|
||||||
|
|
||||||
|
// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/Logger.java
|
||||||
|
|
||||||
|
import android.text.TextUtils
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
companion object {
|
||||||
|
private const val LOG_TAG_CORE = "Tauri"
|
||||||
|
|
||||||
|
fun tags(vararg subtags: String): String {
|
||||||
|
return if (subtags.isNotEmpty()) {
|
||||||
|
LOG_TAG_CORE + "/" + TextUtils.join("/", subtags)
|
||||||
|
} else LOG_TAG_CORE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verbose(message: String) {
|
||||||
|
verbose(LOG_TAG_CORE, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun verbose(tag: String, message: String) {
|
||||||
|
if (!shouldLog()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Log.v(tag, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun debug(message: String) {
|
||||||
|
debug(LOG_TAG_CORE, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun debug(tag: String, message: String) {
|
||||||
|
if (!shouldLog()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Log.d(tag, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun info(message: String) {
|
||||||
|
info(LOG_TAG_CORE, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun info(tag: String, message: String) {
|
||||||
|
if (!shouldLog()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Log.i(tag, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun warn(message: String) {
|
||||||
|
warn(LOG_TAG_CORE, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun warn(tag: String, message: String) {
|
||||||
|
if (!shouldLog()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Log.w(tag, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun error(message: String) {
|
||||||
|
error(LOG_TAG_CORE, message, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun error(message: String, e: Throwable?) {
|
||||||
|
error(LOG_TAG_CORE, message, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun error(tag: String, message: String, e: Throwable?) {
|
||||||
|
if (!shouldLog()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Log.e(tag, message, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldLog(): Boolean {
|
||||||
|
return BuildConfig.DEBUG
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
|
||||||
|
|
||||||
|
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package com.lenn.tauri_serial
|
||||||
|
|
||||||
|
// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/PermissionHelper.java
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
object PermissionHelper {
|
||||||
|
/**
|
||||||
|
* Checks if a list of given permissions are all granted by the user
|
||||||
|
*
|
||||||
|
* @param permissions Permissions to check.
|
||||||
|
* @return True if all permissions are granted, false if at least one is not.
|
||||||
|
*/
|
||||||
|
fun hasPermissions(context: Context?, permissions: Array<String>): Boolean {
|
||||||
|
for (perm in permissions) {
|
||||||
|
if (ActivityCompat.checkSelfPermission(
|
||||||
|
context!!,
|
||||||
|
perm
|
||||||
|
) != PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given permission has been defined in the AndroidManifest.xml
|
||||||
|
*
|
||||||
|
* @param permission A permission to check.
|
||||||
|
* @return True if the permission has been defined in the Manifest, false if not.
|
||||||
|
*/
|
||||||
|
fun hasDefinedPermission(context: Context, permission: String): Boolean {
|
||||||
|
var hasPermission = false
|
||||||
|
val requestedPermissions = getManifestPermissions(context)
|
||||||
|
if (!requestedPermissions.isNullOrEmpty()) {
|
||||||
|
val requestedPermissionsList = listOf(*requestedPermissions)
|
||||||
|
val requestedPermissionsArrayList = ArrayList(requestedPermissionsList)
|
||||||
|
if (requestedPermissionsArrayList.contains(permission)) {
|
||||||
|
hasPermission = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasPermission
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether all of the given permissions have been defined in the AndroidManifest.xml
|
||||||
|
* @param context the app context
|
||||||
|
* @param permissions a list of permissions
|
||||||
|
* @return true only if all permissions are defined in the AndroidManifest.xml
|
||||||
|
*/
|
||||||
|
fun hasDefinedPermissions(context: Context, permissions: Array<String>): Boolean {
|
||||||
|
for (permission in permissions) {
|
||||||
|
if (!hasDefinedPermission(context, permission)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the permissions defined in AndroidManifest.xml
|
||||||
|
*
|
||||||
|
* @return The permissions defined in AndroidManifest.xml
|
||||||
|
*/
|
||||||
|
private fun getManifestPermissions(context: Context): Array<String>? {
|
||||||
|
var requestedPermissions: Array<String>? = null
|
||||||
|
try {
|
||||||
|
val pm = context.packageManager
|
||||||
|
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
pm.getPackageInfo(context.packageName, PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong()))
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
pm.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
|
||||||
|
}
|
||||||
|
if (packageInfo != null) {
|
||||||
|
requestedPermissions = packageInfo.requestedPermissions
|
||||||
|
}
|
||||||
|
} catch (_: Exception) {
|
||||||
|
}
|
||||||
|
return requestedPermissions
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a list of permissions, return a new list with the ones not present in AndroidManifest.xml
|
||||||
|
*
|
||||||
|
* @param neededPermissions The permissions needed.
|
||||||
|
* @return The permissions not present in AndroidManifest.xml
|
||||||
|
*/
|
||||||
|
fun getUndefinedPermissions(context: Context, neededPermissions: Array<String?>): Array<String?> {
|
||||||
|
val undefinedPermissions = ArrayList<String?>()
|
||||||
|
val requestedPermissions = getManifestPermissions(context)
|
||||||
|
if (!requestedPermissions.isNullOrEmpty()) {
|
||||||
|
val requestedPermissionsList = listOf(*requestedPermissions)
|
||||||
|
val requestedPermissionsArrayList = ArrayList(requestedPermissionsList)
|
||||||
|
for (permission in neededPermissions) {
|
||||||
|
if (!requestedPermissionsArrayList.contains(permission)) {
|
||||||
|
undefinedPermissions.add(permission)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var undefinedPermissionArray = arrayOfNulls<String>(undefinedPermissions.size)
|
||||||
|
undefinedPermissionArray = undefinedPermissions.toArray(undefinedPermissionArray)
|
||||||
|
return undefinedPermissionArray
|
||||||
|
}
|
||||||
|
return neededPermissions
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,495 @@
|
|||||||
|
/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
|
||||||
|
|
||||||
|
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
@file:Suppress("ObsoleteSdkInt", "RedundantOverride", "QueryPermissionsNeeded", "SimpleDateFormat")
|
||||||
|
|
||||||
|
package com.lenn.tauri_serial
|
||||||
|
|
||||||
|
// taken from https://github.com/ionic-team/capacitor/blob/6658bca41e78239347e458175b14ca8bd5c1d6e8/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
|
import android.provider.MediaStore
|
||||||
|
import android.view.View
|
||||||
|
import android.webkit.*
|
||||||
|
import android.widget.EditText
|
||||||
|
import androidx.activity.result.ActivityResult
|
||||||
|
import androidx.activity.result.ActivityResultCallback
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class RustWebChromeClient(appActivity: WryActivity) : WebChromeClient() {
|
||||||
|
private interface PermissionListener {
|
||||||
|
fun onPermissionSelect(isGranted: Boolean?)
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface ActivityResultListener {
|
||||||
|
fun onActivityResult(result: ActivityResult?)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val activity: WryActivity
|
||||||
|
private var permissionLauncher: ActivityResultLauncher<Array<String>>
|
||||||
|
private var activityLauncher: ActivityResultLauncher<Intent>
|
||||||
|
private var permissionListener: PermissionListener? = null
|
||||||
|
private var activityListener: ActivityResultListener? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
activity = appActivity
|
||||||
|
val permissionCallback =
|
||||||
|
ActivityResultCallback { isGranted: Map<String, Boolean> ->
|
||||||
|
if (permissionListener != null) {
|
||||||
|
var granted = true
|
||||||
|
for ((_, value) in isGranted) {
|
||||||
|
if (!value) granted = false
|
||||||
|
}
|
||||||
|
permissionListener!!.onPermissionSelect(granted)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
permissionLauncher =
|
||||||
|
activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions(), permissionCallback)
|
||||||
|
activityLauncher = activity.registerForActivityResult(
|
||||||
|
ActivityResultContracts.StartActivityForResult()
|
||||||
|
) { result ->
|
||||||
|
if (activityListener != null) {
|
||||||
|
activityListener!!.onActivityResult(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render web content in `view`.
|
||||||
|
*
|
||||||
|
* Both this method and [.onHideCustomView] are required for
|
||||||
|
* rendering web content in full screen.
|
||||||
|
*
|
||||||
|
* @see [](https://developer.android.com/reference/android/webkit/WebChromeClient.onShowCustomView
|
||||||
|
) */
|
||||||
|
override fun onShowCustomView(view: View, callback: CustomViewCallback) {
|
||||||
|
callback.onCustomViewHidden()
|
||||||
|
super.onShowCustomView(view, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render web content in the original Web View again.
|
||||||
|
*
|
||||||
|
* Do not remove this method--@see #onShowCustomView(View, CustomViewCallback).
|
||||||
|
*/
|
||||||
|
override fun onHideCustomView() {
|
||||||
|
super.onHideCustomView()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPermissionRequest(request: PermissionRequest) {
|
||||||
|
val isRequestPermissionRequired = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
|
val permissionList: MutableList<String> = ArrayList()
|
||||||
|
if (listOf(*request.resources).contains("android.webkit.resource.VIDEO_CAPTURE")) {
|
||||||
|
permissionList.add(Manifest.permission.CAMERA)
|
||||||
|
}
|
||||||
|
if (listOf(*request.resources).contains("android.webkit.resource.AUDIO_CAPTURE")) {
|
||||||
|
permissionList.add(Manifest.permission.MODIFY_AUDIO_SETTINGS)
|
||||||
|
permissionList.add(Manifest.permission.RECORD_AUDIO)
|
||||||
|
}
|
||||||
|
if (permissionList.isNotEmpty() && isRequestPermissionRequired) {
|
||||||
|
val permissions = permissionList.toTypedArray()
|
||||||
|
permissionListener = object : PermissionListener {
|
||||||
|
override fun onPermissionSelect(isGranted: Boolean?) {
|
||||||
|
if (isGranted == true) {
|
||||||
|
request.grant(request.resources)
|
||||||
|
} else {
|
||||||
|
request.deny()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
permissionLauncher.launch(permissions)
|
||||||
|
} else {
|
||||||
|
request.grant(request.resources)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the browser alert modal
|
||||||
|
* @param view
|
||||||
|
* @param url
|
||||||
|
* @param message
|
||||||
|
* @param result
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
override fun onJsAlert(view: WebView, url: String, message: String, result: JsResult): Boolean {
|
||||||
|
if (activity.isFinishing) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val builder = AlertDialog.Builder(view.context)
|
||||||
|
builder
|
||||||
|
.setMessage(message)
|
||||||
|
.setPositiveButton(
|
||||||
|
"OK"
|
||||||
|
) { dialog: DialogInterface, _: Int ->
|
||||||
|
dialog.dismiss()
|
||||||
|
result.confirm()
|
||||||
|
}
|
||||||
|
.setOnCancelListener { dialog: DialogInterface ->
|
||||||
|
dialog.dismiss()
|
||||||
|
result.cancel()
|
||||||
|
}
|
||||||
|
val dialog = builder.create()
|
||||||
|
dialog.show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the browser confirm modal
|
||||||
|
* @param view
|
||||||
|
* @param url
|
||||||
|
* @param message
|
||||||
|
* @param result
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
override fun onJsConfirm(view: WebView, url: String, message: String, result: JsResult): Boolean {
|
||||||
|
if (activity.isFinishing) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val builder = AlertDialog.Builder(view.context)
|
||||||
|
builder
|
||||||
|
.setMessage(message)
|
||||||
|
.setPositiveButton(
|
||||||
|
"OK"
|
||||||
|
) { dialog: DialogInterface, _: Int ->
|
||||||
|
dialog.dismiss()
|
||||||
|
result.confirm()
|
||||||
|
}
|
||||||
|
.setNegativeButton(
|
||||||
|
"Cancel"
|
||||||
|
) { dialog: DialogInterface, _: Int ->
|
||||||
|
dialog.dismiss()
|
||||||
|
result.cancel()
|
||||||
|
}
|
||||||
|
.setOnCancelListener { dialog: DialogInterface ->
|
||||||
|
dialog.dismiss()
|
||||||
|
result.cancel()
|
||||||
|
}
|
||||||
|
val dialog = builder.create()
|
||||||
|
dialog.show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the browser prompt modal
|
||||||
|
* @param view
|
||||||
|
* @param url
|
||||||
|
* @param message
|
||||||
|
* @param defaultValue
|
||||||
|
* @param result
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
override fun onJsPrompt(
|
||||||
|
view: WebView,
|
||||||
|
url: String,
|
||||||
|
message: String,
|
||||||
|
defaultValue: String,
|
||||||
|
result: JsPromptResult
|
||||||
|
): Boolean {
|
||||||
|
if (activity.isFinishing) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val builder = AlertDialog.Builder(view.context)
|
||||||
|
val input = EditText(view.context)
|
||||||
|
builder
|
||||||
|
.setMessage(message)
|
||||||
|
.setView(input)
|
||||||
|
.setPositiveButton(
|
||||||
|
"OK"
|
||||||
|
) { dialog: DialogInterface, _: Int ->
|
||||||
|
dialog.dismiss()
|
||||||
|
val inputText1 = input.text.toString().trim { it <= ' ' }
|
||||||
|
result.confirm(inputText1)
|
||||||
|
}
|
||||||
|
.setNegativeButton(
|
||||||
|
"Cancel"
|
||||||
|
) { dialog: DialogInterface, _: Int ->
|
||||||
|
dialog.dismiss()
|
||||||
|
result.cancel()
|
||||||
|
}
|
||||||
|
.setOnCancelListener { dialog: DialogInterface ->
|
||||||
|
dialog.dismiss()
|
||||||
|
result.cancel()
|
||||||
|
}
|
||||||
|
val dialog = builder.create()
|
||||||
|
dialog.show()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the browser geolocation permission prompt
|
||||||
|
* @param origin
|
||||||
|
* @param callback
|
||||||
|
*/
|
||||||
|
override fun onGeolocationPermissionsShowPrompt(
|
||||||
|
origin: String,
|
||||||
|
callback: GeolocationPermissions.Callback
|
||||||
|
) {
|
||||||
|
super.onGeolocationPermissionsShowPrompt(origin, callback)
|
||||||
|
Logger.debug("onGeolocationPermissionsShowPrompt: DOING IT HERE FOR ORIGIN: $origin")
|
||||||
|
val geoPermissions =
|
||||||
|
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
|
if (!PermissionHelper.hasPermissions(activity, geoPermissions)) {
|
||||||
|
permissionListener = object : PermissionListener {
|
||||||
|
override fun onPermissionSelect(isGranted: Boolean?) {
|
||||||
|
if (isGranted == true) {
|
||||||
|
callback.invoke(origin, true, false)
|
||||||
|
} else {
|
||||||
|
val coarsePermission =
|
||||||
|
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
|
||||||
|
PermissionHelper.hasPermissions(activity, coarsePermission)
|
||||||
|
) {
|
||||||
|
callback.invoke(origin, true, false)
|
||||||
|
} else {
|
||||||
|
callback.invoke(origin, false, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
permissionLauncher.launch(geoPermissions)
|
||||||
|
} else {
|
||||||
|
// permission is already granted
|
||||||
|
callback.invoke(origin, true, false)
|
||||||
|
Logger.debug("onGeolocationPermissionsShowPrompt: has required permission")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onShowFileChooser(
|
||||||
|
webView: WebView,
|
||||||
|
filePathCallback: ValueCallback<Array<Uri?>?>,
|
||||||
|
fileChooserParams: FileChooserParams
|
||||||
|
): Boolean {
|
||||||
|
val acceptTypes = listOf(*fileChooserParams.acceptTypes)
|
||||||
|
val captureEnabled = fileChooserParams.isCaptureEnabled
|
||||||
|
val capturePhoto = captureEnabled && acceptTypes.contains("image/*")
|
||||||
|
val captureVideo = captureEnabled && acceptTypes.contains("video/*")
|
||||||
|
if (capturePhoto || captureVideo) {
|
||||||
|
if (isMediaCaptureSupported) {
|
||||||
|
showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo)
|
||||||
|
} else {
|
||||||
|
permissionListener = object : PermissionListener {
|
||||||
|
override fun onPermissionSelect(isGranted: Boolean?) {
|
||||||
|
if (isGranted == true) {
|
||||||
|
showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo)
|
||||||
|
} else {
|
||||||
|
Logger.warn(Logger.tags("FileChooser"), "Camera permission not granted")
|
||||||
|
filePathCallback.onReceiveValue(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val camPermission = arrayOf(Manifest.permission.CAMERA)
|
||||||
|
permissionLauncher.launch(camPermission)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showFilePicker(filePathCallback, fileChooserParams)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private val isMediaCaptureSupported: Boolean
|
||||||
|
get() {
|
||||||
|
val permissions = arrayOf(Manifest.permission.CAMERA)
|
||||||
|
return PermissionHelper.hasPermissions(activity, permissions) ||
|
||||||
|
!PermissionHelper.hasDefinedPermission(activity, Manifest.permission.CAMERA)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showMediaCaptureOrFilePicker(
|
||||||
|
filePathCallback: ValueCallback<Array<Uri?>?>,
|
||||||
|
fileChooserParams: FileChooserParams,
|
||||||
|
isVideo: Boolean
|
||||||
|
) {
|
||||||
|
val isVideoCaptureSupported = true
|
||||||
|
val shown = if (isVideo && isVideoCaptureSupported) {
|
||||||
|
showVideoCapturePicker(filePathCallback)
|
||||||
|
} else {
|
||||||
|
showImageCapturePicker(filePathCallback)
|
||||||
|
}
|
||||||
|
if (!shown) {
|
||||||
|
Logger.warn(
|
||||||
|
Logger.tags("FileChooser"),
|
||||||
|
"Media capture intent could not be launched. Falling back to default file picker."
|
||||||
|
)
|
||||||
|
showFilePicker(filePathCallback, fileChooserParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showImageCapturePicker(filePathCallback: ValueCallback<Array<Uri?>?>): Boolean {
|
||||||
|
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
|
||||||
|
if (takePictureIntent.resolveActivity(activity.packageManager) == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val imageFileUri: Uri = try {
|
||||||
|
createImageFileUri()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Logger.error("Unable to create temporary media capture file: " + ex.message)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri)
|
||||||
|
activityListener = object : ActivityResultListener {
|
||||||
|
override fun onActivityResult(result: ActivityResult?) {
|
||||||
|
var res: Array<Uri?>? = null
|
||||||
|
if (result?.resultCode == Activity.RESULT_OK) {
|
||||||
|
res = arrayOf(imageFileUri)
|
||||||
|
}
|
||||||
|
filePathCallback.onReceiveValue(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activityLauncher.launch(takePictureIntent)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showVideoCapturePicker(filePathCallback: ValueCallback<Array<Uri?>?>): Boolean {
|
||||||
|
val takeVideoIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
|
||||||
|
if (takeVideoIntent.resolveActivity(activity.packageManager) == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
activityListener = object : ActivityResultListener {
|
||||||
|
override fun onActivityResult(result: ActivityResult?) {
|
||||||
|
var res: Array<Uri?>? = null
|
||||||
|
if (result?.resultCode == Activity.RESULT_OK) {
|
||||||
|
res = arrayOf(result.data!!.data)
|
||||||
|
}
|
||||||
|
filePathCallback.onReceiveValue(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activityLauncher.launch(takeVideoIntent)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showFilePicker(
|
||||||
|
filePathCallback: ValueCallback<Array<Uri?>?>,
|
||||||
|
fileChooserParams: FileChooserParams
|
||||||
|
) {
|
||||||
|
val intent = fileChooserParams.createIntent()
|
||||||
|
if (fileChooserParams.mode == FileChooserParams.MODE_OPEN_MULTIPLE) {
|
||||||
|
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||||
|
}
|
||||||
|
if (fileChooserParams.acceptTypes.size > 1 || intent.type!!.startsWith(".")) {
|
||||||
|
val validTypes = getValidTypes(fileChooserParams.acceptTypes)
|
||||||
|
intent.putExtra(Intent.EXTRA_MIME_TYPES, validTypes)
|
||||||
|
if (intent.type!!.startsWith(".")) {
|
||||||
|
intent.type = validTypes[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
activityListener = object : ActivityResultListener {
|
||||||
|
override fun onActivityResult(result: ActivityResult?) {
|
||||||
|
val res: Array<Uri?>?
|
||||||
|
val resultIntent = result?.data
|
||||||
|
if (result?.resultCode == Activity.RESULT_OK && resultIntent!!.clipData != null) {
|
||||||
|
val numFiles = resultIntent.clipData!!.itemCount
|
||||||
|
res = arrayOfNulls(numFiles)
|
||||||
|
for (i in 0 until numFiles) {
|
||||||
|
res[i] = resultIntent.clipData!!.getItemAt(i).uri
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = FileChooserParams.parseResult(
|
||||||
|
result?.resultCode ?: 0,
|
||||||
|
resultIntent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
filePathCallback.onReceiveValue(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activityLauncher.launch(intent)
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
filePathCallback.onReceiveValue(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getValidTypes(currentTypes: Array<String>): Array<String> {
|
||||||
|
val validTypes: MutableList<String> = ArrayList()
|
||||||
|
val mtm = MimeTypeMap.getSingleton()
|
||||||
|
for (mime in currentTypes) {
|
||||||
|
if (mime.startsWith(".")) {
|
||||||
|
val extension = mime.substring(1)
|
||||||
|
val extensionMime = mtm.getMimeTypeFromExtension(extension)
|
||||||
|
if (extensionMime != null && !validTypes.contains(extensionMime)) {
|
||||||
|
validTypes.add(extensionMime)
|
||||||
|
}
|
||||||
|
} else if (!validTypes.contains(mime)) {
|
||||||
|
validTypes.add(mime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val validObj: Array<Any> = validTypes.toTypedArray()
|
||||||
|
return Arrays.copyOf(
|
||||||
|
validObj, validObj.size,
|
||||||
|
Array<String>::class.java
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
|
||||||
|
val tag: String = Logger.tags("Console")
|
||||||
|
if (consoleMessage.message() != null && isValidMsg(consoleMessage.message())) {
|
||||||
|
val msg = String.format(
|
||||||
|
"File: %s - Line %d - Msg: %s",
|
||||||
|
consoleMessage.sourceId(),
|
||||||
|
consoleMessage.lineNumber(),
|
||||||
|
consoleMessage.message()
|
||||||
|
)
|
||||||
|
val level = consoleMessage.messageLevel().name
|
||||||
|
if ("ERROR".equals(level, ignoreCase = true)) {
|
||||||
|
Logger.error(tag, msg, null)
|
||||||
|
} else if ("WARNING".equals(level, ignoreCase = true)) {
|
||||||
|
Logger.warn(tag, msg)
|
||||||
|
} else if ("TIP".equals(level, ignoreCase = true)) {
|
||||||
|
Logger.debug(tag, msg)
|
||||||
|
} else {
|
||||||
|
Logger.info(tag, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isValidMsg(msg: String): Boolean {
|
||||||
|
return !(msg.contains("%cresult %c") ||
|
||||||
|
msg.contains("%cnative %c") ||
|
||||||
|
msg.equals("[object Object]", ignoreCase = true) ||
|
||||||
|
msg.equals("console.groupEnd", ignoreCase = true))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
private fun createImageFileUri(): Uri {
|
||||||
|
val photoFile = createImageFile(activity)
|
||||||
|
return FileProvider.getUriForFile(
|
||||||
|
activity,
|
||||||
|
activity.packageName.toString() + ".fileprovider",
|
||||||
|
photoFile
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class)
|
||||||
|
private fun createImageFile(activity: Activity): File {
|
||||||
|
// Create an image file name
|
||||||
|
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
|
||||||
|
val imageFileName = "JPEG_" + timeStamp + "_"
|
||||||
|
val storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
|
||||||
|
return File.createTempFile(imageFileName, ".jpg", storageDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReceivedTitle(
|
||||||
|
view: WebView,
|
||||||
|
title: String
|
||||||
|
) {
|
||||||
|
handleReceivedTitle(view, title)
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun handleReceivedTitle(webview: WebView, title: String)
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
|
||||||
|
|
||||||
|
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
@file:Suppress("unused", "SetJavaScriptEnabled")
|
||||||
|
|
||||||
|
package com.lenn.tauri_serial
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.webkit.*
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.webkit.WebViewCompat
|
||||||
|
import androidx.webkit.WebViewFeature
|
||||||
|
import kotlin.collections.Map
|
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
|
class RustWebView(context: Context, val initScripts: Array<String>, val id: String): WebView(context) {
|
||||||
|
val isDocumentStartScriptEnabled: Boolean
|
||||||
|
|
||||||
|
init {
|
||||||
|
settings.javaScriptEnabled = true
|
||||||
|
settings.domStorageEnabled = true
|
||||||
|
settings.setGeolocationEnabled(true)
|
||||||
|
settings.databaseEnabled = true
|
||||||
|
settings.mediaPlaybackRequiresUserGesture = false
|
||||||
|
settings.javaScriptCanOpenWindowsAutomatically = true
|
||||||
|
|
||||||
|
if (WebViewFeature.isFeatureSupported(WebViewFeature.DOCUMENT_START_SCRIPT)) {
|
||||||
|
isDocumentStartScriptEnabled = true
|
||||||
|
for (script in initScripts) {
|
||||||
|
WebViewCompat.addDocumentStartJavaScript(this, script, setOf("*"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isDocumentStartScriptEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadUrlMainThread(url: String) {
|
||||||
|
post {
|
||||||
|
loadUrl(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadUrlMainThread(url: String, additionalHttpHeaders: Map<String, String>) {
|
||||||
|
post {
|
||||||
|
loadUrl(url, additionalHttpHeaders)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadUrl(url: String) {
|
||||||
|
if (!shouldOverride(url)) {
|
||||||
|
super.loadUrl(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadUrl(url: String, additionalHttpHeaders: Map<String, String>) {
|
||||||
|
if (!shouldOverride(url)) {
|
||||||
|
super.loadUrl(url, additionalHttpHeaders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadHTMLMainThread(html: String) {
|
||||||
|
post {
|
||||||
|
super.loadData(html, "text/html", null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun evalScript(id: Int, script: String) {
|
||||||
|
post {
|
||||||
|
super.evaluateJavascript(script) { result ->
|
||||||
|
onEval(id, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearAllBrowsingData() {
|
||||||
|
try {
|
||||||
|
super.getContext().deleteDatabase("webviewCache.db")
|
||||||
|
super.getContext().deleteDatabase("webview.db")
|
||||||
|
super.clearCache(true)
|
||||||
|
super.clearHistory()
|
||||||
|
super.clearFormData()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Logger.error("Unable to create temporary media capture file: " + ex.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCookies(url: String): String {
|
||||||
|
val cookieManager = CookieManager.getInstance()
|
||||||
|
return cookieManager.getCookie(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun shouldOverride(url: String): Boolean
|
||||||
|
private external fun onEval(id: Int, result: String)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
|
||||||
|
|
||||||
|
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package com.lenn.tauri_serial
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import android.webkit.*
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import androidx.webkit.WebViewAssetLoader
|
||||||
|
|
||||||
|
class RustWebViewClient(context: Context): WebViewClient() {
|
||||||
|
private val interceptedState = mutableMapOf<String, Boolean>()
|
||||||
|
var currentUrl: String = "about:blank"
|
||||||
|
private var lastInterceptedUrl: Uri? = null
|
||||||
|
private var pendingUrlRedirect: String? = null
|
||||||
|
|
||||||
|
private val assetLoader = WebViewAssetLoader.Builder()
|
||||||
|
.setDomain(assetLoaderDomain())
|
||||||
|
.addPathHandler("/", WebViewAssetLoader.AssetsPathHandler(context))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
override fun shouldInterceptRequest(
|
||||||
|
view: WebView,
|
||||||
|
request: WebResourceRequest
|
||||||
|
): WebResourceResponse? {
|
||||||
|
pendingUrlRedirect?.let {
|
||||||
|
Handler(Looper.getMainLooper()).post {
|
||||||
|
view.loadUrl(it)
|
||||||
|
}
|
||||||
|
pendingUrlRedirect = null
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
lastInterceptedUrl = request.url
|
||||||
|
return if (withAssetLoader()) {
|
||||||
|
assetLoader.shouldInterceptRequest(request.url)
|
||||||
|
} else {
|
||||||
|
val rustWebview = view as RustWebView;
|
||||||
|
val response = handleRequest(rustWebview.id, request, rustWebview.isDocumentStartScriptEnabled)
|
||||||
|
interceptedState[request.url.toString()] = response != null
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldOverrideUrlLoading(
|
||||||
|
view: WebView,
|
||||||
|
request: WebResourceRequest
|
||||||
|
): Boolean {
|
||||||
|
return shouldOverride(request.url.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
|
||||||
|
currentUrl = url
|
||||||
|
if (interceptedState[url] == false) {
|
||||||
|
val webView = view as RustWebView
|
||||||
|
for (script in webView.initScripts) {
|
||||||
|
view.evaluateJavascript(script, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return onPageLoading(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPageFinished(view: WebView, url: String) {
|
||||||
|
onPageLoaded(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReceivedError(
|
||||||
|
view: WebView,
|
||||||
|
request: WebResourceRequest,
|
||||||
|
error: WebResourceError
|
||||||
|
) {
|
||||||
|
// we get a net::ERR_CONNECTION_REFUSED when an external URL redirects to a custom protocol
|
||||||
|
// e.g. oauth flow, because shouldInterceptRequest is not called on redirects
|
||||||
|
// so we must force retry here with loadUrl() to get a chance of the custom protocol to kick in
|
||||||
|
if (error.errorCode == ERROR_CONNECT && request.isForMainFrame && request.url != lastInterceptedUrl) {
|
||||||
|
// prevent the default error page from showing
|
||||||
|
view.stopLoading()
|
||||||
|
// without this initial loadUrl the app is stuck
|
||||||
|
view.loadUrl(request.url.toString())
|
||||||
|
// ensure the URL is actually loaded - for some reason there's a race condition and we need to call loadUrl() again later
|
||||||
|
pendingUrlRedirect = request.url.toString()
|
||||||
|
} else {
|
||||||
|
super.onReceivedError(view, request, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
init {
|
||||||
|
System.loadLibrary("tauri_demo_lib")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun assetLoaderDomain(): String
|
||||||
|
private external fun withAssetLoader(): Boolean
|
||||||
|
private external fun handleRequest(webviewId: String, request: WebResourceRequest, isDocumentStartScriptEnabled: Boolean): WebResourceResponse?
|
||||||
|
private external fun shouldOverride(url: String): Boolean
|
||||||
|
private external fun onPageLoading(url: String)
|
||||||
|
private external fun onPageLoaded(url: String)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
|
||||||
|
|
||||||
|
package com.lenn.tauri_serial
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.res.Configuration
|
||||||
|
import app.tauri.plugin.PluginManager
|
||||||
|
|
||||||
|
abstract class TauriActivity : WryActivity() {
|
||||||
|
var pluginManager: PluginManager = PluginManager(this)
|
||||||
|
override val handleBackNavigation: Boolean = false
|
||||||
|
|
||||||
|
override fun onNewIntent(intent: Intent) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
pluginManager.onNewIntent(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
pluginManager.onResume()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
pluginManager.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRestart() {
|
||||||
|
super.onRestart()
|
||||||
|
pluginManager.onRestart()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
pluginManager.onStop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
pluginManager.onDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||||
|
super.onConfigurationChanged(newConfig)
|
||||||
|
pluginManager.onConfigurationChanged(newConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
/* THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!! */
|
||||||
|
|
||||||
|
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package com.lenn.tauri_serial
|
||||||
|
|
||||||
|
import com.lenn.tauri_serial.RustWebView
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.webkit.WebView
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import androidx.activity.OnBackPressedCallback
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
||||||
|
abstract class WryActivity : AppCompatActivity() {
|
||||||
|
private lateinit var mWebView: RustWebView
|
||||||
|
open val handleBackNavigation: Boolean = true
|
||||||
|
|
||||||
|
open fun onWebViewCreate(webView: WebView) { }
|
||||||
|
|
||||||
|
fun setWebView(webView: RustWebView) {
|
||||||
|
mWebView = webView
|
||||||
|
|
||||||
|
if (handleBackNavigation) {
|
||||||
|
val callback = object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() {
|
||||||
|
if (this@WryActivity.mWebView.canGoBack()) {
|
||||||
|
this@WryActivity.mWebView.goBack()
|
||||||
|
} else {
|
||||||
|
this.isEnabled = false
|
||||||
|
this@WryActivity.onBackPressed()
|
||||||
|
this.isEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBackPressedDispatcher.addCallback(this, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
onWebViewCreate(webView)
|
||||||
|
}
|
||||||
|
|
||||||
|
val version: String
|
||||||
|
@SuppressLint("WebViewApiAvailability", "ObsoleteSdkInt")
|
||||||
|
get() {
|
||||||
|
// Check getCurrentWebViewPackage() directly if above Android 8
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
return WebView.getCurrentWebViewPackage()?.versionName ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise manually check WebView versions
|
||||||
|
var webViewPackage = "com.google.android.webview"
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
webViewPackage = "com.android.chrome"
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
val info = packageManager.getPackageInfo(webViewPackage, 0)
|
||||||
|
return info.versionName.toString()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Logger.warn("Unable to get package info for '$webViewPackage'$ex")
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
val info = packageManager.getPackageInfo("com.android.webview", 0)
|
||||||
|
return info.versionName.toString()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Logger.warn("Unable to get package info for 'com.android.webview'$ex")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Could not detect any webview, return empty string
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
create(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
resume()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
pause()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||||
|
super.onWindowFocusChanged(hasFocus)
|
||||||
|
focus(hasFocus)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
save()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
destroy()
|
||||||
|
onActivityDestroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLowMemory() {
|
||||||
|
super.onLowMemory()
|
||||||
|
memory()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAppClass(name: String): Class<*> {
|
||||||
|
return Class.forName(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
init {
|
||||||
|
System.loadLibrary("tauri_demo_lib")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun create(activity: WryActivity)
|
||||||
|
private external fun start()
|
||||||
|
private external fun resume()
|
||||||
|
private external fun pause()
|
||||||
|
private external fun stop()
|
||||||
|
private external fun save()
|
||||||
|
private external fun destroy()
|
||||||
|
private external fun onActivityDestroy()
|
||||||
|
private external fun memory()
|
||||||
|
private external fun focus(focus: Boolean)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# THIS FILE IS AUTO-GENERATED. DO NOT MODIFY!!
|
||||||
|
|
||||||
|
# Copyright 2020-2023 Tauri Programme within The Commons Conservancy
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
-keep class com.lenn.tauri_serial.* {
|
||||||
|
native <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keep class com.lenn.tauri_serial.WryActivity {
|
||||||
|
public <init>(...);
|
||||||
|
|
||||||
|
void setWebView(com.lenn.tauri_serial.RustWebView);
|
||||||
|
java.lang.Class getAppClass(...);
|
||||||
|
java.lang.String getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
-keep class com.lenn.tauri_serial.Ipc {
|
||||||
|
public <init>(...);
|
||||||
|
|
||||||
|
@android.webkit.JavascriptInterface public <methods>;
|
||||||
|
}
|
||||||
|
|
||||||
|
-keep class com.lenn.tauri_serial.RustWebView {
|
||||||
|
public <init>(...);
|
||||||
|
|
||||||
|
void loadUrlMainThread(...);
|
||||||
|
void loadHTMLMainThread(...);
|
||||||
|
void evalScript(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
-keep class com.lenn.tauri_serial.RustWebChromeClient,com.lenn.tauri_serial.RustWebViewClient {
|
||||||
|
public <init>(...);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/home/lenn/Workspace/JE-Skin/src-tauri/target/aarch64-linux-android/release/libtauri_demo_lib.so
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/home/lenn/Workspace/JE-Skin/src-tauri/target/armv7-linux-androideabi/release/libtauri_demo_lib.so
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/home/lenn/Workspace/JE-Skin/src-tauri/target/i686-linux-android/release/libtauri_demo_lib.so
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/home/lenn/Workspace/JE-Skin/src-tauri/target/x86_64-linux-android/release/libtauri_demo_lib.so
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
android:viewportHeight="108">
|
|
||||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:endX="85.84757"
|
|
||||||
android:endY="92.4963"
|
|
||||||
android:startX="42.9492"
|
|
||||||
android:startY="49.59793"
|
|
||||||
android:type="linear">
|
|
||||||
<item
|
|
||||||
android:color="#44000000"
|
|
||||||
android:offset="0.0" />
|
|
||||||
<item
|
|
||||||
android:color="#00000000"
|
|
||||||
android:offset="1.0" />
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FFFFFF"
|
|
||||||
android:fillType="nonZero"
|
|
||||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
|
||||||
android:strokeWidth="1"
|
|
||||||
android:strokeColor="#00000000" />
|
|
||||||
</vector>
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportWidth="108"
|
|
||||||
android:viewportHeight="108">
|
|
||||||
<path
|
|
||||||
android:fillColor="#3DDC84"
|
|
||||||
android:pathData="M0,0h108v108h-108z" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M9,0L9,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,0L19,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,0L29,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,0L39,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,0L49,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,0L59,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,0L69,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,0L79,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M89,0L89,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M99,0L99,108"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,9L108,9"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,19L108,19"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,29L108,29"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,39L108,39"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,49L108,49"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,59L108,59"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,69L108,69"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,79L108,79"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,89L108,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,99L108,99"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,29L89,29"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,39L89,39"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,49L89,49"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,59L89,59"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,69L89,69"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,79L89,79"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,19L29,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,19L39,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,19L49,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,19L59,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,19L69,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,19L79,89"
|
|
||||||
android:strokeWidth="0.8"
|
|
||||||
android:strokeColor="#33FFFFFF" />
|
|
||||||
</vector>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".MainActivity">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Hello World!"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 16 KiB |
@@ -1,6 +0,0 @@
|
|||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
<!-- Base application theme. -->
|
|
||||||
<style name="Theme.je_skin" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
|
||||||
<!-- Customize your theme here. -->
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="purple_200">#FFBB86FC</color>
|
|
||||||
<color name="purple_500">#FF6200EE</color>
|
|
||||||
<color name="purple_700">#FF3700B3</color>
|
|
||||||
<color name="teal_200">#FF03DAC5</color>
|
|
||||||
<color name="teal_700">#FF018786</color>
|
|
||||||
<color name="black">#FF000000</color>
|
|
||||||
<color name="white">#FFFFFFFF</color>
|
|
||||||
</resources>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
<resources>
|
|
||||||
<string name="app_name">JE-Skin</string>
|
|
||||||
<string name="main_activity_title">JE-Skin</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
<!-- Base application theme. -->
|
|
||||||
<style name="Theme.je_skin" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
|
||||||
<!-- Customize your theme here. -->
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<external-path name="my_images" path="." />
|
|
||||||
<cache-path name="my_cache_images" path="." />
|
|
||||||
</paths>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- CH340 / CH341 USB-Serial -->
|
|
||||||
<usb-device vendor-id="1a86" product-id="7523" />
|
|
||||||
<!-- CP2102 / CP2104 -->
|
|
||||||
<usb-device vendor-id="10c4" product-id="ea60" />
|
|
||||||
<usb-device vendor-id="10c4" product-id="ea70" />
|
|
||||||
<!-- FTDI FT232R / FT232H -->
|
|
||||||
<usb-device vendor-id="0403" product-id="6001" />
|
|
||||||
<usb-device vendor-id="0403" product-id="6014" />
|
|
||||||
<!-- PL2303 -->
|
|
||||||
<usb-device vendor-id="067b" product-id="2303" />
|
|
||||||
<usb-device vendor-id="067b" product-id="23a3" />
|
|
||||||
<!-- CDC ACM (generic USB serial) -->
|
|
||||||
<usb-device vendor-id="2341" product-id="0001" />
|
|
||||||
<usb-device vendor-id="2341" product-id="0043" />
|
|
||||||
<usb-device vendor-id="2341" product-id="0042" />
|
|
||||||
<!-- Allow any USB device (catch-all) -->
|
|
||||||
<usb-device />
|
|
||||||
</resources>
|
|
||||||
6
src-tauri/gen/android/app/tauri.build.gradle.kts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
val implementation by configurations
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":tauri-android"))
|
||||||
|
implementation(project(":tauri-plugin-opener"))
|
||||||
|
}
|
||||||
3
src-tauri/gen/android/app/tauri.properties
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
tauri.android.versionName=0.4.0
|
||||||
|
tauri.android.versionCode=4000
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath("com.android.tools.build:gradle:8.11.0")
|
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
maven(url = "https://jitpack.io")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register("clean").configure {
|
|
||||||
delete("build")
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
plugins {
|
|
||||||
`kotlin-dsl`
|
|
||||||
}
|
|
||||||
|
|
||||||
gradlePlugin {
|
|
||||||
plugins {
|
|
||||||
create("pluginsForCoolKids") {
|
|
||||||
id = "rust"
|
|
||||||
implementationClass = "RustPlugin"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compileOnly(gradleApi())
|
|
||||||
implementation("com.android.tools.build:gradle:8.11.0")
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import java.io.File
|
|
||||||
import org.apache.tools.ant.taskdefs.condition.Os
|
|
||||||
import org.gradle.api.DefaultTask
|
|
||||||
import org.gradle.api.GradleException
|
|
||||||
import org.gradle.api.logging.LogLevel
|
|
||||||
import org.gradle.api.tasks.Input
|
|
||||||
import org.gradle.api.tasks.TaskAction
|
|
||||||
|
|
||||||
open class BuildTask : DefaultTask() {
|
|
||||||
@Input
|
|
||||||
var rootDirRel: String? = null
|
|
||||||
@Input
|
|
||||||
var target: String? = null
|
|
||||||
@Input
|
|
||||||
var release: Boolean? = null
|
|
||||||
|
|
||||||
@TaskAction
|
|
||||||
fun assemble() {
|
|
||||||
val executable = """cargo""";
|
|
||||||
try {
|
|
||||||
runTauriCli(executable)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
|
||||||
// Try different Windows-specific extensions
|
|
||||||
val fallbacks = listOf(
|
|
||||||
"$executable.exe",
|
|
||||||
"$executable.cmd",
|
|
||||||
"$executable.bat",
|
|
||||||
)
|
|
||||||
|
|
||||||
var lastException: Exception = e
|
|
||||||
for (fallback in fallbacks) {
|
|
||||||
try {
|
|
||||||
runTauriCli(fallback)
|
|
||||||
return
|
|
||||||
} catch (fallbackException: Exception) {
|
|
||||||
lastException = fallbackException
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw lastException
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun runTauriCli(executable: String) {
|
|
||||||
val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null")
|
|
||||||
val target = target ?: throw GradleException("target cannot be null")
|
|
||||||
val release = release ?: throw GradleException("release cannot be null")
|
|
||||||
val args = listOf("tauri", "android", "android-studio-script");
|
|
||||||
|
|
||||||
project.exec {
|
|
||||||
workingDir(File(project.projectDir, rootDirRel))
|
|
||||||
executable(executable)
|
|
||||||
args(args)
|
|
||||||
if (project.logger.isEnabled(LogLevel.DEBUG)) {
|
|
||||||
args("-vv")
|
|
||||||
} else if (project.logger.isEnabled(LogLevel.INFO)) {
|
|
||||||
args("-v")
|
|
||||||
}
|
|
||||||
if (release) {
|
|
||||||
args("--release")
|
|
||||||
}
|
|
||||||
args(listOf("--target", target))
|
|
||||||
}.assertNormalExitValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
import com.android.build.api.dsl.ApplicationExtension
|
|
||||||
import org.gradle.api.DefaultTask
|
|
||||||
import org.gradle.api.Plugin
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.gradle.kotlin.dsl.configure
|
|
||||||
import org.gradle.kotlin.dsl.get
|
|
||||||
|
|
||||||
const val TASK_GROUP = "rust"
|
|
||||||
|
|
||||||
open class Config {
|
|
||||||
lateinit var rootDirRel: String
|
|
||||||
}
|
|
||||||
|
|
||||||
open class RustPlugin : Plugin<Project> {
|
|
||||||
private lateinit var config: Config
|
|
||||||
|
|
||||||
override fun apply(project: Project) = with(project) {
|
|
||||||
config = extensions.create("rust", Config::class.java)
|
|
||||||
|
|
||||||
val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64");
|
|
||||||
val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList
|
|
||||||
|
|
||||||
val defaultArchList = listOf("arm64", "arm", "x86", "x86_64");
|
|
||||||
val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList
|
|
||||||
|
|
||||||
val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64")
|
|
||||||
|
|
||||||
extensions.configure<ApplicationExtension> {
|
|
||||||
@Suppress("UnstableApiUsage")
|
|
||||||
flavorDimensions.add("abi")
|
|
||||||
productFlavors {
|
|
||||||
create("universal") {
|
|
||||||
dimension = "abi"
|
|
||||||
ndk {
|
|
||||||
abiFilters += abiList
|
|
||||||
}
|
|
||||||
}
|
|
||||||
defaultArchList.forEachIndexed { index, arch ->
|
|
||||||
create(arch) {
|
|
||||||
dimension = "abi"
|
|
||||||
ndk {
|
|
||||||
abiFilters.add(defaultAbiList[index])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
afterEvaluate {
|
|
||||||
for (profile in listOf("debug", "release")) {
|
|
||||||
val profileCapitalized = profile.replaceFirstChar { it.uppercase() }
|
|
||||||
val buildTask = tasks.maybeCreate(
|
|
||||||
"rustBuildUniversal$profileCapitalized",
|
|
||||||
DefaultTask::class.java
|
|
||||||
).apply {
|
|
||||||
group = TASK_GROUP
|
|
||||||
description = "Build dynamic library in $profile mode for all targets"
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask)
|
|
||||||
|
|
||||||
for (targetPair in targetsList.withIndex()) {
|
|
||||||
val targetName = targetPair.value
|
|
||||||
val targetArch = archList[targetPair.index]
|
|
||||||
val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() }
|
|
||||||
val targetBuildTask = project.tasks.maybeCreate(
|
|
||||||
"rustBuild$targetArchCapitalized$profileCapitalized",
|
|
||||||
BuildTask::class.java
|
|
||||||
).apply {
|
|
||||||
group = TASK_GROUP
|
|
||||||
description = "Build dynamic library in $profile mode for $targetArch"
|
|
||||||
rootDirRel = config.rootDirRel
|
|
||||||
target = targetName
|
|
||||||
release = profile == "release"
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTask.dependsOn(targetBuildTask)
|
|
||||||
tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn(
|
|
||||||
targetBuildTask
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# Project-wide Gradle settings.
|
|
||||||
# IDE (e.g. Android Studio) users:
|
|
||||||
# Gradle settings configured through the IDE *will override*
|
|
||||||
# any settings specified in this file.
|
|
||||||
# For more details on how to configure your build environment visit
|
|
||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
|
||||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
|
||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
|
||||||
# org.gradle.parallel=true
|
|
||||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
|
||||||
# Android operating system, and which are packaged with your app"s APK
|
|
||||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
|
||||||
android.useAndroidX=true
|
|
||||||
# Kotlin code style for this project: "official" or "obsolete":
|
|
||||||
kotlin.code.style=official
|
|
||||||
# Enables namespacing of each library's R class so that its R class includes only the
|
|
||||||
# resources declared in the library itself and none from the library's dependencies,
|
|
||||||
# thereby reducing the size of the R class for that library
|
|
||||||
android.nonTransitiveRClass=true
|
|
||||||
android.nonFinalResIds=false
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#Tue May 10 19:22:52 CST 2022
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
185
src-tauri/gen/android/gradlew
vendored
@@ -1,185 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright 2015 the original author or authors.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
##
|
|
||||||
## Gradle start up script for UN*X
|
|
||||||
##
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD="maximum"
|
|
||||||
|
|
||||||
warn () {
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die () {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
nonstop=false
|
|
||||||
case "`uname`" in
|
|
||||||
CYGWIN* )
|
|
||||||
cygwin=true
|
|
||||||
;;
|
|
||||||
Darwin* )
|
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
NONSTOP* )
|
|
||||||
nonstop=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
|
||||||
else
|
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD="java"
|
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
|
||||||
if [ $? -eq 0 ] ; then
|
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
ulimit -n $MAX_FD
|
|
||||||
if [ $? -ne 0 ] ; then
|
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=`expr $i + 1`
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
0) set -- ;;
|
|
||||||
1) set -- "$args0" ;;
|
|
||||||
2) set -- "$args0" "$args1" ;;
|
|
||||||
3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Escape application args
|
|
||||||
save () {
|
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
|
||||||
echo " "
|
|
||||||
}
|
|
||||||
APP_ARGS=`save "$@"`
|
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
|
||||||
89
src-tauri/gen/android/gradlew.bat
vendored
@@ -1,89 +0,0 @@
|
|||||||
@rem
|
|
||||||
@rem Copyright 2015 the original author or authors.
|
|
||||||
@rem
|
|
||||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
@rem you may not use this file except in compliance with the License.
|
|
||||||
@rem You may obtain a copy of the License at
|
|
||||||
@rem
|
|
||||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
@rem
|
|
||||||
@rem Unless required by applicable law or agreed to in writing, software
|
|
||||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
@rem See the License for the specific language governing permissions and
|
|
||||||
@rem limitations under the License.
|
|
||||||
@rem
|
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
|
||||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if "%ERRORLEVEL%" == "0" goto execute
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
include ':app'
|
|
||||||
|
|
||||||
apply from: 'tauri.settings.gradle'
|
|
||||||
5
src-tauri/gen/android/tauri.settings.gradle
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
include ':tauri-android'
|
||||||
|
project(':tauri-android').projectDir = new File("/home/lenn/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tauri-2.10.3/mobile/android")
|
||||||
|
include ':tauri-plugin-opener'
|
||||||
|
project(':tauri-plugin-opener').projectDir = new File("/home/lenn/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tauri-plugin-opener-2.5.3/android")
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
[default]
|
|
||||||
description = "Allows Android USB serial plugin commands."
|
|
||||||
permissions = [
|
|
||||||
"allow-usb-serial-list",
|
|
||||||
"allow-usb-serial-open",
|
|
||||||
"allow-usb-serial-close",
|
|
||||||
"allow-usb-serial-list-camel",
|
|
||||||
"allow-usb-serial-open-camel",
|
|
||||||
"allow-usb-serial-close-camel",
|
|
||||||
"allow-local-commands"
|
|
||||||
]
|
|
||||||
|
|
||||||
[[permission]]
|
|
||||||
identifier = "allow-usb-serial-list"
|
|
||||||
description = "Allows listing Android USB serial devices."
|
|
||||||
commands.allow = ["plugin:usb-serial|usb_serial_list"]
|
|
||||||
|
|
||||||
[[permission]]
|
|
||||||
identifier = "allow-usb-serial-open"
|
|
||||||
description = "Allows opening Android USB serial devices."
|
|
||||||
commands.allow = ["plugin:usb-serial|usb_serial_open"]
|
|
||||||
|
|
||||||
[[permission]]
|
|
||||||
identifier = "allow-usb-serial-close"
|
|
||||||
description = "Allows closing Android USB serial devices."
|
|
||||||
commands.allow = ["plugin:usb-serial|usb_serial_close"]
|
|
||||||
|
|
||||||
[[permission]]
|
|
||||||
identifier = "allow-usb-serial-list-camel"
|
|
||||||
description = "Allows listing Android USB serial devices via camelCase command."
|
|
||||||
commands.allow = ["plugin:usb-serial|usbSerialList"]
|
|
||||||
|
|
||||||
[[permission]]
|
|
||||||
identifier = "allow-usb-serial-open-camel"
|
|
||||||
description = "Allows opening Android USB serial devices via camelCase command."
|
|
||||||
commands.allow = ["plugin:usb-serial|usbSerialOpen"]
|
|
||||||
|
|
||||||
[[permission]]
|
|
||||||
identifier = "allow-usb-serial-close-camel"
|
|
||||||
description = "Allows closing Android USB serial devices via camelCase command."
|
|
||||||
commands.allow = ["plugin:usb-serial|usbSerialClose"]
|
|
||||||
|
|
||||||
[[permission]]
|
|
||||||
identifier = "allow-local-commands"
|
|
||||||
description = "Allows application commands used by the Android frontend."
|
|
||||||
commands.allow = [
|
|
||||||
"file_explorer_list",
|
|
||||||
"serial_enum",
|
|
||||||
"serial_connect",
|
|
||||||
"serial_connect_fd",
|
|
||||||
"serial_disconnect",
|
|
||||||
"serial_export_csv",
|
|
||||||
"serial_has_record_data",
|
|
||||||
"serial_export_csv_to_path",
|
|
||||||
"serial_import_csv",
|
|
||||||
"serial_import_csv_from_path",
|
|
||||||
"win_minimize",
|
|
||||||
"win_toggle_maximize",
|
|
||||||
"win_close",
|
|
||||||
"devkit_status",
|
|
||||||
"devkit_start",
|
|
||||||
"devkit_stop",
|
|
||||||
"devkit_get_config",
|
|
||||||
"devkit_set_config",
|
|
||||||
"devkit_process_export"
|
|
||||||
]
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": {
|
|
||||||
"usb-serial": {
|
|
||||||
"android": {
|
|
||||||
"package": "com.lenn.tauri_serial.UsbSerialPlugin"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,6 +27,14 @@ message PztAngleResponse {
|
|||||||
uint32 dts_ms = 4;
|
uint32 dts_ms = 4;
|
||||||
bool ok = 5;
|
bool ok = 5;
|
||||||
string message = 6;
|
string message = 6;
|
||||||
|
float magnitude = 7;
|
||||||
|
uint32 state = 8;
|
||||||
|
float cop_x = 9;
|
||||||
|
float cop_y = 10;
|
||||||
|
float base_x = 11;
|
||||||
|
float base_y = 12;
|
||||||
|
float total_press = 13;
|
||||||
|
float threshold = 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ProcessRequest {
|
message ProcessRequest {
|
||||||
|
|||||||