Author SHA1 Message Date
xsl 27b7075818 fix bug and add log 2026-04-23 22:18:22 +08:00
xsl fb434f09b8 添加调试日志 2026-04-23 11:29:18 +08:00
xsl 7ab4274e4f 整理卡死的问题 2026-04-21 00:03:27 +08:00
xsl 5d8e108306 fix crash bug 2026-02-05 21:06:02 +08:00
xsl 52c9da08ed save code 2026-01-13 08:12:46 +08:00
xsl 496d56f9c6 save code 2026-01-08 21:52:28 +08:00
xsl 60b40bfd5f 添加圆心遮罩 2026-01-08 21:19:32 +08:00
xsl b44162e6cb 修改背景图为透明 2025-12-26 16:23:07 +08:00
xsl 6ef6e012bd save code 2025-12-24 21:01:14 +08:00
xsl f5b2d490c0 save code 2025-12-24 10:55:30 +08:00
xsl 4c5a05ae21 asdf 2025-12-24 10:20:53 +08:00
xsl 1f9e4939b9 修改为高分辨率 2025-12-22 15:55:43 +08:00
xsl c83f36c976 修复 动画播放 错误的bug 2025-12-22 14:55:00 +08:00
xsl 29e0c1e9a8 完成动画序列播放 2025-12-22 00:40:45 +08:00
xsl 7b07e7fbc1 save code 2025-12-20 22:34:23 +08:00
xsl b6ac86a134 save code 2025-12-19 18:55:44 +08:00
xsl 6bbbb3c3ef save code 2025-12-19 13:47:16 +08:00
xsl e38da96e37 save code 2025-12-18 22:05:10 +08:00
xsl 9ee028248d save code 2025-12-17 22:58:30 +08:00
xsl 84cc693593 保存代码 2025-12-16 22:15:42 +08:00
xsl 4cf1990b16 save code 2025-12-12 10:27:49 +08:00
xsl 2130cf0e6b save 2025-12-12 09:58:03 +08:00
xsl 6717047d1d save code 2025-12-12 09:49:56 +08:00
xsl da2c97e412 修改检测参数,降低置信度,提高检测的延时 2025-12-06 11:59:00 +08:00
xsl db80a5dbbd asdf 2025-12-02 20:36:32 +08:00
xsl 634d22f3be 完成动画切换 2025-11-30 12:22:43 +08:00
xsl 835f768a4a 基本调通 回调 2025-11-29 23:44:22 +08:00
xsl 1859706412 优化内存读取 2025-11-29 11:35:56 +08:00
xsl 9c71e40c97 新版本f1118 更新图片 修复_running bug 2025-11-17 22:36:59 +08:00
xsl 84d567674f 化妆切换完成 2025-11-12 15:13:55 +08:00
xsl 43b00c8446 添加是否运行的标致 2025-11-12 15:05:31 +08:00
xsl e23ccd75cd 清理所有资源,有两处内存泄漏,暂时找不到了 2025-11-12 15:03:15 +08:00
xsl 8623b71ab7 总算是编译通过了 2025-11-12 10:53:41 +08:00
xsl 16efcbcff3 现在才真的能打包正确的 aar 2025-11-09 10:25:43 +08:00
xsl 4f62081239 生成aar文件成功 2025-11-08 20:32:31 +08:00
xsl 9f29667b73 更新编译版本为 甲方提供的版本 2025-11-08 20:10:49 +08:00
xsl 0c7455650d 更新 新版本贴图 2025-11-06 22:24:58 +08:00
xsl 00aabfc6d9 发布f20251107 版本 2025-11-06 21:28:34 +08:00
xsl 02a005f5b1 动画调整为30帧 2025-11-02 15:25:20 +08:00
xsl 6495a27658 完成动画在设备上播放和切换 2025-11-01 14:56:03 +08:00
xsl 263a061d27 处理图片的缩放 2025-10-31 15:16:27 +08:00
xsl 2555047190 动画编码完成 2025-10-31 14:22:08 +08:00
xsl dfbef7caf1 36张图片打包 2025-10-29 21:38:03 +08:00
xsl 13357ab256 android 平台跑通中文路径 2025-10-28 22:24:24 +08:00
xsl 1dfc63543f 添加中文解决的代码 2025-10-28 18:16:41 +08:00
xsl 10505c616f 修改为单纹理,在android上编译通过,apk修改为日期名字 2025-10-27 21:48:15 +08:00
xsl 300340bb19 延时优化完成 2025-10-26 22:42:05 +08:00
xsl 57b7c40835 添加了动画,资源也改为英文名了 2025-10-26 21:54:34 +08:00
xsl b2da84f903 save code 2025-10-26 00:13:08 +08:00
xsl 41a659bd6d 完成双贴图效果,修改闪退的bug,换成赴宴的贴图 2025-10-23 21:58:11 +08:00
xsl afd02550a8 添加非线性颜色过滤 2025-10-23 21:30:24 +08:00
xsl b73e94b7bf 修改了 2025-10-23 21:16:10 +08:00
xsl 2876599568 添加Example 模块,并且在设备上跑通双纹理效果 2025-10-22 22:11:01 +08:00
xsl f6dd3ab38e 添加双纹理采样 2025-10-22 18:16:03 +08:00
xsl ce2444bd07 输出aar 到新项目,运行成功 2025-10-22 00:07:53 +08:00
xsl 25fd6b4a32 终于打包成功aar 2025-10-21 18:56:09 +08:00
xsl bdcf466b73 还原为只有一个app 2025-10-21 17:53:41 +08:00
xsl 8a1d39ee94 简化MainActivity 2025-10-21 15:53:56 +08:00
xsl 438d1c246d 去掉media pipe 的依赖 2025-10-21 15:31:53 +08:00
xsl eb507c0529 修改MainActivity 文件名为 FaceActivity 2025-10-21 15:07:50 +08:00
696 changed files with 32393 additions and 987 deletions
+1
View File
@@ -12,4 +12,5 @@
/captures
.externalNativeBuild
.cxx
.idea
local.properties
+10 -8
View File
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.22.1)
project("sample")
project("face_sdk")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -23,9 +23,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android")
third_party/vma/include
)
add_library(sample SHARED
add_library(face_sdk SHARED
app/src/main/cpp/main.cpp
app/src/main/cpp/AndroidOut.cpp
app/src/main/cpp/DebugLog.h
app/src/main/cpp/DebugLog.cpp
vulkan/AppBase.h
vulkan/AppBase.cpp
vulkan/Application.h
@@ -45,13 +47,13 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Android")
find_package(Vulkan REQUIRED)
target_link_libraries(sample
target_link_libraries(face_sdk
game-activity::game-activity_static
Vulkan::Vulkan
android
log)
target_compile_definitions(sample PRIVATE
target_compile_definitions(face_sdk PRIVATE
VMA_STATIC_VULKAN_FUNCTIONS=0
VMA_DYNAMIC_VULKAN_FUNCTIONS=1
)
@@ -82,7 +84,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR WIN32)
)
# 将源代码添加到此项目的可执行文件。
add_executable (sample
add_executable (face_sdk
vulkan/AppBase.h
vulkan/AppBase.cpp
vulkan/Application.h
@@ -97,7 +99,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR WIN32)
endif()
# target_compile_definitions(sample PRIVATE VK_NO_PROTOTYPES) 使用volk 动态加载的时候需要定义,不自动生成vulkan接口
target_compile_definitions(sample PRIVATE GLM_ENABLE_EXPERIMENTAL)
# target_compile_definitions(sample PRIVATE VULKAN_HPP_NO_STRUCT_CONSTRUCTORS) 解决vs 编译c++ 20 不支持新构造函数的特性
# target_compile_definitions(face_sdk PRIVATE VK_NO_PROTOTYPES) 使用volk 动态加载的时候需要定义,不自动生成vulkan接口
target_compile_definitions(face_sdk PRIVATE GLM_ENABLE_EXPERIMENTAL)
# target_compile_definitions(face_sdk PRIVATE VULKAN_HPP_NO_STRUCT_CONSTRUCTORS) 解决vs 编译c++ 20 不支持新构造函数的特性
+191
View File
@@ -0,0 +1,191 @@
# Face SDK 崩溃调试指南
本文档说明如何配合 AI 定位 `libface_sdk.so` 里的崩溃 / 异常。核心思路:**把 Vulkan 每一次异常的上下文写进一个持久日志文件里,崩溃或画面卡住后把这份文件发给 AI 分析。**
---
## 一、已经加好的东西(不需要你做什么)
### 1. `DebugLog` 模块(`app/src/main/cpp/DebugLog.{h,cpp}`
- 线程安全;
- 每条日志带**时间戳 + 线程 ID(tid)**
- 写到 App **私有目录下的文件** —— 不会被 logcat 自动清掉;
- 每写一行 `fflush`,进程挂了也不丢最后几行;
- 文件大小超过 2MB 自动滚动到 `.old`
- 同步把日志镜像到 logcat,tag 是 `FACE_DBG`
### 2. 打点位置
| 位置 | 打点内容 | 用途 |
|---|---|---|
| `android_main` 启动 | pid、tid、日志文件绝对路径 | 每次启动一条,作为分段锚点 |
| 渲染循环心跳 | 每 600 帧一条:`frame=X exceptions_so_far=Y` | 判断启动多久后崩溃 / 异常持续性 |
| `try/catch` 兜底 | 首 10 次异常每次都打,之后每 120 次打一次 | **Vulkan 异常不会再让进程硬崩**,留住现场 |
| `handle_cmd` | 每个 `APP_CMD_*` 事件(尤其 `INIT_WINDOW`/`TERM_WINDOW`/`CONFIG_CHANGED`) | 旋转 / 切后台 / 锁屏场景的时间线 |
| `FaceApp::initVulkan` 入/出口 | 调用次数、`_applicationInited` / `_faceAppInited` / `_sceondInited` 状态 | 判断是否被多次重复调用 |
| `processImageNative` / `passDataToNative` | 每 300 次调用打一条 tid | 验证"Java 两个回调在不同线程并发调 Vulkan"假设 |
| `Application::drawFrame` 里的 4 次 Vulkan 调用 | 非 `VK_SUCCESS` 时打印数值 + 字符串名(例如 `-4 (VK_ERROR_DEVICE_LOST)` | **最关键的证据** |
### 3. 关键行为变化
**⚠️ 现在 `drawFrame` 里 Vulkan 抛出的异常会被 `try/catch` 吃掉 —— App 不会再因为这类问题硬崩溃。**
- 好处:你能继续跑、继续复现、日志一直在写;
- 代价:出问题时表现从"崩溃"变成"**画面卡住 / 黑屏 / 不再更新**"。
- 如果想暂时回到硬崩行为:把 `app/src/main/cpp/main.cpp` 里那段 `try { g_Application->drawFrame(...); } catch (...) { ... }` 改回直接 `g_Application->drawFrame(frameTime);` 即可。
---
## 二、怎么把日志文件取出来
### 方式 A`run-as`(推荐,不需要 root
```bash
adb shell "run-as com.inewme.uvmirror cat files/face_sdk_debug.log" > face_sdk_debug.log
adb shell "run-as com.inewme.uvmirror cat files/face_sdk_debug.log.old" > face_sdk_debug.log.old
```
> `.old` 只有文件滚动过一次才存在,没有可以忽略错误。
### 方式 B:直接看 logcat(实时)
```bash
adb logcat -s FACE_DBG
```
和文件内容基本一致。跑较久的话还是文件更可靠。
### 方式 C:从 App 里拿路径
启动后 `FACE_DBG` 第一条日志长这样:
```
[10:12:03.041][tid=12345] android_main start, pid=23456 tid=12345, logPath=/data/user/0/com.inewme.uvmirror/files/face_sdk_debug.log
```
照这个路径走就对了。
---
## 三、你现在要做的事(B 方案:两种场景都复现一次)
### 场景 1:旋转崩溃(已确认必现)
1. 打开 App,等初始化完成(画面能看到人脸渲染)。
2. **旋转一次屏幕**
3. 等 3~5 秒让日志写进去。
4.`face_sdk_debug.log`**不要清文件**,继续场景 2。
期望看到的关键行:
```
>> handle_cmd APP_CMD_TERM_WINDOW(...)
>> handle_cmd APP_CMD_INIT_WINDOW(...)
FaceApp::initVulkan enter, call#2 ...
drawFrame[NNN] vkAcquireNextImageKHR -> ??? (...)
!!! drawFrame std::exception (frame=NNN count=M): failed to ...
```
注意里面那个 `???` —— 这是整件事的核心证据。
### 场景 2:长时间运行崩溃(之前那个 10 分钟左右的)
**不要退出 App,接着跑**。现在即使旋转触发了异常,进程没死,我们希望看后续会不会再出另一种 VkResult:
1. 尽量不操作(不切后台、不旋转、不锁屏,让 App 持续渲染)。
2. 连续跑 **15~20 分钟**,观察是否复现之前的"无外部事件崩溃"。
3. 复现后(或稳定 20 分钟未复现也行),再取一次 `face_sdk_debug.log`(这次会覆盖场景 1 的那份,所以务必**先把场景 1 的单独保存好**)。
期望看到的关键行(如果真的是 DEVICE_LOST):
```
drawFrame[NNN] vkQueueSubmit -> -4 (VK_ERROR_DEVICE_LOST) ...
```
或者某个 Vulkan 调用返回其他错误码。
### 辅助信息(手边有就顺便记一下)
| 项 | 为什么要 |
|---|---|
| 机型 + Android 版本 | GPU 驱动差异;Adreno / Mali / Xclipse 表现差别大 |
| 复现时手机是不是很烫 | 排查 GPU 温控 / thermal throttling |
| 旋转时是"横屏 → 竖屏"还是"竖屏 → 横屏" / 多次连续旋转? | 某些机型一次 vs 多次触发行为不同 |
| 10 分钟崩溃时 App 在做什么(有在切换 motion 吗?) | 帮助排除 `changeMotionList` 相关路径 |
---
## 四、发给 AI 的时候包含什么
最小集:
1. `face_sdk_debug.log`(场景 1 旋转那份)
2. `face_sdk_debug.log`(场景 2 长跑那份)
3. 如果文件很大,**完整发**比截断发强(AI 主要关心最后几千行)
4. 一句话说明这份日志对应场景 1 还是场景 2,是否复现了
不需要的:
- logcat 完整 dump(体积太大且大多无关,除非 AI 主动问特定 tag)
- 录屏
- 源代码(AI 已经能看到仓库)
---
## 五、当前未解决的假设,等日志验证
| 假设 | 对应 VkResult | 修法 |
|---|---|---|
| 旋转导致 surface 失效未处理 | `VK_ERROR_OUT_OF_DATE_KHR` (-1000001004) 或 `VK_ERROR_SURFACE_LOST_KHR` (-1000000000) 或 `VK_SUBOPTIMAL_KHR` (1000001003) | 实现 `APP_CMD_TERM_WINDOW` 销毁流程 + swapchain 重建 |
| Java 多线程并发提交 graphicsQueue 导致 GPU 长时间后挂 | `VK_ERROR_DEVICE_LOST` (-4),且 `processImageNative` / `passDataToNative` 日志里 tid 不同 | 给所有 `vkQueueSubmit`/`vkQueuePresentKHR` 加全局 queue mutex |
| 驱动 bug / 温度导致 GPU hang | `VK_ERROR_DEVICE_LOST` (-4),单线程也出 | 捕获并尝试重建 device,或上报给机型厂商 |
| 资源累积泄漏 | `VK_ERROR_OUT_OF_DEVICE_MEMORY` (-2) 或 `VK_ERROR_TOO_MANY_OBJECTS` | 排查 `beginSingleTimeCommands`/`processWithVulkan` 路径 |
---
## 六、日志样例(便于你确认打印是否正常)
正常启动应该看到:
```
========== DebugLog opened @ 2026-04-23 14:05:12 (pid=12345) ==========
[14:05:12.019][tid=12345] android_main start, pid=12345 tid=12345, logPath=/data/user/0/com.inewme.uvmirror/files/face_sdk_debug.log
[14:05:12.155][tid=12345] >> handle_cmd APP_CMD_START(10) tid=12345
[14:05:12.155][tid=12345] << handle_cmd APP_CMD_START done
[14:05:12.210][tid=12345] >> handle_cmd APP_CMD_INIT_WINDOW(1) tid=12345
[14:05:12.210][tid=12345] handle_cmd APP_CMD_INIT_WINDOW: calling initVulkan()
[14:05:12.210][tid=12345] FaceApp::initVulkan enter, call#1 _applicationInited=0 _faceAppInited=0 _secondfaceAppInited=0
[14:05:13.420][tid=12345] FaceApp::initVulkan exit, call#1 _applicationInited=1 _faceAppInited=1 _secondfaceAppInited=1
[14:05:13.420][tid=12345] handle_cmd APP_CMD_INIT_WINDOW: initVulkan() returned, isInited=1
[14:05:13.421][tid=12345] << handle_cmd APP_CMD_INIT_WINDOW done
[14:05:14.005][tid=67890] processImageNative #1 tid=67890 w=480 h=480
[14:05:14.008][tid=67891] passDataToNative #1 tid=67891 point_count=468 w=480 h=480
[14:05:35.200][tid=12345] heartbeat: frame=600 exceptions_so_far=0
```
旋转时如果触发异常应该看到:
```
[14:06:10.112][tid=12345] >> handle_cmd APP_CMD_CONFIG_CHANGED(8) tid=12345
[14:06:10.113][tid=12345] >> handle_cmd APP_CMD_TERM_WINDOW(2) tid=12345
[14:06:10.113][tid=12345] handle_cmd APP_CMD_TERM_WINDOW: (no handler yet, ...)
[14:06:10.113][tid=12345] << handle_cmd APP_CMD_TERM_WINDOW done
[14:06:10.250][tid=12345] >> handle_cmd APP_CMD_INIT_WINDOW(1) tid=12345
[14:06:10.250][tid=12345] FaceApp::initVulkan enter, call#2 _applicationInited=1 _faceAppInited=1 _secondfaceAppInited=0
[14:06:10.250][tid=12345] FaceApp::initVulkan exit, call#2 _applicationInited=1 _faceAppInited=1 _secondfaceAppInited=1
[14:06:10.280][tid=12345] drawFrame[1234] vkAcquireNextImageKHR -> -1000001004 (VK_ERROR_OUT_OF_DATE_KHR) currentFrame=0
[14:06:10.280][tid=12345] !!! drawFrame std::exception (frame=1234 count=1): failed to acquire swap chain image!
```
**只要日志里能看到 `vkXxxKHR -> <数值> (<名字>)` 这一行,诊断就成立了。**
---
## 七、文件清单(仅供参考,日常不用动)
```
app/src/main/cpp/
DebugLog.h 新增
DebugLog.cpp 新增
main.cpp 改:日志初始化 / 心跳 / try-catch / cmd 日志 / JNI tid
vulkan/
Application.cpp 改:drawFrame 4 处 VkResult 日志 + VkResultStr
FaceApp.cpp 改:initVulkan 入/出口日志
CMakeLists.txt 改:加入 DebugLog.cpp 到 Android 构建
```
+70 -10
View File
@@ -1,19 +1,20 @@
plugins {
alias(libs.plugins.android.application)
id 'org.jetbrains.kotlin.android'
//alias(libs.plugins.android.application)
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
//id 'org.jetbrains.kotlin.android'
}
ext.vvl_version='1.4.321.0'
apply from: "./download_vvl.gradle"
android {
namespace 'com.hmwl.sample'
compileSdk 35
namespace 'com.hmwl.face_sdk'
compileSdk 36
defaultConfig {
applicationId "com.hmwl.sample"
//applicationId "com.hmwl.face_sdk"
minSdk 30
targetSdk 35
targetSdk 36
versionCode 1
versionName "1.0"
@@ -22,12 +23,25 @@ android {
}
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
debug {
debuggable true
jniDebuggable true
externalNativeBuild {
cmake {
arguments "-DCMAKE_BUILD_TYPE=Debug"
cppFlags "-DDEBUG -O0 -g"
}
}
ndk {
debugSymbolLevel 'FULL' // Debug 版本包含完整符号
}
}
release {
@@ -36,18 +50,54 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_21
targetCompatibility JavaVersion.VERSION_21
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
// 添加 Kotlin 编译选项
// kotlinOptions {
// jvmTarget = '17' // 与 Java 版本保持一致
// }
// kotlin {
// jvmToolchain(17)
// }
buildFeatures {
prefab true
}
sourceSets {
main {
jniLibs.srcDirs += [
'libs/tasks-vision/jni',
'libs/tasks-core/jni'
]
//java.srcDirs += [
// 'libs/tasks-vision/vision_classes',
// 'libs/tasks-core/core_classes'
//]
res.srcDirs += [
'libs/tasks-vision/res',
'libs/tasks-core/res'
]
}
}
externalNativeBuild {
cmake {
path file('../CMakeLists.txt')
version '3.22.1'
}
}
packagingOptions {
pickFirst '**/*.jar'
}
kotlinOptions {
jvmTarget = '17'
}
}
dependencies {
@@ -55,13 +105,23 @@ dependencies {
implementation libs.appcompat
implementation libs.material
implementation libs.games.activity
implementation libs.androidx.core.core.ktx
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
implementation 'com.google.mediapipe:tasks-vision:0.10.26'
implementation 'com.google.protobuf:protobuf-javalite:3.21.12'
implementation files('libs/tasks-vision.jar', 'libs/tasks-core.jar')
//implementation fileTree(dir: 'libs/tasks-vision', include: ['*.jar'])
//implementation fileTree(dir: 'libs/tasks-core', include: ['*.jar'])
def camerax_version = '1.4.2'
implementation "androidx.camera:camera-core:$camerax_version"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_version"
}
+2 -1
View File
@@ -1,4 +1,5 @@
apply plugin: 'com.android.application'
//apply plugin: 'com.android.application'
apply plugin: 'com.android.library'
/*
* Copyright (c) 2022-2024, The Android Open Source Project.
Binary file not shown.
Binary file not shown.
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.mediapipe.tasks.core" >
<uses-sdk
android:minSdkVersion="24"
android:targetSdkVersion="34" />
</manifest>
+255
View File
@@ -0,0 +1,255 @@
int anim fragment_fast_out_extra_slow_in 0x00000000
int animator fragment_close_enter 0x00000000
int animator fragment_close_exit 0x00000000
int animator fragment_fade_enter 0x00000000
int animator fragment_fade_exit 0x00000000
int animator fragment_open_enter 0x00000000
int animator fragment_open_exit 0x00000000
int attr alpha 0x00000000
int attr coordinatorLayoutStyle 0x00000000
int attr font 0x00000000
int attr fontProviderAuthority 0x00000000
int attr fontProviderCerts 0x00000000
int attr fontProviderFetchStrategy 0x00000000
int attr fontProviderFetchTimeout 0x00000000
int attr fontProviderPackage 0x00000000
int attr fontProviderQuery 0x00000000
int attr fontStyle 0x00000000
int attr fontVariationSettings 0x00000000
int attr fontWeight 0x00000000
int attr keylines 0x00000000
int attr layout_anchor 0x00000000
int attr layout_anchorGravity 0x00000000
int attr layout_behavior 0x00000000
int attr layout_dodgeInsetEdges 0x00000000
int attr layout_insetEdge 0x00000000
int attr layout_keyline 0x00000000
int attr statusBarBackground 0x00000000
int attr ttcIndex 0x00000000
int color notification_action_color_filter 0x00000000
int color notification_icon_bg_color 0x00000000
int color notification_material_background_media_default_color 0x00000000
int color primary_text_default_material_dark 0x00000000
int color ripple_material_light 0x00000000
int color secondary_text_default_material_dark 0x00000000
int color secondary_text_default_material_light 0x00000000
int dimen compat_button_inset_horizontal_material 0x00000000
int dimen compat_button_inset_vertical_material 0x00000000
int dimen compat_button_padding_horizontal_material 0x00000000
int dimen compat_button_padding_vertical_material 0x00000000
int dimen compat_control_corner_material 0x00000000
int dimen compat_notification_large_icon_max_height 0x00000000
int dimen compat_notification_large_icon_max_width 0x00000000
int dimen notification_action_icon_size 0x00000000
int dimen notification_action_text_size 0x00000000
int dimen notification_big_circle_margin 0x00000000
int dimen notification_content_margin_start 0x00000000
int dimen notification_large_icon_height 0x00000000
int dimen notification_large_icon_width 0x00000000
int dimen notification_main_column_padding_top 0x00000000
int dimen notification_media_narrow_margin 0x00000000
int dimen notification_right_icon_size 0x00000000
int dimen notification_right_side_padding_top 0x00000000
int dimen notification_small_icon_background_padding 0x00000000
int dimen notification_small_icon_size_as_large 0x00000000
int dimen notification_subtext_size 0x00000000
int dimen notification_top_pad 0x00000000
int dimen notification_top_pad_large_text 0x00000000
int dimen subtitle_corner_radius 0x00000000
int dimen subtitle_outline_width 0x00000000
int dimen subtitle_shadow_offset 0x00000000
int dimen subtitle_shadow_radius 0x00000000
int drawable notification_action_background 0x00000000
int drawable notification_bg 0x00000000
int drawable notification_bg_low 0x00000000
int drawable notification_bg_low_normal 0x00000000
int drawable notification_bg_low_pressed 0x00000000
int drawable notification_bg_normal 0x00000000
int drawable notification_bg_normal_pressed 0x00000000
int drawable notification_icon_background 0x00000000
int drawable notification_template_icon_bg 0x00000000
int drawable notification_template_icon_low_bg 0x00000000
int drawable notification_tile_bg 0x00000000
int drawable notify_panel_notification_icon_bg 0x00000000
int id accessibility_action_clickable_span 0x00000000
int id accessibility_custom_action_0 0x00000000
int id accessibility_custom_action_1 0x00000000
int id accessibility_custom_action_10 0x00000000
int id accessibility_custom_action_11 0x00000000
int id accessibility_custom_action_12 0x00000000
int id accessibility_custom_action_13 0x00000000
int id accessibility_custom_action_14 0x00000000
int id accessibility_custom_action_15 0x00000000
int id accessibility_custom_action_16 0x00000000
int id accessibility_custom_action_17 0x00000000
int id accessibility_custom_action_18 0x00000000
int id accessibility_custom_action_19 0x00000000
int id accessibility_custom_action_2 0x00000000
int id accessibility_custom_action_20 0x00000000
int id accessibility_custom_action_21 0x00000000
int id accessibility_custom_action_22 0x00000000
int id accessibility_custom_action_23 0x00000000
int id accessibility_custom_action_24 0x00000000
int id accessibility_custom_action_25 0x00000000
int id accessibility_custom_action_26 0x00000000
int id accessibility_custom_action_27 0x00000000
int id accessibility_custom_action_28 0x00000000
int id accessibility_custom_action_29 0x00000000
int id accessibility_custom_action_3 0x00000000
int id accessibility_custom_action_30 0x00000000
int id accessibility_custom_action_31 0x00000000
int id accessibility_custom_action_4 0x00000000
int id accessibility_custom_action_5 0x00000000
int id accessibility_custom_action_6 0x00000000
int id accessibility_custom_action_7 0x00000000
int id accessibility_custom_action_8 0x00000000
int id accessibility_custom_action_9 0x00000000
int id action0 0x00000000
int id action_container 0x00000000
int id action_divider 0x00000000
int id action_image 0x00000000
int id action_text 0x00000000
int id actions 0x00000000
int id all 0x00000000
int id async 0x00000000
int id blocking 0x00000000
int id bottom 0x00000000
int id cancel_action 0x00000000
int id center 0x00000000
int id center_horizontal 0x00000000
int id center_vertical 0x00000000
int id chronometer 0x00000000
int id clip_horizontal 0x00000000
int id clip_vertical 0x00000000
int id dialog_button 0x00000000
int id end 0x00000000
int id end_padder 0x00000000
int id fill 0x00000000
int id fill_horizontal 0x00000000
int id fill_vertical 0x00000000
int id forever 0x00000000
int id fragment_container_view_tag 0x00000000
int id icon 0x00000000
int id icon_group 0x00000000
int id info 0x00000000
int id italic 0x00000000
int id left 0x00000000
int id line1 0x00000000
int id line3 0x00000000
int id media_actions 0x00000000
int id none 0x00000000
int id normal 0x00000000
int id notification_background 0x00000000
int id notification_main_column 0x00000000
int id notification_main_column_container 0x00000000
int id right 0x00000000
int id right_icon 0x00000000
int id right_side 0x00000000
int id special_effects_controller_view_tag 0x00000000
int id start 0x00000000
int id status_bar_latest_event_content 0x00000000
int id tag_accessibility_actions 0x00000000
int id tag_accessibility_clickable_spans 0x00000000
int id tag_accessibility_heading 0x00000000
int id tag_accessibility_pane_title 0x00000000
int id tag_screen_reader_focusable 0x00000000
int id tag_transition_group 0x00000000
int id tag_unhandled_key_event_manager 0x00000000
int id tag_unhandled_key_listeners 0x00000000
int id text 0x00000000
int id text2 0x00000000
int id time 0x00000000
int id title 0x00000000
int id top 0x00000000
int id view_tree_lifecycle_owner 0x00000000
int id view_tree_saved_state_registry_owner 0x00000000
int id view_tree_view_model_store_owner 0x00000000
int id visible_removing_fragment_view_tag 0x00000000
int integer cancel_button_image_alpha 0x00000000
int integer status_bar_notification_info_maxnum 0x00000000
int layout custom_dialog 0x00000000
int layout notification_action 0x00000000
int layout notification_action_tombstone 0x00000000
int layout notification_media_action 0x00000000
int layout notification_media_cancel_action 0x00000000
int layout notification_template_big_media 0x00000000
int layout notification_template_big_media_custom 0x00000000
int layout notification_template_big_media_narrow 0x00000000
int layout notification_template_big_media_narrow_custom 0x00000000
int layout notification_template_custom_big 0x00000000
int layout notification_template_icon_group 0x00000000
int layout notification_template_lines_media 0x00000000
int layout notification_template_media 0x00000000
int layout notification_template_media_custom 0x00000000
int layout notification_template_part_chronometer 0x00000000
int layout notification_template_part_time 0x00000000
int string status_bar_notification_info_overflow 0x00000000
int style TextAppearance_Compat_Notification 0x00000000
int style TextAppearance_Compat_Notification_Info 0x00000000
int style TextAppearance_Compat_Notification_Info_Media 0x00000000
int style TextAppearance_Compat_Notification_Line2 0x00000000
int style TextAppearance_Compat_Notification_Line2_Media 0x00000000
int style TextAppearance_Compat_Notification_Media 0x00000000
int style TextAppearance_Compat_Notification_Time 0x00000000
int style TextAppearance_Compat_Notification_Time_Media 0x00000000
int style TextAppearance_Compat_Notification_Title 0x00000000
int style TextAppearance_Compat_Notification_Title_Media 0x00000000
int style Widget_Compat_NotificationActionContainer 0x00000000
int style Widget_Compat_NotificationActionText 0x00000000
int style Widget_Support_CoordinatorLayout 0x00000000
int[] styleable ColorStateListItem { 0x010101a5, 0x0101031f, 0x00000000 }
int styleable ColorStateListItem_android_color 0
int styleable ColorStateListItem_android_alpha 1
int styleable ColorStateListItem_alpha 2
int[] styleable CoordinatorLayout { 0x00000000, 0x00000000 }
int styleable CoordinatorLayout_keylines 0
int styleable CoordinatorLayout_statusBarBackground 1
int[] styleable CoordinatorLayout_Layout { 0x010100b3, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
int styleable CoordinatorLayout_Layout_android_layout_gravity 0
int styleable CoordinatorLayout_Layout_layout_anchor 1
int styleable CoordinatorLayout_Layout_layout_anchorGravity 2
int styleable CoordinatorLayout_Layout_layout_behavior 3
int styleable CoordinatorLayout_Layout_layout_dodgeInsetEdges 4
int styleable CoordinatorLayout_Layout_layout_insetEdge 5
int styleable CoordinatorLayout_Layout_layout_keyline 6
int[] styleable FontFamily { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
int styleable FontFamily_fontProviderAuthority 0
int styleable FontFamily_fontProviderCerts 1
int styleable FontFamily_fontProviderFetchStrategy 2
int styleable FontFamily_fontProviderFetchTimeout 3
int styleable FontFamily_fontProviderPackage 4
int styleable FontFamily_fontProviderQuery 5
int[] styleable FontFamilyFont { 0x01010532, 0x01010533, 0x0101053f, 0x0101056f, 0x01010570, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
int styleable FontFamilyFont_android_font 0
int styleable FontFamilyFont_android_fontWeight 1
int styleable FontFamilyFont_android_fontStyle 2
int styleable FontFamilyFont_android_ttcIndex 3
int styleable FontFamilyFont_android_fontVariationSettings 4
int styleable FontFamilyFont_font 5
int styleable FontFamilyFont_fontStyle 6
int styleable FontFamilyFont_fontVariationSettings 7
int styleable FontFamilyFont_fontWeight 8
int styleable FontFamilyFont_ttcIndex 9
int[] styleable Fragment { 0x01010003, 0x010100d0, 0x010100d1 }
int styleable Fragment_android_name 0
int styleable Fragment_android_id 1
int styleable Fragment_android_tag 2
int[] styleable FragmentContainerView { 0x01010003, 0x010100d1 }
int styleable FragmentContainerView_android_name 0
int styleable FragmentContainerView_android_tag 1
int[] styleable GradientColor { 0x0101019d, 0x0101019e, 0x010101a1, 0x010101a2, 0x010101a3, 0x010101a4, 0x01010201, 0x0101020b, 0x01010510, 0x01010511, 0x01010512, 0x01010513 }
int styleable GradientColor_android_startColor 0
int styleable GradientColor_android_endColor 1
int styleable GradientColor_android_type 2
int styleable GradientColor_android_centerX 3
int styleable GradientColor_android_centerY 4
int styleable GradientColor_android_gradientRadius 5
int styleable GradientColor_android_tileMode 6
int styleable GradientColor_android_centerColor 7
int styleable GradientColor_android_startX 8
int styleable GradientColor_android_startY 9
int styleable GradientColor_android_endX 10
int styleable GradientColor_android_endY 11
int[] styleable GradientColorItem { 0x010101a5, 0x01010514 }
int styleable GradientColorItem_android_color 0
int styleable GradientColorItem_android_offset 1
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.mediapipe.tasks.vision" >
<uses-sdk
android:minSdkVersion="24"
android:targetSdkVersion="34" />
</manifest>
+255
View File
@@ -0,0 +1,255 @@
int anim fragment_fast_out_extra_slow_in 0x00000000
int animator fragment_close_enter 0x00000000
int animator fragment_close_exit 0x00000000
int animator fragment_fade_enter 0x00000000
int animator fragment_fade_exit 0x00000000
int animator fragment_open_enter 0x00000000
int animator fragment_open_exit 0x00000000
int attr alpha 0x00000000
int attr coordinatorLayoutStyle 0x00000000
int attr font 0x00000000
int attr fontProviderAuthority 0x00000000
int attr fontProviderCerts 0x00000000
int attr fontProviderFetchStrategy 0x00000000
int attr fontProviderFetchTimeout 0x00000000
int attr fontProviderPackage 0x00000000
int attr fontProviderQuery 0x00000000
int attr fontStyle 0x00000000
int attr fontVariationSettings 0x00000000
int attr fontWeight 0x00000000
int attr keylines 0x00000000
int attr layout_anchor 0x00000000
int attr layout_anchorGravity 0x00000000
int attr layout_behavior 0x00000000
int attr layout_dodgeInsetEdges 0x00000000
int attr layout_insetEdge 0x00000000
int attr layout_keyline 0x00000000
int attr statusBarBackground 0x00000000
int attr ttcIndex 0x00000000
int color notification_action_color_filter 0x00000000
int color notification_icon_bg_color 0x00000000
int color notification_material_background_media_default_color 0x00000000
int color primary_text_default_material_dark 0x00000000
int color ripple_material_light 0x00000000
int color secondary_text_default_material_dark 0x00000000
int color secondary_text_default_material_light 0x00000000
int dimen compat_button_inset_horizontal_material 0x00000000
int dimen compat_button_inset_vertical_material 0x00000000
int dimen compat_button_padding_horizontal_material 0x00000000
int dimen compat_button_padding_vertical_material 0x00000000
int dimen compat_control_corner_material 0x00000000
int dimen compat_notification_large_icon_max_height 0x00000000
int dimen compat_notification_large_icon_max_width 0x00000000
int dimen notification_action_icon_size 0x00000000
int dimen notification_action_text_size 0x00000000
int dimen notification_big_circle_margin 0x00000000
int dimen notification_content_margin_start 0x00000000
int dimen notification_large_icon_height 0x00000000
int dimen notification_large_icon_width 0x00000000
int dimen notification_main_column_padding_top 0x00000000
int dimen notification_media_narrow_margin 0x00000000
int dimen notification_right_icon_size 0x00000000
int dimen notification_right_side_padding_top 0x00000000
int dimen notification_small_icon_background_padding 0x00000000
int dimen notification_small_icon_size_as_large 0x00000000
int dimen notification_subtext_size 0x00000000
int dimen notification_top_pad 0x00000000
int dimen notification_top_pad_large_text 0x00000000
int dimen subtitle_corner_radius 0x00000000
int dimen subtitle_outline_width 0x00000000
int dimen subtitle_shadow_offset 0x00000000
int dimen subtitle_shadow_radius 0x00000000
int drawable notification_action_background 0x00000000
int drawable notification_bg 0x00000000
int drawable notification_bg_low 0x00000000
int drawable notification_bg_low_normal 0x00000000
int drawable notification_bg_low_pressed 0x00000000
int drawable notification_bg_normal 0x00000000
int drawable notification_bg_normal_pressed 0x00000000
int drawable notification_icon_background 0x00000000
int drawable notification_template_icon_bg 0x00000000
int drawable notification_template_icon_low_bg 0x00000000
int drawable notification_tile_bg 0x00000000
int drawable notify_panel_notification_icon_bg 0x00000000
int id accessibility_action_clickable_span 0x00000000
int id accessibility_custom_action_0 0x00000000
int id accessibility_custom_action_1 0x00000000
int id accessibility_custom_action_10 0x00000000
int id accessibility_custom_action_11 0x00000000
int id accessibility_custom_action_12 0x00000000
int id accessibility_custom_action_13 0x00000000
int id accessibility_custom_action_14 0x00000000
int id accessibility_custom_action_15 0x00000000
int id accessibility_custom_action_16 0x00000000
int id accessibility_custom_action_17 0x00000000
int id accessibility_custom_action_18 0x00000000
int id accessibility_custom_action_19 0x00000000
int id accessibility_custom_action_2 0x00000000
int id accessibility_custom_action_20 0x00000000
int id accessibility_custom_action_21 0x00000000
int id accessibility_custom_action_22 0x00000000
int id accessibility_custom_action_23 0x00000000
int id accessibility_custom_action_24 0x00000000
int id accessibility_custom_action_25 0x00000000
int id accessibility_custom_action_26 0x00000000
int id accessibility_custom_action_27 0x00000000
int id accessibility_custom_action_28 0x00000000
int id accessibility_custom_action_29 0x00000000
int id accessibility_custom_action_3 0x00000000
int id accessibility_custom_action_30 0x00000000
int id accessibility_custom_action_31 0x00000000
int id accessibility_custom_action_4 0x00000000
int id accessibility_custom_action_5 0x00000000
int id accessibility_custom_action_6 0x00000000
int id accessibility_custom_action_7 0x00000000
int id accessibility_custom_action_8 0x00000000
int id accessibility_custom_action_9 0x00000000
int id action0 0x00000000
int id action_container 0x00000000
int id action_divider 0x00000000
int id action_image 0x00000000
int id action_text 0x00000000
int id actions 0x00000000
int id all 0x00000000
int id async 0x00000000
int id blocking 0x00000000
int id bottom 0x00000000
int id cancel_action 0x00000000
int id center 0x00000000
int id center_horizontal 0x00000000
int id center_vertical 0x00000000
int id chronometer 0x00000000
int id clip_horizontal 0x00000000
int id clip_vertical 0x00000000
int id dialog_button 0x00000000
int id end 0x00000000
int id end_padder 0x00000000
int id fill 0x00000000
int id fill_horizontal 0x00000000
int id fill_vertical 0x00000000
int id forever 0x00000000
int id fragment_container_view_tag 0x00000000
int id icon 0x00000000
int id icon_group 0x00000000
int id info 0x00000000
int id italic 0x00000000
int id left 0x00000000
int id line1 0x00000000
int id line3 0x00000000
int id media_actions 0x00000000
int id none 0x00000000
int id normal 0x00000000
int id notification_background 0x00000000
int id notification_main_column 0x00000000
int id notification_main_column_container 0x00000000
int id right 0x00000000
int id right_icon 0x00000000
int id right_side 0x00000000
int id special_effects_controller_view_tag 0x00000000
int id start 0x00000000
int id status_bar_latest_event_content 0x00000000
int id tag_accessibility_actions 0x00000000
int id tag_accessibility_clickable_spans 0x00000000
int id tag_accessibility_heading 0x00000000
int id tag_accessibility_pane_title 0x00000000
int id tag_screen_reader_focusable 0x00000000
int id tag_transition_group 0x00000000
int id tag_unhandled_key_event_manager 0x00000000
int id tag_unhandled_key_listeners 0x00000000
int id text 0x00000000
int id text2 0x00000000
int id time 0x00000000
int id title 0x00000000
int id top 0x00000000
int id view_tree_lifecycle_owner 0x00000000
int id view_tree_saved_state_registry_owner 0x00000000
int id view_tree_view_model_store_owner 0x00000000
int id visible_removing_fragment_view_tag 0x00000000
int integer cancel_button_image_alpha 0x00000000
int integer status_bar_notification_info_maxnum 0x00000000
int layout custom_dialog 0x00000000
int layout notification_action 0x00000000
int layout notification_action_tombstone 0x00000000
int layout notification_media_action 0x00000000
int layout notification_media_cancel_action 0x00000000
int layout notification_template_big_media 0x00000000
int layout notification_template_big_media_custom 0x00000000
int layout notification_template_big_media_narrow 0x00000000
int layout notification_template_big_media_narrow_custom 0x00000000
int layout notification_template_custom_big 0x00000000
int layout notification_template_icon_group 0x00000000
int layout notification_template_lines_media 0x00000000
int layout notification_template_media 0x00000000
int layout notification_template_media_custom 0x00000000
int layout notification_template_part_chronometer 0x00000000
int layout notification_template_part_time 0x00000000
int string status_bar_notification_info_overflow 0x00000000
int style TextAppearance_Compat_Notification 0x00000000
int style TextAppearance_Compat_Notification_Info 0x00000000
int style TextAppearance_Compat_Notification_Info_Media 0x00000000
int style TextAppearance_Compat_Notification_Line2 0x00000000
int style TextAppearance_Compat_Notification_Line2_Media 0x00000000
int style TextAppearance_Compat_Notification_Media 0x00000000
int style TextAppearance_Compat_Notification_Time 0x00000000
int style TextAppearance_Compat_Notification_Time_Media 0x00000000
int style TextAppearance_Compat_Notification_Title 0x00000000
int style TextAppearance_Compat_Notification_Title_Media 0x00000000
int style Widget_Compat_NotificationActionContainer 0x00000000
int style Widget_Compat_NotificationActionText 0x00000000
int style Widget_Support_CoordinatorLayout 0x00000000
int[] styleable ColorStateListItem { 0x010101a5, 0x0101031f, 0x00000000 }
int styleable ColorStateListItem_android_color 0
int styleable ColorStateListItem_android_alpha 1
int styleable ColorStateListItem_alpha 2
int[] styleable CoordinatorLayout { 0x00000000, 0x00000000 }
int styleable CoordinatorLayout_keylines 0
int styleable CoordinatorLayout_statusBarBackground 1
int[] styleable CoordinatorLayout_Layout { 0x010100b3, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
int styleable CoordinatorLayout_Layout_android_layout_gravity 0
int styleable CoordinatorLayout_Layout_layout_anchor 1
int styleable CoordinatorLayout_Layout_layout_anchorGravity 2
int styleable CoordinatorLayout_Layout_layout_behavior 3
int styleable CoordinatorLayout_Layout_layout_dodgeInsetEdges 4
int styleable CoordinatorLayout_Layout_layout_insetEdge 5
int styleable CoordinatorLayout_Layout_layout_keyline 6
int[] styleable FontFamily { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
int styleable FontFamily_fontProviderAuthority 0
int styleable FontFamily_fontProviderCerts 1
int styleable FontFamily_fontProviderFetchStrategy 2
int styleable FontFamily_fontProviderFetchTimeout 3
int styleable FontFamily_fontProviderPackage 4
int styleable FontFamily_fontProviderQuery 5
int[] styleable FontFamilyFont { 0x01010532, 0x01010533, 0x0101053f, 0x0101056f, 0x01010570, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }
int styleable FontFamilyFont_android_font 0
int styleable FontFamilyFont_android_fontWeight 1
int styleable FontFamilyFont_android_fontStyle 2
int styleable FontFamilyFont_android_ttcIndex 3
int styleable FontFamilyFont_android_fontVariationSettings 4
int styleable FontFamilyFont_font 5
int styleable FontFamilyFont_fontStyle 6
int styleable FontFamilyFont_fontVariationSettings 7
int styleable FontFamilyFont_fontWeight 8
int styleable FontFamilyFont_ttcIndex 9
int[] styleable Fragment { 0x01010003, 0x010100d0, 0x010100d1 }
int styleable Fragment_android_name 0
int styleable Fragment_android_id 1
int styleable Fragment_android_tag 2
int[] styleable FragmentContainerView { 0x01010003, 0x010100d1 }
int styleable FragmentContainerView_android_name 0
int styleable FragmentContainerView_android_tag 1
int[] styleable GradientColor { 0x0101019d, 0x0101019e, 0x010101a1, 0x010101a2, 0x010101a3, 0x010101a4, 0x01010201, 0x0101020b, 0x01010510, 0x01010511, 0x01010512, 0x01010513 }
int styleable GradientColor_android_startColor 0
int styleable GradientColor_android_endColor 1
int styleable GradientColor_android_type 2
int styleable GradientColor_android_centerX 3
int styleable GradientColor_android_centerY 4
int styleable GradientColor_android_gradientRadius 5
int styleable GradientColor_android_tileMode 6
int styleable GradientColor_android_centerColor 7
int styleable GradientColor_android_startX 8
int styleable GradientColor_android_startY 9
int styleable GradientColor_android_endX 10
int styleable GradientColor_android_endY 11
int[] styleable GradientColorItem { 0x010101a5, 0x01010514 }
int styleable GradientColorItem_android_color 0
int styleable GradientColorItem_android_offset 1
Binary file not shown.
@@ -1,26 +0,0 @@
package com.hmwl.sample;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.hmwl.sample", appContext.getPackageName());
}
}
+14 -19
View File
@@ -2,33 +2,28 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- Declare features -->
<uses-feature android:name="android.hardware.camera" />
<!-- 声明摄像头硬件特性 -->
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<!-- Declare permissions -->
<!-- 声明摄像头权限 -->
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Sample">
<application>
<!-- 声明 MainActivity -->
<!-- 作为库,exported 通常设为 false,除非明确需要外部应用启动 -->
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
android:name=".FaceActivity"
android:exported="true"
tools:ignore="MissingClass"> <!-- 如果IDE报类找不到,可以添加这个 -->
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- 重要:移除 MAIN/LAUNCHER intent-filter -->
<!-- 让使用库的应用来决定哪个是主Activity -->
<meta-data
android:name="android.app.lib_name"
android:value="sample" />
android:value="face_sdk" />
</activity>
</application>
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

+28 -2
View File
@@ -9,7 +9,33 @@ layout(location = 0) out vec4 outColor;
// 纹理采样器
layout(binding = 0) uniform sampler2D texSampler;
layout(push_constant) uniform PushConstants {
float zoom;
float r;
float g;
float b;
float radius;
float ux;
float uy;
} pushConstants;
void main() {
// 采样纹理
outColor = texture(texSampler, inTexCoord);
// outFragColor = color;
// 获取当前片元的屏幕坐标(左下角为原点)
vec2 fragCoord = gl_FragCoord.xy;
// 屏幕中心(480x480 的中心是 (240, 240)
vec2 center = vec2(240.0, 240.0);
// 计算到中心的距离(欧氏距离,单位:像素)
float dist = length(fragCoord - center);
// 判断是否在半径之外
if (dist > pushConstants.radius) {
// 使用 push constant 中的 RGB 颜色(注意 alpha 设为 1.0
outColor = vec4(pushConstants.r, pushConstants.g, pushConstants.b, 1.0);
} else {
// 采样纹理
outColor = texture(texSampler, inTexCoord);
}
}
Binary file not shown.
+12 -2
View File
@@ -38,7 +38,15 @@ const vec2 texCoords[6] = vec2[6](
// 定义 Push Constant,只有一个 float
layout(push_constant) uniform PushConstants {
float myValue;
float zoom;
float r;
float g;
float b;
float radius;
float ux;
float uy;
float offset_x;
float offset_y;
} pushConstants;
@@ -48,7 +56,9 @@ layout(location = 0) out vec2 outTexCoord;
void main() {
// 获取顶点位置
vec2 position = positions[gl_VertexIndex];
position = position * pushConstants.myValue;
position = position * pushConstants.zoom;
position.x = position.x + (pushConstants.offset_x/480);
position.y = position.y + (pushConstants.offset_y/480);
// 设置输出位置(Vulkan使用不同的坐标系)
gl_Position = vec4(position, 0.0, 1.0);
Binary file not shown.
Binary file not shown.
Binary file not shown.
+28 -10
View File
@@ -1,26 +1,44 @@
#version 450
#version 450
layout (binding = 1) uniform sampler2D samplerColor;
layout (location = 0) in vec2 inUV;
layout (location = 1) in vec3 inNormal;
layout(push_constant) uniform PushConstants {
float zoom;
float r;
float g;
float b;
float radius;
float ux;
float uy;
} pushConstants;
layout (location = 0) out vec4 outFragColor;
void main()
{
vec4 color = texture(samplerColor, inUV);
// outFragColor = color;
// 获取当前片元的屏幕坐标(左下角为原点)
vec2 fragCoord = gl_FragCoord.xy;
vec3 N = normalize(inNormal);
// 屏幕中心(480x480 的中心是 (240, 240)
vec2 center = vec2(240.0, 240.0);
vec4 textureColor = color;
if (textureColor.a < 0.1) {
//textureColor = vec4(0.2, 0.2, 0.2, 0.5);
discard;
// 计算到中心的距离(欧氏距离,单位:像素)
float dist = length(fragCoord - center);
// 判断是否在半径之外
if (dist > pushConstants.radius) {
// 使用 push constant 中的 RGB 颜色(注意 alpha 设为 1.0
outFragColor = vec4(pushConstants.r, pushConstants.g, pushConstants.b, 1.0);
} else {
vec2 pos = vec2(pushConstants.ux/4096.f, pushConstants.uy/2048.f);
vec2 uv = pos + vec2(inUV.x/8.f, inUV.y/4.f);
vec4 color = texture(samplerColor, uv);
outFragColor = color;
}
outFragColor = textureColor;
// outFragColor = vec4(1, 0, 0, 1);
}
Binary file not shown.
+12 -2
View File
@@ -17,7 +17,15 @@ layout (location = 0) out vec2 outUV;
layout (location = 1) out vec3 outNormal;
layout(push_constant) uniform PushConstants {
float myValue;
float zoom;
float r;
float g;
float b;
float radius;
float ux;
float uy;
float offset_x;
float offset_y;
} pushConstants;
out gl_PerVertex
@@ -30,7 +38,9 @@ void main()
outUV = inUV;
vec2 position = vec2(inPos.xy*2 -1);
position = position * pushConstants.myValue;
position = position * pushConstants.zoom;
position.x = position.x + (pushConstants.offset_x/480);
position.y = position.y + (pushConstants.offset_y/480);
gl_Position = vec4(position, 0.5, 1.0);
vec4 pos = ubo.model * vec4(inPos, 1.0);
Binary file not shown.
@@ -0,0 +1,56 @@
#version 450
layout (binding = 1) uniform sampler2D samplerColor;
layout (binding = 2) uniform sampler2D samplerColor_ex;
layout (location = 0) in vec2 inUV;
layout (location = 1) in vec3 inNormal;
layout (location = 0) out vec4 outFragColor;
void main()
{
vec4 color = texture(samplerColor, inUV);
vec4 color_ex = texture(samplerColor_ex, inUV);
vec3 N = normalize(inNormal);
// 计算与 (0,0,1) 的点乘
float ndot = dot(N, vec3(0.0, 0.0, -1.0));
// 保证结果 >= 0
ndot = max(ndot, 0.0);
// 重新映射ndot值,让中间2/3部分进行融合
// 当ndot在[0.166, 0.833]范围内时进行混合,两端保持不变
float blendFactor;
if (ndot < 0.0) {
blendFactor = 0.0; // 完全使用color_ex
} else if (ndot > 0.1) {
blendFactor = 1.0; // 完全使用color
} else {
// 在中间2/3部分进行平滑过渡
blendFactor = (ndot - 0.0) / (1 - 0);
}
// 使用smoothstep创建中间2/3的融合区域
// 参数说明:smoothstep(edge0, edge1, x)
// 当x < edge0时返回0,当x > edge1时返回1,在中间时平滑过渡
//float blendFactor = smoothstep(0.166, 0.833, ndot);
// vec4 blendedColor = mix(color_ex, color, ndot);
// outFragColor = blendedColor;
if (ndot < 0.3){
outFragColor = color_ex;
}
else
{
outFragColor = color;
}
// outFragColor = vec4(1, 0, 0, 1);
}
Binary file not shown.
+165
View File
@@ -0,0 +1,165 @@
#include "DebugLog.h"
#include <android/log.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <cstdarg>
#include <cstdio>
#include <ctime>
#include <cstring>
#include <mutex>
#include <string>
#include <unordered_map>
namespace {
std::mutex g_mtx;
FILE* g_fp = nullptr;
std::string g_path;
constexpr size_t kMaxSize = 2 * 1024 * 1024; // 2 MB before rotation
// Throttle bookkeeping: one slot per distinct key passed to log_throttled().
struct ThrottleSlot {
int64_t last_emit_ms = 0; // when we last actually wrote a line for this key
uint32_t suppressed = 0; // number of calls swallowed since last_emit_ms
};
std::unordered_map<std::string, ThrottleSlot> g_throttle;
constexpr int64_t kThrottleWindowMs = 2000; // 2 seconds
pid_t currentTid() {
return static_cast<pid_t>(syscall(SYS_gettid));
}
int64_t nowMs() {
timespec ts{};
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<int64_t>(ts.tv_sec) * 1000 + ts.tv_nsec / 1000000;
}
// Assumes g_mtx is held. Writes a single pre-formatted line to disk + logcat.
void writeLineLocked(const char* body) {
pid_t tid = currentTid();
timespec ts{};
clock_gettime(CLOCK_REALTIME, &ts);
struct tm tm_info{};
localtime_r(&ts.tv_sec, &tm_info);
char timebuf[32];
strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tm_info);
if (g_fp) {
std::fprintf(g_fp, "[%s.%03ld][tid=%d] %s\n",
timebuf, ts.tv_nsec / 1000000, tid, body);
std::fflush(g_fp);
}
__android_log_print(ANDROID_LOG_INFO, "FACE_DBG", "[tid=%d] %s", tid, body);
}
} // namespace
namespace DebugLog {
void init(const char* internalDataPath) {
std::lock_guard<std::mutex> lk(g_mtx);
if (g_fp) {
return; // already initialized
}
const char* base = (internalDataPath && *internalDataPath) ? internalDataPath : "/data/local/tmp";
g_path = std::string(base) + "/face_sdk_debug.log";
// Rotate once if current file is too large.
struct stat st{};
if (stat(g_path.c_str(), &st) == 0 && static_cast<size_t>(st.st_size) > kMaxSize) {
std::string backup = g_path + ".old";
std::remove(backup.c_str());
std::rename(g_path.c_str(), backup.c_str());
}
g_fp = std::fopen(g_path.c_str(), "a");
if (g_fp) {
time_t now = time(nullptr);
struct tm tm_info{};
localtime_r(&now, &tm_info);
char tbuf[64];
strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", &tm_info);
std::fprintf(g_fp,
"\n========== DebugLog opened @ %s (pid=%d) ==========\n",
tbuf, getpid());
std::fflush(g_fp);
}
__android_log_print(ANDROID_LOG_INFO, "FACE_DBG",
"DebugLog file path: %s", g_path.c_str());
}
void log(const char* fmt, ...) {
char buf[1024];
va_list ap;
va_start(ap, fmt);
int n = std::vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (n < 0) return;
std::lock_guard<std::mutex> lk(g_mtx);
writeLineLocked(buf);
}
void log_throttled(const char* key, const char* fmt, ...) {
char buf[1024];
va_list ap;
va_start(ap, fmt);
int n = std::vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (n < 0) return;
const char* k = key ? key : "";
int64_t now = nowMs();
std::lock_guard<std::mutex> lk(g_mtx);
auto it = g_throttle.find(k);
if (it == g_throttle.end()) {
// First time we see this key -> always log.
ThrottleSlot slot;
slot.last_emit_ms = now;
slot.suppressed = 0;
g_throttle.emplace(k, slot);
writeLineLocked(buf);
return;
}
ThrottleSlot& slot = it->second;
int64_t elapsed = now - slot.last_emit_ms;
if (elapsed < kThrottleWindowMs) {
// Still inside the 2s window -> swallow.
++slot.suppressed;
return;
}
// Window elapsed: emit the line, annotated with how many we swallowed.
if (slot.suppressed > 0) {
char annotated[1200];
std::snprintf(annotated, sizeof(annotated),
"%s (repeated %u times in last %lldms, key=%s)",
buf, slot.suppressed, (long long)elapsed, k);
writeLineLocked(annotated);
} else {
writeLineLocked(buf);
}
slot.last_emit_ms = now;
slot.suppressed = 0;
}
void flush() {
std::lock_guard<std::mutex> lk(g_mtx);
if (g_fp) std::fflush(g_fp);
}
std::string getLogPath() {
std::lock_guard<std::mutex> lk(g_mtx);
return g_path;
}
} // namespace DebugLog
+33
View File
@@ -0,0 +1,33 @@
#ifndef FACE_SDK_DEBUGLOG_H
#define FACE_SDK_DEBUGLOG_H
#include <string>
namespace DebugLog {
// Call once (e.g. in android_main) with android_app->activity->internalDataPath.
// Safe to call multiple times; subsequent calls are no-ops.
void init(const char* internalDataPath);
// Thread-safe. Also mirrored to logcat with tag "FACE_DBG".
// Every line is prefixed with timestamp + thread id and flushed to disk immediately,
// so even a hard crash will preserve the tail.
void log(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
// Throttled variant keyed by a caller-supplied string.
// - The first call with a given key is always written.
// - Subsequent calls with the same key within 2 seconds are suppressed.
// - When the throttle window elapses, the next matching call is written with a
// "(repeated N times in last Xms)" suffix describing the suppressed ones.
// Use stable, short keys (e.g. "drawFrame.acquire", "drawFrame.present").
void log_throttled(const char* key, const char* fmt, ...) __attribute__((format(printf, 2, 3)));
// Force flush to disk.
void flush();
// Absolute path of the log file (valid after init()).
std::string getLogPath();
} // namespace DebugLog
#endif // FACE_SDK_DEBUGLOG_H
+369 -21
View File
@@ -3,44 +3,97 @@
#include <game-activity/native_app_glue/android_native_app_glue.h>
#include <game-activity/GameActivity.h>
#include "AndroidOut.h"
#include "DebugLog.h"
#include "FaceApp.h"
#include <android/asset_manager.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <atomic>
#include <chrono>
#include <thread>
using namespace std;
static inline pid_t dbg_tid() {
return static_cast<pid_t>(syscall(SYS_gettid));
}
static const char* appCmdName(int32_t cmd) {
switch (cmd) {
case APP_CMD_INIT_WINDOW: return "APP_CMD_INIT_WINDOW";
case APP_CMD_TERM_WINDOW: return "APP_CMD_TERM_WINDOW";
case APP_CMD_WINDOW_RESIZED: return "APP_CMD_WINDOW_RESIZED";
case APP_CMD_WINDOW_REDRAW_NEEDED: return "APP_CMD_WINDOW_REDRAW_NEEDED";
case APP_CMD_CONTENT_RECT_CHANGED: return "APP_CMD_CONTENT_RECT_CHANGED";
case APP_CMD_GAINED_FOCUS: return "APP_CMD_GAINED_FOCUS";
case APP_CMD_LOST_FOCUS: return "APP_CMD_LOST_FOCUS";
case APP_CMD_CONFIG_CHANGED: return "APP_CMD_CONFIG_CHANGED";
case APP_CMD_LOW_MEMORY: return "APP_CMD_LOW_MEMORY";
case APP_CMD_START: return "APP_CMD_START";
case APP_CMD_RESUME: return "APP_CMD_RESUME";
case APP_CMD_SAVE_STATE: return "APP_CMD_SAVE_STATE";
case APP_CMD_PAUSE: return "APP_CMD_PAUSE";
case APP_CMD_STOP: return "APP_CMD_STOP";
case APP_CMD_DESTROY: return "APP_CMD_DESTROY";
default: return "APP_CMD_???";
}
}
extern "C" {
android_app* g_android_app = nullptr;
Application* g_Application = nullptr;
FaceApp* g_Application = nullptr;
AAssetManager* g_assetManager = nullptr;
jobject g_callback = nullptr;
jobject g_callbackAnimationFinished = nullptr;
void handle_cmd(android_app *pApp, int32_t cmd) {
DebugLog::log(">> handle_cmd %s(%d) tid=%d", appCmdName(cmd), (int)cmd, dbg_tid());
switch (cmd) {
case APP_CMD_INIT_WINDOW:
aout << "APP_CMD_INIT_WINDOW" << std::endl;
g_Application->initVulkan();
DebugLog::log("handle_cmd APP_CMD_INIT_WINDOW: calling onWindowInit()");
g_Application->onWindowInit();
DebugLog::log("handle_cmd APP_CMD_INIT_WINDOW: onWindowInit() returned, isInited=%d",
(int)g_Application->isInited());
break;
case APP_CMD_TERM_WINDOW:
aout << "APP_CMD_TERM_WINDOW" << std::endl;
DebugLog::log("handle_cmd APP_CMD_TERM_WINDOW: calling onWindowLost()");
if (g_Application != nullptr) {
g_Application->onWindowLost();
}
DebugLog::log("handle_cmd APP_CMD_TERM_WINDOW: onWindowLost() returned");
break;
default:
break;
}
DebugLog::log("<< handle_cmd %s done", appCmdName(cmd));
}
const int ArgLen = 128*1024;
char g_InitArgString[ArgLen] = {0};
void android_main(struct android_app *pApp) {
DebugLog::init(pApp->activity->internalDataPath);
DebugLog::log("android_main start, pid=%d tid=%d, logPath=%s",
getpid(), dbg_tid(), DebugLog::getLogPath().c_str());
aout << "Welcome to android_main" << std::endl;
g_android_app = pApp;
g_assetManager = pApp->activity->assetManager;
FaceApp application;
g_Application = &application;
//FaceApp application;
//g_Application = &application;
if(g_Application == nullptr) {
g_Application = new FaceApp();
}
g_Application->SetInitArg(g_InitArgString);
pApp->onAppCmd = handle_cmd;
long long last_update_time = 0;
android_app_set_motion_event_filter(pApp, nullptr);
long long _lastDrawFrameTime = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
do {
auto ms = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
auto start_time = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
// Process all pending events before running game logic.
bool done = false;
while (!done) {
@@ -66,14 +119,57 @@ void android_main(struct android_app *pApp) {
}
}
}
if(application.isInited())
// isInited() checks _applicationInited && _faceAppInited && _sceondInited,
// so while the window is gone (between TERM_WINDOW and the next
// INIT_WINDOW) this is false and we skip drawFrame entirely — no
// exceptions, no log spam. The outer sleep at the bottom already
// caps the loop frequency.
if(g_Application->isInited())
{
application.drawFrame();
auto frameTime = (start_time - _lastDrawFrameTime);
_lastDrawFrameTime = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
static uint64_t s_frameIdx = 0;
static uint64_t s_excCount = 0;
++s_frameIdx;
if (s_frameIdx % 600 == 0) {
DebugLog::log("heartbeat: frame=%llu exceptions_so_far=%llu",
(unsigned long long)s_frameIdx,
(unsigned long long)s_excCount);
}
try {
g_Application->drawFrame(frameTime);
} catch (const std::exception& e) {
++s_excCount;
DebugLog::log_throttled("main.drawFrame.stdexc",
"!!! drawFrame std::exception (frame=%llu count=%llu): %s",
(unsigned long long)s_frameIdx,
(unsigned long long)s_excCount,
e.what());
} catch (...) {
++s_excCount;
DebugLog::log_throttled("main.drawFrame.unknown",
"!!! drawFrame unknown exception (frame=%llu count=%llu)",
(unsigned long long)s_frameIdx,
(unsigned long long)s_excCount);
}
}
auto end_time = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
auto frameTime = end_time - last_update_time;
last_update_time = end_time;
auto function_time = (end_time - start_time);
//aout << "function_time:" << function_time << " fps:" << (1000/frameTime) << std::endl;
if(function_time < 35)
{
this_thread::sleep_for(chrono::milliseconds((35-function_time)));
}
auto end_ms = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
this_thread::sleep_for(chrono::milliseconds((end_ms-ms)));
} while (!pApp->destroyRequested);
application.cleanup();
DebugLog::log("android_main: destroyRequested, running cleanup");
//application.cleanup();
g_Application->cleanupSecondInit();
g_Application->clearnSecondFaceApp();
DebugLog::log("android_main: exit");
}
}
@@ -85,13 +181,21 @@ void processWithVulkan(uint8_t* data, int width, int height, int format,
TextureLoadProcessWithVulkan(data, width, height, rowStride, dataSize);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_hmwl_sample_MainActivity_processImageNative(JNIEnv *env, jobject thiz, jobject buffer,
jint width, jint height, jint format,
jint row_stride, jint pixel_stride,
jint rotation) {
Java_com_hmwl_face_1sdk_FaceActivity_processImageNative(JNIEnv *env, jobject thiz, jobject buffer,
jint width, jint height, jint format,
jint row_stride, jint pixel_stride,
jint rotation) {
static std::atomic<uint64_t> s_imgCount{0};
uint64_t n = s_imgCount.fetch_add(1) + 1;
if (n == 1 || n % 300 == 0) {
DebugLog::log("processImageNative #%llu tid=%d w=%d h=%d",
(unsigned long long)n, dbg_tid(), width, height);
}
// TODO: implement processImageNative()
uint8_t* imageData = static_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
jlong capacity = env->GetDirectBufferCapacity(buffer);
@@ -103,12 +207,17 @@ Java_com_hmwl_sample_MainActivity_processImageNative(JNIEnv *env, jobject thiz,
// 创建 Vulkan 图像或更新现有图像
processWithVulkan(imageData, width, height, format, row_stride, capacity);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_hmwl_sample_MainActivity_passDataToNative(JNIEnv *env, jobject thiz, jobject buffer,
jint point_count, jint width, jint height) {
Java_com_hmwl_face_1sdk_FaceActivity_passDataToNative(JNIEnv *env, jobject thiz, jobject buffer,
jint point_count, jint width, jint height) {
static std::atomic<uint64_t> s_ptCount{0};
uint64_t n = s_ptCount.fetch_add(1) + 1;
if (n == 1 || n % 300 == 0) {
DebugLog::log("passDataToNative #%llu tid=%d point_count=%d w=%d h=%d",
(unsigned long long)n, dbg_tid(), point_count, width, height);
}
// TODO: implement passDataToNative()
float* pos = static_cast<float*>(env->GetDirectBufferAddress(buffer));
if (pos == nullptr) {
@@ -118,4 +227,243 @@ Java_com_hmwl_sample_MainActivity_passDataToNative(JNIEnv *env, jobject thiz, jo
// 或者直接将指针传递给Vulkan
ReceiveFacePoint(pos, point_count, width, height);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_SetCppInitArg(JNIEnv *env, jobject thiz, jstring json) {
const char *nativeString = env->GetStringUTFChars(json, nullptr);
jsize len = env->GetStringUTFLength(json);
DebugLog::log("JNI SetCppInitArg tid=%d len=%d", dbg_tid(), (int)len);
if(len > ArgLen)
{
aout << "ArgLen to long:" << len << std::endl;
return;
}
memcpy(g_InitArgString, nativeString, len);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_StopRunning(JNIEnv *env, jobject thiz) {
DebugLog::log("JNI StopRunning tid=%d", dbg_tid());
g_Application->Stop();
}
JavaVM* g_jvm = nullptr;
// 添加 JNI_OnLoad 函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
g_jvm = vm; // 保存 JavaVM 指针,供其他线程使用
return JNI_VERSION_1_6;
}
void CppCallback()
{
JNIEnv* env = nullptr;
bool needDetach = false;
// 获取当前线程的 JNIEnv
JavaVM* vm = g_jvm; // 你需要提前保存 JavaVM* 到全局变量 g_jvm
int status = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (status == JNI_EDETACHED) {
// 当前线程未 attach,需 attach
if (vm->AttachCurrentThread(&env, nullptr) != 0) {
return;
}
needDetach = true;
} else if (status != JNI_OK) {
return;
}
if (g_callback == nullptr) {
if (needDetach) vm->DetachCurrentThread();
return;
}
// 1. 获取 CallbackInterface 的 class
jclass callbackClass = env->GetObjectClass(g_callback);
if (callbackClass == nullptr) {
if (needDetach) vm->DetachCurrentThread();
return;
}
// 2. 获取 OnLoadActionFinished 方法 ID(注意方法名大小写必须一致!)
jmethodID methodId = env->GetMethodID(callbackClass, "OnLoadMotionListFinished", "(Ljava/lang/String;)V");
if (methodId == nullptr) {
env->ExceptionDescribe(); // 打印异常
env->ExceptionClear();
if (needDetach) vm->DetachCurrentThread();
return;
}
// 3. 构造 jstring 参数
jstring jResult = env->NewStringUTF("ok");
// 4. 调用 Java 回调
env->CallVoidMethod(g_callback, methodId, jResult);
// 5. 检查是否抛出异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
// 6. 释放局部引用(可选,但推荐)
env->DeleteLocalRef(jResult);
env->DeleteLocalRef(callbackClass);
// 7. 如果是临时 attach 的线程,要 detach
if (needDetach) {
vm->DetachCurrentThread();
}
}
void CppAnimationFinishedCallback()
{
JNIEnv* env = nullptr;
bool needDetach = false;
// 获取当前线程的 JNIEnv
JavaVM* vm = g_jvm; // 你需要提前保存 JavaVM* 到全局变量 g_jvm
int status = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (status == JNI_EDETACHED) {
// 当前线程未 attach,需 attach
if (vm->AttachCurrentThread(&env, nullptr) != 0) {
return;
}
needDetach = true;
} else if (status != JNI_OK) {
return;
}
if (g_callbackAnimationFinished == nullptr) {
if (needDetach) vm->DetachCurrentThread();
return;
}
// 1. 获取 CallbackInterface 的 class
jclass callbackClass = env->GetObjectClass(g_callbackAnimationFinished);
if (callbackClass == nullptr) {
if (needDetach) vm->DetachCurrentThread();
return;
}
// 2. 获取 OnLoadActionFinished 方法 ID(注意方法名大小写必须一致!)
jmethodID methodId = env->GetMethodID(callbackClass, "OnPlayMotionListFinished", "()V");
if (methodId == nullptr) {
env->ExceptionDescribe(); // 打印异常
env->ExceptionClear();
if (needDetach) vm->DetachCurrentThread();
return;
}
// 4. 调用 Java 回调
env->CallVoidMethod(g_callbackAnimationFinished, methodId);
// 5. 检查是否抛出异常
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
}
env->DeleteLocalRef(callbackClass);
// 7. 如果是临时 attach 的线程,要 detach
if (needDetach) {
vm->DetachCurrentThread();
}
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_PreReadAction(JNIEnv *env, jobject thiz, jstring motion,
jobject callback) {
DebugLog::log("JNI PreReadAction tid=%d", dbg_tid());
// 清理旧的全局引用
if (g_callback != nullptr) {
env->DeleteGlobalRef(g_callback);
g_callback = nullptr;
}
// 保存新的回调
if (callback != nullptr) {
g_callback = env->NewGlobalRef(callback);
} else {
g_callback = nullptr;
}
const char *nativeString = env->GetStringUTFChars(motion, nullptr);
jsize len = env->GetStringUTFLength(motion);
if(len > ArgLen)
{
aout << "ArgLen to long:" << len << std::endl;
}
std::string ret = g_Application->preLoadMotionList(nativeString, CppCallback);
return env->NewStringUTF(ret.c_str());
}
const char DELIMITER = 0x1F; // same as \u001F
std::vector<std::string> splitMotionString(const std::string& input) {
std::vector<std::string> result;
if (input.empty()) return result;
size_t start = 0;
size_t pos = input.find(DELIMITER);
while (pos != std::string::npos) {
result.push_back(input.substr(start, pos - start));
start = pos + 1;
pos = input.find(DELIMITER, start);
}
// Add last part
result.push_back(input.substr(start));
return result;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_ChangeMotionCpp(JNIEnv *env, jobject thiz, jstring json,
jobject callback, jboolean loop) {
const char *nativeString = env->GetStringUTFChars(json, nullptr);
jsize len = env->GetStringUTFLength(json);
DebugLog::log_throttled("JNI.ChangeMotionCpp",
"JNI ChangeMotionCpp tid=%d len=%d loop=%d",
dbg_tid(), (int)len, (int)loop);
if(len > ArgLen)
{
aout << "ArgLen to long:" << len << std::endl;
return;
}
// 保存新的回调
if (callback != nullptr) {
g_callbackAnimationFinished = env->NewGlobalRef(callback);
} else {
g_callbackAnimationFinished = nullptr;
}
if(g_Application->isInited())
{
std::vector<std::string> motions = splitMotionString(nativeString);
g_Application->changeMotionList(motions, CppAnimationFinishedCallback, loop);
}
}
extern "C"
JNIEXPORT void JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_StopMotionNative(JNIEnv *env, jobject thiz) {
DebugLog::log("JNI StopMotionNative tid=%d", dbg_tid());
g_Application->StopMotion();
}
extern "C"
JNIEXPORT void JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_ResumeMotionNative(JNIEnv *env, jobject thiz) {
DebugLog::log("JNI ResumeMotionNative tid=%d", dbg_tid());
g_Application->ResumeMotion();
}
@@ -1,10 +1,9 @@
package com.hmwl.sample;
package com.hmwl.face_sdk;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.NonNull;
@@ -31,13 +30,12 @@ import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class MainActivity extends GameActivity implements FaceLandmarkerHelper.LandmarkerListener {
private static final String TAG = "MainActivity";
public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.LandmarkerListener {
private static final String TAG = "FaceActivity";
static {
System.loadLibrary("sample");
System.loadLibrary("face_sdk");
}
private ProcessCameraProvider cameraProvider;
@@ -50,6 +48,21 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
// 检查权限是否被授予
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户授予了权限启动相机
startCamera();
} else {
requestCameraPermission();
}
}
}
private void startCamera() {
ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
ProcessCameraProvider.getInstance(this);
@@ -70,47 +83,23 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
imageAnalyzer.setAnalyzer(backgroundExecutor, new ImageAnalysis.Analyzer() {
private long lastCaptureTime = 0;
private int frameCount = 0;
@Override
public void analyze(@NonNull ImageProxy image) {
frameCount++;
long currentTime = System.currentTimeMillis();
try {
long captureTimeNs = image.getImageInfo().getTimestamp();
long analyzeTime = System.currentTimeMillis();
// 简单直接的计算方法
long captureTimeMs = TimeUnit.NANOSECONDS.toMillis(captureTimeNs);
long latency = analyzeTime - captureTimeMs;
// 帧率计算
if (lastCaptureTime > 0) {
long frameInterval = captureTimeMs - lastCaptureTime;
double fps = 1000.0 / frameInterval;
if (frameCount % 10 == 0) { // 每30帧打印一次
Log.i("TimeLatency", String.format(
"Frame %d - Latency: %d ms, FPS: %.1f",
frameCount, latency, fps
));
}
}
lastCaptureTime = captureTimeMs;
processImageForVulkan(image);
if(frameCount %2 == 0)
if(frameCount %3 == 0)
{
detectFace(image);
}
else
{
image.close();
}
// else
// {
// image.close();
// }
} finally {
//image.close(); // 确保在这里关闭
image.close(); // 确保在这里关闭
//Log.d("Camera", "Image closed, ready for next frame");
}
}
@@ -146,6 +135,22 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
}
}
public void Stop(){
StopRunning();
}
private native void StopMotionNative();
public void StopMotion(){
StopMotionNative();
}
private native void ResumeMotionNative();
public void ResumeMotion(){
ResumeMotionNative();
}
private native void StopRunning();
// Native 方法
private native void processImageNative(ByteBuffer buffer, int width, int height,
int format, int rowStride, int pixelStride,
@@ -186,41 +191,15 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
0.5f,
0.5f,
1,
0,
RunningMode.LIVE_STREAM,
MainActivity.this,
MainActivity.this
FaceActivity.this,
FaceActivity.this
);
}
});
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
float x = event.getX();
float y = event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "Java Layer: Touch DOWN at (" + x + ", " + y + ")");
// 你可以在这里做些事比如发消息给 C++ UI 反馈
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "Java Layer: Touch MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "Java Layer: Touch UP");
break;
}
// 关键返回 false 才能让事件继续传递给 Native C++
// 如果返回 true表示事件已被消费C++ 层将收不到
return false;
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
@@ -308,4 +287,48 @@ public class MainActivity extends GameActivity implements FaceLandmarkerHelper.L
}
public native void passDataToNative(ByteBuffer buffer, int pointCount, int width, int height);
protected native void SetCppInitArg(String json);
public void SetInitArg(String json)
{
SetCppInitArg(json);
}
public interface LoadMotionListFinishedCallback {
void OnLoadMotionListFinished(String result);
}
public interface PlayMotionListFinishedCallback {
void OnPlayMotionListFinished();
}
protected native String PreReadAction(String motion, LoadMotionListFinishedCallback callback);
public String PreLoadAction(String json, LoadMotionListFinishedCallback callback){
return PreReadAction(json, callback);
}
protected native void ChangeMotionCpp(String json, PlayMotionListFinishedCallback callback, boolean loop);
public void PlayMotionList(List<String> motionList, boolean loop, PlayMotionListFinishedCallback callback)
{
if(callback == null)
{
callback = new PlayMotionListFinishedCallback() {
@Override
public void OnPlayMotionListFinished() {
Log.i(TAG, "OnPlayMotionListFinished: ");
}
};
}
final String DELIMITER = "\u001F"; // ASCII Unit Separator
String motion_list_str = String.join(DELIMITER, motionList);
ChangeMotionCpp(motion_list_str, callback, loop);
}
// 添加这个缺失的方法
@Override
public void onEmpty() {
// 当没有检测到人脸时的处理逻辑
//Log.d(TAG, "No face detected in the current frame");
}
}
@@ -1,12 +1,8 @@
package com.hmwl.sample;
package com.hmwl.face_sdk
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.media.MediaMetadataRetriever
import android.net.Uri
import android.os.SystemClock
import android.util.Log
import androidx.annotation.VisibleForTesting
@@ -24,8 +20,7 @@ class FaceLandmarkerHelper(
var minFaceTrackingConfidence: Float = DEFAULT_FACE_TRACKING_CONFIDENCE,
var minFacePresenceConfidence: Float = DEFAULT_FACE_PRESENCE_CONFIDENCE,
var maxNumFaces: Int = DEFAULT_NUM_FACES,
var currentDelegate: Int = DELEGATE_CPU,
var runningMode: RunningMode = RunningMode.IMAGE,
var runningMode: RunningMode = RunningMode.LIVE_STREAM,
val context: Context,
// this listener is only used when running in RunningMode.LIVE_STREAM
val faceLandmarkerHelperListener: LandmarkerListener? = null
@@ -54,14 +49,7 @@ class FaceLandmarkerHelper(
val baseOptionBuilder = BaseOptions.builder()
// Use the specified hardware for running the model. Default to CPU
when (currentDelegate) {
DELEGATE_CPU -> {
baseOptionBuilder.setDelegate(Delegate.CPU)
}
DELEGATE_GPU -> {
baseOptionBuilder.setDelegate(Delegate.GPU)
}
}
baseOptionBuilder.setDelegate(Delegate.GPU)
baseOptionBuilder.setModelAssetPath(MP_FACE_LANDMARKER_TASK)
@@ -79,6 +67,9 @@ class FaceLandmarkerHelper(
}
}
minFaceDetectionConfidence = 0.1f;
minFaceTrackingConfidence = 0.1f;
minFacePresenceConfidence = 0.1f;
try {
val baseOptions = baseOptionBuilder.build()
// Create an option builder with base options and specific
@@ -201,7 +192,7 @@ class FaceLandmarkerHelper(
Bitmap.Config.ARGB_8888
)
imageProxy.use { bitmapBuffer.copyPixelsFromBuffer(imageProxy.planes[0].buffer) }
imageProxy.close()
//imageProxy.close()
val matrix = Matrix().apply {
// Rotate the frame received from the camera to be in the same direction as it'll be shown
@@ -250,32 +241,33 @@ class FaceLandmarkerHelper(
val frameId = result.timestampMs()
if( result.faceLandmarks().size > 0 ) {
// 计算各种延时
val timings = frameTimings[frameId]
if (timings != null) {
val totalLatency = resultTime - timings.captureTime
val preprocessLatency = timings.preprocessEndTime - timings.preprocessStartTime
val detectionLatency = resultTime - timings.detectionStartTime
val captureToDetectionLatency = timings.detectionStartTime - timings.captureTime
Log.i("TimeLatency",
"总延时: ${totalLatency}ms | " +
"预处理: ${preprocessLatency}ms | " +
"检测: ${detectionLatency}ms | " +
"捕获到检测: ${captureToDetectionLatency}ms | " +
"FPS: ${String.format("%.1f", currentFps)}"
)
val finishTimeMs = SystemClock.uptimeMillis()
val inferenceTime = finishTimeMs - result.timestampMs()
faceLandmarkerHelperListener?.onResults(
ResultBundle(
result,
inferenceTime, // 主要是检测时间
input.height,
input.width,
)
)
} else {
// val timings = frameTimings[frameId]
// if (timings != null) {
// val totalLatency = resultTime - timings.captureTime
// val preprocessLatency = timings.preprocessEndTime - timings.preprocessStartTime
// val detectionLatency = resultTime - timings.detectionStartTime
// val captureToDetectionLatency = timings.detectionStartTime - timings.captureTime
//
// Log.i("TimeLatency",
// "总延时: ${totalLatency}ms | " +
// "预处理: ${preprocessLatency}ms | " +
// "检测: ${detectionLatency}ms | " +
// "捕获到检测: ${captureToDetectionLatency}ms | " +
// "FPS: ${String.format("%.1f", currentFps)}"
// )
//
// val finishTimeMs = SystemClock.uptimeMillis()
// val inferenceTime = finishTimeMs - result.timestampMs()
// faceLandmarkerHelperListener?.onResults(
// ResultBundle(
// result,
// inferenceTime, // 主要是检测时间
// input.height,
// input.width,
// )
// )
// } else
//{
val finishTimeMs = SystemClock.uptimeMillis()
val inferenceTime = finishTimeMs - result.timestampMs()
Log.i("TimeLatency",
@@ -289,7 +281,7 @@ class FaceLandmarkerHelper(
input.width
)
)
}
//}
}
else {
faceLandmarkerHelperListener?.onEmpty()
@@ -0,0 +1,27 @@
package com.hmwl.face_sdk;
import org.json.JSONObject;
public class Frame {
public String name;
public float x;
public float y;
public Frame(String name, float x, float y)
{
this.name = name;
this.x = x;
this.y = y;
}
public JSONObject toJsonObject(){
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", name);
jsonObject.put("x", x);
jsonObject.put("y", y);
return jsonObject;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
@@ -0,0 +1,30 @@
package com.hmwl.face_sdk;
import org.json.JSONObject;
public class InitArg {
public int action_fps;
public float zoom;
public float r;
public float g;
public float b;
public float radius;
public float offset_x;
public float offset_y;
public String toJson() {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("action_fps", action_fps);
jsonObject.put("zoom", zoom);
jsonObject.put("r", r);
jsonObject.put("g", g);
jsonObject.put("b", b);
jsonObject.put("radius", radius);
jsonObject.put("offset_x", offset_x);
jsonObject.put("offset_y", offset_y);
return jsonObject.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
@@ -0,0 +1,33 @@
package com.hmwl.face_sdk;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class Motion {
public String name = "no";
public List<Frame> frames = new ArrayList<>();
public Motion(String name, List<Frame> frames)
{
this.name = name;
this.frames = frames;
}
public JSONObject toJsonObject() {
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", name);
JSONArray jframes = new JSONArray();
for(int i = 0; i < frames.size(); ++i){
jframes.put(frames.get(i).toJsonObject());
}
jsonObject.put("frames", jframes);
return jsonObject;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
};
@@ -0,0 +1,28 @@
package com.hmwl.face_sdk;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class MotionList {
public List<Motion> motions = new ArrayList<>();
public JSONObject toJsonObject() {
try {
JSONObject jsonObject = new JSONObject();
JSONArray jMotions = new JSONArray();
for(int i = 0; i < motions.size(); ++i){
jMotions.put(motions.get(i).toJsonObject());
}
jsonObject.put("motions", jMotions);
return jsonObject;
} catch (Exception e) {
e.printStackTrace();
return new JSONObject();
}
}
public String toJsonString(){
return toJsonObject().toString();
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

@@ -1,17 +0,0 @@
package com.hmwl.sample;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
+16 -2
View File
@@ -1,5 +1,19 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.3.2'
}
}
plugins {
alias(libs.plugins.android.application) apply false
id 'org.jetbrains.kotlin.android' version '2.2.0' apply false
alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlin.android) apply false // 添加这行
//alias(libs.plugins.kotlin.android) apply false
//id 'org.jetbrains.kotlin.android' version '2.2.0' apply false
}
+12
View File
@@ -0,0 +1,12 @@
glslangValidator -V app/src/main/assets/shaders/bg.frag -o app/src/main/assets/shaders/bg.frag.spv
glslangValidator -V app/src/main/assets/shaders/bg.vert -o app/src/main/assets/shaders/bg.vert.spv
glslangValidator -V app/src/main/assets/shaders/texture.frag -o app/src/main/assets/shaders/texture.frag.spv
glslangValidator -V app/src/main/assets/shaders/texture.vert -o app/src/main/assets/shaders/texture.vert.spv
glslangValidator -V app/src/main/assets/shaders/simple_shader.frag -o app/src/main/assets/shaders/simple_shader.frag.spv
glslangValidator -V app/src/main/assets/shaders/simple_shader.vert -o app/src/main/assets/shaders/simple_shader.vert.spv
glslangValidator -V app/src/main/assets/shaders/texture_thick.frag -o app/src/main/assets/shaders/texture_thick.frag.spv
rem glslangValidator -V app/src/main/assets/shaders/texture_thick.vert -o app/src/main/assets/shaders/texture_thick.vert.spv
+1
View File
@@ -0,0 +1 @@
/build
+86
View File
@@ -0,0 +1,86 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
//alias(libs.plugins.kotlin.android)
}
android {
namespace 'com.inewme.uvmirror'
compileSdk 36
defaultConfig {
applicationId "com.inewme.uvmirror.f20260113"
minSdk 30
targetSdk 36
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
signingConfig signingConfigs.debug
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.5.1'
}
kotlinOptions {
jvmTarget = '17'
}
// kotlinOptions {
// jvmTarget = '17'
// }
}
dependencies {
implementation libs.appcompat
implementation libs.material
implementation libs.games.activity
implementation libs.core.ktx
implementation libs.androidx.core.ktx
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
implementation project(':app')
// Jetpack Compose
implementation "androidx.compose.ui:ui:1.5.0"
implementation "androidx.compose.material3:material3:1.0.0"
implementation "androidx.compose.foundation:foundation:1.5.0"
implementation "androidx.compose.runtime:runtime:1.5.0"
implementation "androidx.activity:activity-compose:1.7.2" // ؼṩ setContent
implementation "androidx.compose.ui:ui-tooling:1.5.4"
def camerax_version = '1.4.2'
implementation "androidx.camera:camera-core:$camerax_version"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_version"
implementation 'com.google.protobuf:protobuf-javalite:3.21.12'
implementation 'com.google.android.datatransport:transport-runtime:3.1.9'
implementation 'com.google.android.datatransport:transport-backend-cct:3.1.9'
implementation 'com.google.flogger:flogger:0.7.4'
implementation 'com.google.flogger:flogger-system-backend:0.7.4'
implementation 'com.google.guava:guava:31.1-android'
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7") // 提供 lifecycleScope
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
}
+21
View File
@@ -0,0 +1,21 @@
# 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
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Sample" >
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="face_sdk" />
</activity>
<activity
android:name=".MakeupActivity"
android:exported="false" />
</application>
</manifest>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Some files were not shown because too many files have changed in this diff Show More